@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.
- package/README.md +49 -83
- package/dist/.tsbuildinfo +1 -1
- package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-collect-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/animation-graph-serialize.unit.test.d.ts +2 -0
- package/dist/__tests__/animation-graph-serialize.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts +2 -0
- package/dist/__tests__/asset-brand-and-name-retirement.test.d.ts.map +1 -0
- package/dist/__tests__/asset-error-exhaustive.test-d.d.ts +11 -0
- package/dist/__tests__/asset-error-exhaustive.test-d.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-guid-reverse.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-guid-reverse.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-hdr-equirect.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mesh-pack-payload.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-mounts.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-mounts.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.browser.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.browser.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.dawn.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.listCatalog.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.listCatalog.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.mesh-bin.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.mesh-bin.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.pack-cache.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.raw-container-failfast.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.recursive.spec.d.ts +2 -0
- package/dist/__tests__/asset-registry.recursive.spec.d.ts.map +1 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset.unit.test.d.ts +2 -0
- package/dist/__tests__/asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/audio-load-by-guid.unit.test.d.ts +2 -0
- package/dist/__tests__/audio-load-by-guid.unit.test.d.ts.map +1 -0
- package/dist/__tests__/backend-selection.integration.test.d.ts +2 -0
- package/dist/__tests__/backend-selection.integration.test.d.ts.map +1 -0
- package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts +2 -0
- package/dist/__tests__/basis-catalog-dispatch.integration.test.d.ts.map +1 -0
- package/dist/__tests__/builtin-asset-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/builtin-asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/collect-scene-asset.test.d.ts +1 -2
- package/dist/__tests__/collect-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/collect-scene-mount-collapse.test.d.ts +2 -0
- package/dist/__tests__/collect-scene-mount-collapse.test.d.ts.map +1 -0
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts +1 -1
- package/dist/__tests__/collect-transient-roundtrip.test.d.ts.map +1 -1
- package/dist/__tests__/collect-transient-skip.test.d.ts +1 -2
- package/dist/__tests__/collect-transient-skip.test.d.ts.map +1 -1
- package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts +2 -0
- package/dist/__tests__/compressed-texture-physical-extent.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/mesh-update-dawn.test.d.ts.map +1 -0
- package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts +2 -0
- package/dist/__tests__/dawn/upload-texture.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/draw-published.d.ts +2 -2
- package/dist/__tests__/draw-published.d.ts.map +1 -1
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts +2 -0
- package/dist/__tests__/dynamic-texture-store.unit.test.d.ts.map +1 -0
- package/dist/__tests__/errors.unit.test.d.ts +2 -0
- package/dist/__tests__/errors.unit.test.d.ts.map +1 -0
- package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts +2 -0
- package/dist/__tests__/extract-skin-mismatch.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fetch-binary-decompress.test.d.ts +2 -0
- package/dist/__tests__/fetch-binary-decompress.test.d.ts.map +1 -0
- package/dist/__tests__/four-path-compression.integration.test.d.ts +2 -0
- package/dist/__tests__/four-path-compression.integration.test.d.ts.map +1 -0
- package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts +2 -0
- package/dist/__tests__/fullscreen-feature-host.dawn.test.d.ts.map +1 -0
- package/dist/__tests__/guid-for-asset.unit.test.d.ts +2 -0
- package/dist/__tests__/guid-for-asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/handle-migration.test.d.ts +2 -0
- package/dist/__tests__/handle-migration.test.d.ts.map +1 -0
- package/dist/__tests__/helpers/register-runtime-components.d.ts.map +1 -1
- package/dist/__tests__/host-custom-kind-contract.test-d.d.ts +2 -0
- package/dist/__tests__/host-custom-kind-contract.test-d.d.ts.map +1 -0
- package/dist/__tests__/host-custom-kind-contract.test.d.ts +2 -0
- package/dist/__tests__/host-custom-kind-contract.test.d.ts.map +1 -0
- package/dist/__tests__/inspect-name.test.d.ts +2 -0
- package/dist/__tests__/inspect-name.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts +2 -0
- package/dist/__tests__/instantiate-mount-deferred-wiring.test.d.ts.map +1 -0
- package/dist/__tests__/loadbyguid-payload.unit.test.d.ts +2 -0
- package/dist/__tests__/loadbyguid-payload.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts +2 -0
- package/dist/__tests__/loadbyguid-texture-intern.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-extract-graceful.test.d.ts +2 -0
- package/dist/__tests__/loader-extract-graceful.test.d.ts.map +1 -0
- package/dist/__tests__/loader-name-survival.test.d.ts +2 -0
- package/dist/__tests__/loader-name-survival.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-contract.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-contract.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-skin-roundtrip.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-loader-skin-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/new-kind-refs-contract.test.d.ts +2 -0
- package/dist/__tests__/new-kind-refs-contract.test.d.ts.map +1 -0
- package/dist/__tests__/package-promotion.test.d.ts +2 -0
- package/dist/__tests__/package-promotion.test.d.ts.map +1 -0
- package/dist/__tests__/package-rename.test.d.ts +2 -0
- package/dist/__tests__/package-rename.test.d.ts.map +1 -0
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts +1 -1
- package/dist/__tests__/recover-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts +1 -1
- package/dist/__tests__/render-error-exhaustive.test-d.d.ts.map +1 -1
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts +10 -0
- package/dist/__tests__/render-feature-prepared-graphics.fixture.d.ts.map +1 -0
- package/dist/__tests__/render-system-extract.unit.test.d.ts +2 -0
- package/dist/__tests__/render-system-extract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/renderer-test-utils.d.ts +10 -0
- package/dist/__tests__/renderer-test-utils.d.ts.map +1 -0
- package/dist/__tests__/renderer.test-d.d.ts +2 -0
- package/dist/__tests__/renderer.test-d.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle-err.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle-err.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts +2 -0
- package/dist/__tests__/resolve-asset-handle.unit.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-fallback.test.d.ts +2 -0
- package/dist/__tests__/resolveName-fallback.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-null-package.test.d.ts +2 -0
- package/dist/__tests__/resolveName-null-package.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName-unified-entry.test.d.ts +2 -0
- package/dist/__tests__/resolveName-unified-entry.test.d.ts.map +1 -0
- package/dist/__tests__/resolveName.test.d.ts +2 -0
- package/dist/__tests__/resolveName.test.d.ts.map +1 -0
- package/dist/__tests__/roots-to-scene-asset.test.d.ts +1 -1
- package/dist/__tests__/roots-to-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/roundtrip-primitive.test.d.ts +2 -0
- package/dist/__tests__/roundtrip-primitive.test.d.ts.map +1 -0
- package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts +2 -0
- package/dist/__tests__/scene-bare-guid-refs-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/scene-instance-authoring.integration.test.d.ts +2 -0
- package/dist/__tests__/scene-instance-authoring.integration.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-fixed-point.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-fixed-point.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/scene-mount-wrapper-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/scene-sugar-instantiate.test.d.ts +2 -0
- package/dist/__tests__/scene-sugar-instantiate.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts +2 -0
- package/dist/__tests__/serialize-mounts-roundtrip.test.d.ts.map +1 -0
- package/dist/__tests__/serialize-scene-asset.test.d.ts +1 -1
- package/dist/__tests__/serialize-scene-asset.test.d.ts.map +1 -1
- package/dist/__tests__/template-game-default-api-contract.test.d.ts +2 -0
- package/dist/__tests__/template-game-default-api-contract.test.d.ts.map +1 -0
- package/dist/__tests__/tileset-asset-validate.test.d.ts +2 -0
- package/dist/__tests__/tileset-asset-validate.test.d.ts.map +1 -0
- package/dist/__tests__/transcode-fallback.unit.test.d.ts +2 -0
- package/dist/__tests__/transcode-fallback.unit.test.d.ts.map +1 -0
- package/dist/__tests__/transient-runtime-behavior.test.d.ts +2 -0
- package/dist/__tests__/transient-runtime-behavior.test.d.ts.map +1 -0
- package/dist/__tests__/video-loader-consumption.test.d.ts +2 -0
- package/dist/__tests__/video-loader-consumption.test.d.ts.map +1 -0
- package/dist/__tests__/video-loader-smoke.dawn.test.d.ts +2 -0
- package/dist/__tests__/video-loader-smoke.dawn.test.d.ts.map +1 -0
- package/dist/backend-selection.d.ts +13 -0
- package/dist/backend-selection.d.ts.map +1 -0
- package/dist/collect-scene-asset.d.ts +3 -3
- package/dist/collect-scene-asset.d.ts.map +1 -1
- package/dist/createRenderer.d.ts +14 -2
- package/dist/createRenderer.d.ts.map +1 -1
- package/dist/errors/environment.d.ts +1 -1
- package/dist/errors/environment.d.ts.map +1 -1
- package/dist/index.d.ts +19 -81
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +105 -108
- package/dist/index.mjs.map +1 -1
- package/dist/renderer-host.d.ts +9 -0
- package/dist/renderer-host.d.ts.map +1 -0
- package/dist/renderer-host.mjs +62 -0
- package/dist/renderer-host.mjs.map +1 -0
- package/dist/scene-instances/index.d.ts +2 -0
- package/dist/scene-instances/index.d.ts.map +1 -0
- package/dist/scene-utils/mount-override-fold.d.ts +1 -2
- package/dist/scene-utils/mount-override-fold.d.ts.map +1 -1
- package/dist/systems/sprite-animation-tick.d.ts +1 -1
- package/dist/systems/sprite-animation-tick.d.ts.map +1 -1
- package/dist/systems/transparent-sort.d.ts +1 -2
- package/dist/systems/transparent-sort.d.ts.map +1 -1
- package/dist/tilemap-register-validate.d.ts.map +1 -1
- package/package.json +34 -33
- package/src/__tests__/active-camera.unit.test.ts +19 -9
- package/src/__tests__/animation-graph-collect-roundtrip.test.ts +213 -0
- package/src/__tests__/animation-graph-serialize.unit.test.ts +171 -0
- package/src/__tests__/append-injection.test.ts +1 -1
- package/src/__tests__/asset-brand-and-name-retirement.test.ts +102 -0
- package/src/__tests__/asset-error-exhaustive.test-d.ts +62 -0
- package/src/__tests__/asset-registry-guid-reverse.test.ts +575 -0
- package/src/__tests__/asset-registry-hdr-equirect.test.ts +78 -0
- package/src/__tests__/asset-registry-mesh-pack-payload.dawn.test.ts +232 -0
- package/src/__tests__/asset-registry-mounts.test.ts +806 -0
- package/src/__tests__/asset-registry.browser.test.ts +81 -0
- package/src/__tests__/asset-registry.dawn.test.ts +94 -0
- package/src/__tests__/asset-registry.listCatalog.test.ts +170 -0
- package/src/__tests__/asset-registry.mesh-bin.test.ts +316 -0
- package/src/__tests__/asset-registry.pack-cache.test.ts +969 -0
- package/src/__tests__/asset-registry.raw-container-failfast.test.ts +225 -0
- package/src/__tests__/asset-registry.recursive.spec.ts +1397 -0
- package/src/__tests__/asset-registry.unit.test.ts +1030 -0
- package/src/__tests__/asset.unit.test.ts +7107 -0
- package/src/__tests__/audio-load-by-guid.unit.test.ts +126 -0
- package/src/__tests__/backend-selection.integration.test.ts +11 -0
- package/src/__tests__/basis-catalog-dispatch.integration.test.ts +320 -0
- package/src/__tests__/bind-group-cache-keying.test.ts +4 -4
- package/src/__tests__/block-upload-math.unit.test.ts +2 -2
- package/src/__tests__/builtin-asset-registry.unit.test.ts +112 -0
- package/src/__tests__/builtin-shader-register-e2e.test.ts +1 -1
- package/src/__tests__/cache-false-eviction.test.ts +2 -1
- package/src/__tests__/cache-isolation-matrix.test.ts +2 -1
- package/src/__tests__/camera-clear-snapshot-equivalence.unit.test.ts +5 -6
- package/src/__tests__/clamp-to-last.e2e.browser.test.ts +29 -19
- package/src/__tests__/collect-scene-asset.test.ts +49 -52
- package/src/__tests__/collect-scene-mount-collapse.test.ts +391 -0
- package/src/__tests__/collect-subtree.unit.test.ts +1 -2
- package/src/__tests__/collect-transient-children-absent.test.ts +24 -10
- package/src/__tests__/collect-transient-roundtrip.test.ts +44 -20
- package/src/__tests__/collect-transient-skip.test.ts +24 -13
- package/src/__tests__/components.test-d.ts +1 -6
- package/src/__tests__/components.unit.test.ts +20 -19
- package/src/__tests__/composite-skybox-cross-world.browser.test.ts +59 -27
- package/src/__tests__/compressed-texture-physical-extent.integration.test.ts +139 -0
- package/src/__tests__/create-renderer-assembly.integration.test.ts +42 -29
- package/src/__tests__/createRenderer-dispose.test.ts +35 -402
- package/src/__tests__/createRenderer.browser-no-webgpu.test.ts +25 -30
- package/src/__tests__/createRenderer.unit.test.ts +1 -1
- package/src/__tests__/dawn/hello-sprite-nineslice-section.dawn.test.ts +27 -63
- package/src/__tests__/dawn/ibl-precompute-readback.dawn.test.ts +56 -47
- package/src/__tests__/dawn/instances-per-instance-pbr.dawn.test.ts +49 -29
- package/src/__tests__/dawn/instances-shadow.dawn.test.ts +26 -15
- package/src/__tests__/dawn/instances-uniform-fallback.dawn.test.ts +13 -14
- package/src/__tests__/dawn/material-alpha.dawn.test.ts +23 -31
- package/src/__tests__/dawn/material-cooked-fixture.dawn.test.ts +0 -18
- package/src/__tests__/dawn/{mesh-update.dawn.test.ts → mesh-update-dawn.test.ts} +42 -134
- package/src/__tests__/dawn/mipmap-srgb-linear.dawn.test.ts +14 -7
- package/src/__tests__/dawn/per-entity-material-texture-isolation.dawn.test.ts +16 -28
- package/src/__tests__/dawn/sprite-nineslice-mesh-bind.dawn.test.ts +23 -39
- package/src/__tests__/dawn/upload-texture.dawn.test.ts +198 -0
- package/src/__tests__/dawn/user-handle-mesh-render.dawn.test.ts +12 -14
- package/src/__tests__/dawn/user-mesh-upload.dawn.test.ts +27 -22
- package/src/__tests__/dawn/zero-manifest-mesh-fail.dawn.test.ts +25 -28
- package/src/__tests__/dawn/zero-manifest-ready.dawn.test.ts +10 -11
- package/src/__tests__/demo-sortscope-migration.unit.test.ts +5 -5
- package/src/__tests__/derive-bgl-integration.test.ts +34 -44
- package/src/__tests__/derive-render-data-skin.unit.test.ts +1 -1
- package/src/__tests__/draw-published.ts +11 -4
- package/src/__tests__/dynamic-texture-store.unit.test.ts +190 -0
- package/src/__tests__/equirect-bc6h.integration.test.ts +144 -21
- package/src/__tests__/errors.unit.test.ts +1203 -0
- package/src/__tests__/extract-frames-graceful-degradation.test.ts +3 -7
- package/src/__tests__/extract-frames-merge.test.ts +35 -22
- package/src/__tests__/extract-record-no-hardcoded-texture-fields.test.ts +5 -16
- package/src/__tests__/extract-skin-mismatch.unit.test.ts +322 -0
- package/src/__tests__/fetch-binary-decompress.test.ts +356 -0
- package/src/__tests__/four-path-compression.integration.test.ts +395 -0
- package/src/__tests__/frame-targets-shadow-regression.unit.test.ts +1 -1
- package/src/__tests__/fullscreen-feature-host.dawn.test.ts +80 -0
- package/src/__tests__/fullscreen-post-bgl-depth.test.ts +4 -2
- package/src/__tests__/fullscreen-post-depth-params-arity.test.ts +3 -3
- package/src/__tests__/fullscreen-post-process-pass.dawn.test.ts +39 -23
- package/src/__tests__/fullscreen-post-process-pass.unit.test.ts +4 -2
- package/src/__tests__/fxaa-pixel-diff.dawn.test.ts +28 -17
- package/src/__tests__/fxaa-validation-and-resize.dawn.test.ts +29 -18
- package/src/__tests__/fxaa-zero-overhead.dawn.test.ts +16 -12
- package/src/__tests__/geometry.unit.test.ts +525 -159
- package/src/__tests__/glyph-tilemap-worldid.test.ts +1 -1
- package/src/__tests__/gpu-resource-cow-survivor.test.ts +6 -4
- package/src/__tests__/guid-for-asset.unit.test.ts +102 -0
- package/src/__tests__/handle-migration.test.ts +136 -0
- package/src/__tests__/helpers/register-runtime-components.ts +4 -2
- package/src/__tests__/helpers/register-scene-components.ts +1 -1
- package/src/__tests__/host-custom-kind-contract.test-d.ts +47 -0
- package/src/__tests__/host-custom-kind-contract.test.ts +578 -0
- package/src/__tests__/inspect-name.test.ts +139 -0
- package/src/__tests__/instances.test-d.ts +1 -1
- package/src/__tests__/instantiate-mount-deferred-wiring.test.ts +112 -0
- package/src/__tests__/light-casters-9-light.browser.test.ts +73 -76
- package/src/__tests__/light-gpu-byte-neutral.unit.test.ts +7 -10
- package/src/__tests__/light-snapshot.test-d.ts +2 -2
- package/src/__tests__/lights-vec-negative.unit.test.ts +1 -1
- package/src/__tests__/lights.unit.test.ts +16 -500
- package/src/__tests__/loadbyguid-payload.unit.test.ts +117 -0
- package/src/__tests__/loadbyguid-texture-intern.unit.test.ts +213 -0
- package/src/__tests__/loader-extract-graceful.test.ts +146 -0
- package/src/__tests__/loader-name-survival.test.ts +213 -0
- package/src/__tests__/m3-vec-negative.unit.test.ts +3 -2
- package/src/__tests__/material-texture-uv-scale.unit.test.ts +101 -31
- package/src/__tests__/materials.unit.test.ts +10 -27
- package/src/__tests__/mesh-bin-contract.test.ts +28 -0
- package/src/__tests__/mesh-bin-skin-roundtrip.unit.test.ts +149 -0
- package/src/__tests__/mesh-bin.test.ts +38 -0
- package/src/__tests__/mesh-loader-skin-contract.unit.test.ts +120 -0
- package/src/__tests__/mesh-ssbo-grow.unit.test.ts +3 -3
- package/src/__tests__/mip-gate.unit.test.ts +1 -1
- package/src/__tests__/msaa-sprite-pixel-diff.dawn.test.ts +29 -68
- package/src/__tests__/new-kind-refs-contract.test.ts +132 -0
- package/src/__tests__/node-shims.d.ts +4 -6
- package/src/__tests__/package-promotion.test.ts +88 -0
- package/src/__tests__/package-rename.test.ts +103 -0
- package/src/__tests__/pass-selector.unit.test.ts +2 -2
- package/src/__tests__/pbr-pipeline.unit.test.ts +14 -21
- package/src/__tests__/pipeline-builder-msaa.unit.test.ts +6 -9
- package/src/__tests__/pipeline-cache-keying.unit.test.ts +6 -9
- package/src/__tests__/pipeline-spec.test.ts +16 -177
- package/src/__tests__/pipeline.unit.test.ts +154 -1693
- package/src/__tests__/point-light-shadow.dawn.test.ts +33 -42
- package/src/__tests__/point-light-shadow.unit.test.ts +19 -60
- package/src/__tests__/post-process-error-codes.unit.test.ts +4 -1
- package/src/__tests__/post-process-params-component.unit.test.ts +1 -1
- package/src/__tests__/post-process-params-extract.unit.test.ts +2 -5
- package/src/__tests__/postprocess-camera-consistency.test.ts +4 -7
- package/src/__tests__/profiler-assembly.integration.test.ts +1 -1
- package/src/__tests__/propagate-transforms.dawn.test.ts +12 -11
- package/src/__tests__/record-worldid-isolation.test.ts +7 -29
- package/src/__tests__/recover-error-exhaustive.test-d.ts +1 -1
- package/src/__tests__/render-error-exhaustive.test-d.ts +81 -71
- package/src/__tests__/render-feature-assembly.test-d.ts +20 -9
- package/src/__tests__/render-feature-prepared-graphics-docs.unit.test.ts +8 -6
- package/src/__tests__/render-feature-prepared-graphics.browser.test.ts +60 -558
- package/src/__tests__/render-feature-prepared-graphics.dawn.test.ts +57 -544
- package/src/__tests__/render-feature-prepared-graphics.fixture.ts +104 -0
- package/src/__tests__/render-feature-prepared-graphics.integration.test.ts +40 -248
- package/src/__tests__/render-feature-prepared-graphics.regression.integration.test.ts +83 -340
- package/src/__tests__/render-feature-recover.integration.test.ts +9 -49
- package/src/__tests__/render-feature-runtime-surface.test-d.ts +17 -20
- package/src/__tests__/render-schema-consumer.integration.test.ts +20 -13
- package/src/__tests__/render-schema-owner-boundary.unit.test.ts +2 -6
- package/src/__tests__/render-system-cross-world-overlay-queue.test.ts +5 -5
- package/src/__tests__/render-system-extract-dispatch-ordering.test.ts +16 -31
- package/src/__tests__/render-system-extract.test.ts +36 -51
- package/src/__tests__/render-system-extract.unit.test.ts +360 -0
- package/src/__tests__/render-system-fold-bucket.unit.test.ts +3 -5
- package/src/__tests__/render-system-fold-fallback.unit.test.ts +6 -3
- package/src/__tests__/render-system-fold-material.unit.test.ts +3 -5
- package/src/__tests__/render-system-fold-metrics.unit.test.ts +5 -5
- package/src/__tests__/render-system-fold-modegate.unit.test.ts +6 -6
- package/src/__tests__/render-system-fold.dawn.test.ts +7 -5
- package/src/__tests__/render-system-mega.test.ts +292 -190
- package/src/__tests__/render-system-owner-split-contract.test.ts +10 -32
- package/src/__tests__/render-system-record-multi-material-textureview.test.ts +59 -45
- package/src/__tests__/render-system-record-per-submesh-transparency.test.ts +23 -29
- package/src/__tests__/render-system-record.test.ts +398 -235
- package/src/__tests__/render-system-record.unit.test.ts +25 -26
- package/src/__tests__/render-system-skin-bg.unit.test.ts +8 -12
- package/src/__tests__/renderer-consumer.test-d.ts +16 -3
- package/src/__tests__/renderer-health.unit.test.ts +26 -916
- package/src/__tests__/renderer-lifecycle.integration.test.ts +19 -6
- package/src/__tests__/renderer-recover.unit.test.ts +49 -1069
- package/src/__tests__/renderer-result.test-d.ts +19 -9
- package/src/__tests__/renderer-surface.unit.test.ts +3 -5
- package/src/__tests__/renderer-test-utils.ts +56 -0
- package/src/__tests__/renderer.test-d.ts +59 -0
- package/src/__tests__/resolve-asset-handle-err.test.ts +111 -0
- package/src/__tests__/resolve-asset-handle.unit.test.ts +64 -0
- package/src/__tests__/resolve-depth-only-view.test.ts +1 -1
- package/src/__tests__/resolveName-fallback.test.ts +64 -0
- package/src/__tests__/resolveName-null-package.test.ts +38 -0
- package/src/__tests__/resolveName-unified-entry.test.ts +65 -0
- package/src/__tests__/resolveName.test.ts +64 -0
- package/src/__tests__/rhi-null-command-flow.unit.test.ts +43 -261
- package/src/__tests__/rhi-null-renderer-lifecycle.unit.test.ts +41 -169
- package/src/__tests__/roots-to-scene-asset.test.ts +199 -93
- package/src/__tests__/roundtrip-primitive.test.ts +351 -0
- package/src/__tests__/scene-bare-guid-refs-instantiate.test.ts +123 -0
- package/src/__tests__/scene-equirect-roundtrip.test.ts +103 -16
- package/src/__tests__/scene-instance-authoring.integration.test.ts +8 -0
- package/src/__tests__/scene-instance-bridge.integration.test.ts +1 -1
- package/src/__tests__/scene-instance-component.test.ts +1 -1
- package/src/__tests__/scene-mount-fixed-point.test.ts +257 -0
- package/src/__tests__/scene-mount-roundtrip.test.ts +987 -0
- package/src/__tests__/scene-mount-wrapper-roundtrip.test.ts +202 -0
- package/src/__tests__/scene-sugar-instantiate.test.ts +324 -0
- package/src/__tests__/serialize-mounts-roundtrip.test.ts +533 -0
- package/src/__tests__/serialize-scene-asset.test.ts +219 -22
- package/src/__tests__/shadow-caster-empty-schema.test.ts +3 -3
- package/src/__tests__/shadow-csm-cascade-loadop.test.ts +37 -17
- package/src/__tests__/shadow-csm-component.test.ts +3 -5
- package/src/__tests__/shadow-csm-extract.test.ts +2 -100
- package/src/__tests__/shadow-csm-orthoz.test.ts +2 -16
- package/src/__tests__/shadow-csm-runtime-vary.dawn.test.ts +19 -14
- package/src/__tests__/shadow-csm-tile-consistency.test.ts +32 -26
- package/src/__tests__/shadow-csm-ubo.dawn.test.ts +8 -49
- package/src/__tests__/shadow-csm-ubo.test.ts +3 -25
- package/src/__tests__/shadow-csm-viewport.browser.test.ts +1 -1
- package/src/__tests__/shadow-fields-observable.dawn.test.ts +67 -56
- package/src/__tests__/shadow-m1.dawn.test.ts +8 -9
- package/src/__tests__/shadow-mesh-ssbo-order.test.ts +11 -27
- package/src/__tests__/skin-errors.unit.test.ts +1 -1
- package/src/__tests__/skin-extract-getarrayview-count.unit.test.ts +7 -5
- package/src/__tests__/skylight-lazy-projection.test.ts +36 -15
- package/src/__tests__/sparse-tag-scene-roundtrip.test.ts +5 -5
- package/src/__tests__/sprite-cullmode-flip.dawn.test.ts +47 -64
- package/src/__tests__/sprite-lit-bgl-byte-identical.test.ts +12 -11
- package/src/__tests__/sprite-lit-extract-branch.test.ts +1 -1
- package/src/__tests__/sprite-lit-pipeline-cache-key.test.ts +1 -1
- package/src/__tests__/ssao-bgl.test.ts +16 -9
- package/src/__tests__/ssao-buffers.test.ts +2 -2
- package/src/__tests__/ssao-data.test.ts +2 -2
- package/src/__tests__/ssao-errors.test.ts +1 -1
- package/src/__tests__/ssao-passes.test.ts +64 -392
- package/src/__tests__/ssao-pipelines.test.ts +1 -1
- package/src/__tests__/ssao-uniform-layout.test.ts +8 -6
- package/src/__tests__/stencil-outline-pixel.dawn.test.ts +25 -17
- package/src/__tests__/swap-chain-format.unit.test.ts +5 -7
- package/src/__tests__/systems.unit.test.ts +536 -1326
- package/src/__tests__/template-game-default-api-contract.test.ts +362 -0
- package/src/__tests__/text.unit.test.ts +56 -33
- package/src/__tests__/tilemap-childed-despawn.test.ts +8 -14
- package/src/__tests__/tilemap-chunk-extract.overhang-bounds.test.ts +8 -12
- package/src/__tests__/tilemap-chunk-extract.propagate-order.test.ts +2 -1
- package/src/__tests__/tilemap-chunk-extract.test.ts +13 -17
- package/src/__tests__/tilemap-dirty-rebuild.test.ts +7 -11
- package/src/__tests__/tilemap-material-cache.test.ts +8 -13
- package/src/__tests__/tilemap-multi-atlas.test.ts +12 -32
- package/src/__tests__/tilemap-owner-boundary.unit.test.ts +5 -2
- package/src/__tests__/tilemap-region-pack.test.ts +8 -12
- package/src/__tests__/tilemap-spawn-flip-pivot.test.ts +8 -12
- package/src/__tests__/tilemap-uv-inset.test.ts +11 -14
- package/src/__tests__/tilemap-validate.test.ts +1 -1
- package/src/__tests__/tileset-asset-validate.test.ts +638 -0
- package/src/__tests__/transcode-fallback.unit.test.ts +207 -0
- package/src/__tests__/transform-hierarchy-pixel-diff.dawn.test.ts +36 -28
- package/src/__tests__/transient-fields-collect.test.ts +28 -21
- package/src/__tests__/transient-runtime-behavior.test.ts +227 -0
- package/src/__tests__/transparent-sort-tilemap-sprite-interleave.test.ts +4 -4
- package/src/__tests__/variant-selection.unit.test.ts +1 -1
- package/src/__tests__/video-extract-bindgroup.dawn.test.ts +89 -136
- package/src/__tests__/video-loader-consumption.test.ts +86 -0
- package/src/__tests__/video-loader-smoke.dawn.test.ts +60 -0
- package/src/__tests__/view-ubo-layout.browser.test.ts +0 -22
- package/src/__tests__/world-entity-key.test.ts +1 -1
- package/src/__tests__/world-scene-despawn.test.ts +1 -1
- package/src/__tests__/world-scene-instantiate.test.ts +2 -36
- package/src/__tests__/world-scene-nested.test.ts +1 -1
- package/src/__tests__/world-scene-override.test.ts +1 -1
- package/src/backend-selection.ts +69 -0
- package/src/collect-scene-asset.ts +28 -23
- package/src/components/__tests__/camera.test-d.ts +1 -1
- package/src/components/__tests__/camera.test.ts +1 -1
- package/src/components/__tests__/sprite-animation.test-d.ts +2 -2
- package/src/components/__tests__/tile-layer.test-d.ts +1 -1
- package/src/components/__tests__/tile-layer.unit.test.ts +2 -2
- package/src/createRenderer.ts +24 -36
- package/src/errors/environment.ts +1 -1
- package/src/index.ts +47 -113
- package/src/renderer-host.ts +33 -0
- package/src/scene-instances/__tests__/post-spawn-resolve-joints.unit.test.ts +1 -1
- package/src/scene-instances/index.ts +4 -0
- package/src/scene-utils/mount-override-fold.ts +3 -7
- package/src/systems/__tests__/transparent-sort.bench.ts +3 -3
- package/src/systems/sprite-animation-tick.ts +1 -1
- package/src/systems/transparent-sort.ts +38 -38
- package/src/tilemap-register-validate.ts +4 -4
- package/dist/__tests__/bind-group-cache-binding.test.d.ts +0 -2
- package/dist/__tests__/bind-group-cache-binding.test.d.ts.map +0 -1
- package/dist/__tests__/bind-group-cache-frame.test.d.ts +0 -2
- package/dist/__tests__/bind-group-cache-frame.test.d.ts.map +0 -1
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts +0 -2
- package/dist/__tests__/dawn/mesh-update.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts +0 -2
- package/dist/__tests__/dispatch-fullscreen-pass-params.unit.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-manifest.d.ts +0 -131
- package/dist/__tests__/fog-producer-manifest.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel-probe.d.ts +0 -42
- package/dist/__tests__/fog-producer-pixel-probe.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts +0 -2
- package/dist/__tests__/fog-producer-pixel.browser.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts +0 -2
- package/dist/__tests__/fog-producer-pixel.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-real-fixture.d.ts +0 -5
- package/dist/__tests__/fog-producer-real-fixture.d.ts.map +0 -1
- package/dist/__tests__/fog-producer-vfx-effect.d.ts +0 -3
- package/dist/__tests__/fog-producer-vfx-effect.d.ts.map +0 -1
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts +0 -2
- package/dist/__tests__/fog-scene-asset.integration.test.d.ts.map +0 -1
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts +0 -2
- package/dist/__tests__/gpu-resource-store-cubemap-status.test.d.ts.map +0 -1
- package/dist/__tests__/gpu-resource.test.d.ts +0 -2
- package/dist/__tests__/gpu-resource.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts +0 -2
- package/dist/__tests__/hdrp-bgl-slots.browser.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts +0 -2
- package/dist/__tests__/hdrp-buffers.unit.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts +0 -2
- package/dist/__tests__/hdrp-execute-filter.unit.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts +0 -2
- package/dist/__tests__/hdrp-gbuffer-attachments.browser.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts +0 -2
- package/dist/__tests__/hdrp-pipeline-asset-type.test-d.d.ts.map +0 -1
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts +0 -2
- package/dist/__tests__/hdrp-ssao-boundary.test.d.ts.map +0 -1
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts +0 -2
- package/dist/__tests__/hdrp-ssao-falsification.test.d.ts.map +0 -1
- package/dist/__tests__/helpers/primitive-world.d.ts +0 -8
- package/dist/__tests__/helpers/primitive-world.d.ts.map +0 -1
- package/dist/__tests__/helpers/render-asset-port.d.ts +0 -15
- package/dist/__tests__/helpers/render-asset-port.d.ts.map +0 -1
- package/dist/__tests__/helpers/scene-asset-port.d.ts +0 -9
- package/dist/__tests__/helpers/scene-asset-port.d.ts.map +0 -1
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts +0 -2
- package/dist/__tests__/material-derived-coordinates.integration.test.d.ts.map +0 -1
- package/dist/__tests__/pipeline-layout-selection.test.d.ts +0 -2
- package/dist/__tests__/pipeline-layout-selection.test.d.ts.map +0 -1
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts +0 -2
- package/dist/__tests__/post-process-reads-narrowing.test-d.d.ts.map +0 -1
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts +0 -2
- package/dist/__tests__/post-process-register-roundtrip.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts +0 -2
- package/dist/__tests__/render-feature-zero-feature.browser.test.d.ts.map +0 -1
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts +0 -2
- package/dist/__tests__/render-pipeline-trivial.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-caster-membership.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-pssm.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-pssm.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-temporal.browser.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-csm-viewport.test.d.ts +0 -2
- package/dist/__tests__/shadow-csm-viewport.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m2.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m2.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m3-calibrate-run.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3-calibrate.d.ts +0 -83
- package/dist/__tests__/shadow-m3-calibrate.d.ts.map +0 -1
- package/dist/__tests__/shadow-m3.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-m3.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-probe-control-flow.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts +0 -2
- package/dist/__tests__/shadow-quality-metrics.dawn.test.d.ts.map +0 -1
- package/dist/__tests__/temporal-off-path.unit.test.d.ts +0 -2
- package/dist/__tests__/temporal-off-path.unit.test.d.ts.map +0 -1
- package/dist/__tests__/video-cache-regression.unit.test.d.ts +0 -2
- package/dist/__tests__/video-cache-regression.unit.test.d.ts.map +0 -1
- package/dist/asset-kind.d.ts +0 -4
- package/dist/asset-kind.d.ts.map +0 -1
- package/dist/errors/sprite-animation.d.ts +0 -3
- package/dist/errors/sprite-animation.d.ts.map +0 -1
- package/dist/scene-asset-port.d.ts +0 -17
- package/dist/scene-asset-port.d.ts.map +0 -1
- package/dist/scene-collect-errors.d.ts +0 -22
- package/dist/scene-collect-errors.d.ts.map +0 -1
- package/dist/shadow-m3-calibrate.d.ts +0 -40
- package/dist/shadow-m3-calibrate.d.ts.map +0 -1
- package/src/__tests__/bind-group-cache-binding.test.ts +0 -2513
- package/src/__tests__/bind-group-cache-frame.test.ts +0 -1511
- package/src/__tests__/dispatch-fullscreen-pass-composite-swapchain.dawn.test.ts +0 -204
- package/src/__tests__/dispatch-fullscreen-pass-custom-reads.dawn.test.ts +0 -297
- package/src/__tests__/dispatch-fullscreen-pass-depth-composite.dawn.test.ts +0 -271
- package/src/__tests__/dispatch-fullscreen-pass-params.unit.test.ts +0 -321
- package/src/__tests__/fog-producer-manifest.ts +0 -162
- package/src/__tests__/fog-producer-pixel-probe.ts +0 -263
- package/src/__tests__/fog-producer-pixel.browser.test.ts +0 -26
- package/src/__tests__/fog-producer-pixel.dawn.test.ts +0 -55
- package/src/__tests__/fog-producer-real-fixture.ts +0 -805
- package/src/__tests__/fog-producer-vfx-effect.ts +0 -272
- package/src/__tests__/fog-scene-asset.integration.test.ts +0 -123
- package/src/__tests__/gpu-resource-store-cubemap-status.test.ts +0 -207
- package/src/__tests__/gpu-resource.test.ts +0 -1206
- package/src/__tests__/hdrp-bgl-slots.browser.test.ts +0 -50
- package/src/__tests__/hdrp-buffers.unit.test.ts +0 -70
- package/src/__tests__/hdrp-execute-filter.unit.test.ts +0 -200
- package/src/__tests__/hdrp-gbuffer-attachments.browser.test.ts +0 -64
- package/src/__tests__/hdrp-pipeline-asset-type.test-d.ts +0 -139
- package/src/__tests__/hdrp-ssao-boundary.test.ts +0 -237
- package/src/__tests__/hdrp-ssao-falsification.test.ts +0 -289
- package/src/__tests__/helpers/primitive-world.ts +0 -91
- package/src/__tests__/helpers/render-asset-port.ts +0 -65
- package/src/__tests__/helpers/scene-asset-port.ts +0 -23
- package/src/__tests__/material-derived-coordinates.integration.test.ts +0 -100
- package/src/__tests__/pipeline-layout-selection.test.ts +0 -298
- package/src/__tests__/post-process-reads-narrowing.test-d.ts +0 -52
- package/src/__tests__/post-process-register-roundtrip.dawn.test.ts +0 -230
- package/src/__tests__/render-feature-zero-feature.browser.test.ts +0 -152
- package/src/__tests__/render-pipeline-trivial.dawn.test.ts +0 -525
- package/src/__tests__/shadow-csm-caster-membership.test.ts +0 -232
- package/src/__tests__/shadow-csm-pssm.test.ts +0 -142
- package/src/__tests__/shadow-csm-temporal.browser.test.ts +0 -145
- package/src/__tests__/shadow-csm-viewport.test.ts +0 -74
- package/src/__tests__/shadow-m2.dawn.test.ts +0 -394
- package/src/__tests__/shadow-m3-calibrate-run.dawn.test.ts +0 -248
- package/src/__tests__/shadow-m3-calibrate.ts +0 -203
- package/src/__tests__/shadow-m3.dawn.test.ts +0 -288
- package/src/__tests__/shadow-probe-control-flow.dawn.test.ts +0 -264
- package/src/__tests__/shadow-quality-metrics.dawn.test.ts +0 -324
- package/src/__tests__/temporal-off-path.unit.test.ts +0 -69
- package/src/__tests__/video-cache-regression.unit.test.ts +0 -186
- package/src/asset-kind.ts +0 -7
- package/src/errors/sprite-animation.ts +0 -5
- package/src/scene-asset-port.ts +0 -32
- package/src/scene-collect-errors.ts +0 -30
- package/src/shadow-m3-calibrate.ts +0 -171
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
// M3 test -- full schema primitive round-trip (AC-18)
|
|
2
|
+
// (plan-strategy: cover f32/f64/i32/u32/bool/string + entity + shared<>
|
|
3
|
+
// combination + TypedArray->Array normalization).
|
|
4
|
+
//
|
|
5
|
+
// The round-trip path is: spawn live entities → rootsToSceneAsset collect → verify
|
|
6
|
+
// value equivalence. We use live entity spawning rather than instantiateScene because
|
|
7
|
+
// instantiateScene creates internal shared<> refs back to the SceneAsset itself,
|
|
8
|
+
// which would require cataloguing the scene asset.
|
|
9
|
+
|
|
10
|
+
import type { Asset } from '@forgeax/engine-assets-runtime';
|
|
11
|
+
import { AssetRegistry } from '@forgeax/engine-assets-runtime';
|
|
12
|
+
import { defineComponent, type EntityHandle, World } from '@forgeax/engine-ecs';
|
|
13
|
+
import { AssetGuid } from '@forgeax/engine-pack/guid';
|
|
14
|
+
import { ChildOf } from '@forgeax/engine-scene';
|
|
15
|
+
import { describe, expect, it } from 'vitest';
|
|
16
|
+
import { rootsToSceneAsset } from '../collect-scene-asset';
|
|
17
|
+
import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
|
|
18
|
+
|
|
19
|
+
function linkChildren(
|
|
20
|
+
world: World,
|
|
21
|
+
parent: EntityHandle,
|
|
22
|
+
children: readonly (EntityHandle | number)[],
|
|
23
|
+
): void {
|
|
24
|
+
for (const child of children) {
|
|
25
|
+
const result = world.addComponent(child as EntityHandle, {
|
|
26
|
+
component: ChildOf,
|
|
27
|
+
data: { parent },
|
|
28
|
+
});
|
|
29
|
+
if (!result.ok) throw new Error(result.error.code);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
34
|
+
// Helpers
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
36
|
+
|
|
37
|
+
function makeRegistry(): AssetRegistry {
|
|
38
|
+
return new AssetRegistry(makeMockShaderRegistry());
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function makePayload(kind: Asset['kind']): Asset {
|
|
42
|
+
return { kind } as Asset;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function registerComponents(
|
|
46
|
+
world: World,
|
|
47
|
+
...components: readonly Parameters<World['components']['register']>[0][]
|
|
48
|
+
): void {
|
|
49
|
+
for (const component of components) world.components.register(component).unwrap();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// biome-ignore lint/suspicious/noExplicitAny: test helper bridging typed component tokens to World.spawn
|
|
53
|
+
function s(w: World, compToken: any, data: any): number {
|
|
54
|
+
// biome-ignore lint/suspicious/noExplicitAny: test helper adapter for World.spawn overload
|
|
55
|
+
const r = w.spawn({ component: compToken, data } as any);
|
|
56
|
+
if (!r.ok) throw new Error('spawn failed');
|
|
57
|
+
return r.value as number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
61
|
+
// m3-t3(a): individual primitive field round-trip value equivalence
|
|
62
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
63
|
+
|
|
64
|
+
describe('m3-t3(a): individual primitive field round-trip', () => {
|
|
65
|
+
it('f32 field round-trips with value equivalence', () => {
|
|
66
|
+
const Test_F32 = defineComponent('Test_RT_F32', { val: 'f32' });
|
|
67
|
+
|
|
68
|
+
const world = new World();
|
|
69
|
+
registerComponents(world, Test_F32);
|
|
70
|
+
const reg = makeRegistry();
|
|
71
|
+
// 1.5 is exactly representable in f32.
|
|
72
|
+
const r0 = s(world, Test_F32, { val: 1.5 });
|
|
73
|
+
|
|
74
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
75
|
+
expect(collected.ok).toBe(true);
|
|
76
|
+
if (!collected.ok) return;
|
|
77
|
+
const scene = collected.value;
|
|
78
|
+
expect(scene.entities).toHaveLength(1);
|
|
79
|
+
|
|
80
|
+
const ent0 = scene.entities[0];
|
|
81
|
+
if (!ent0) throw new Error('entity 0 missing');
|
|
82
|
+
const comps = ent0.components as Record<string, Record<string, unknown>>;
|
|
83
|
+
const cf = comps.Test_RT_F32;
|
|
84
|
+
expect(cf).toBeDefined();
|
|
85
|
+
if (!cf) throw new Error('Test_RT_F32 missing');
|
|
86
|
+
expect(cf.val).toBe(1.5);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('f64 field round-trips with value equivalence', () => {
|
|
90
|
+
const Test_F64 = defineComponent('Test_RT_F64', { val: 'f64' });
|
|
91
|
+
|
|
92
|
+
const world = new World();
|
|
93
|
+
registerComponents(world, Test_F64);
|
|
94
|
+
const reg = makeRegistry();
|
|
95
|
+
const r0 = s(world, Test_F64, { val: 1.7976931348623157e308 });
|
|
96
|
+
|
|
97
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
98
|
+
expect(collected.ok).toBe(true);
|
|
99
|
+
if (!collected.ok) return;
|
|
100
|
+
const scene = collected.value;
|
|
101
|
+
expect(scene.entities).toHaveLength(1);
|
|
102
|
+
|
|
103
|
+
const ent0 = scene.entities[0];
|
|
104
|
+
if (!ent0) throw new Error('entity 0 missing');
|
|
105
|
+
const comps = ent0.components as Record<string, Record<string, unknown>>;
|
|
106
|
+
const cf = comps.Test_RT_F64;
|
|
107
|
+
expect(cf).toBeDefined();
|
|
108
|
+
if (!cf) throw new Error('Test_RT_F64 missing');
|
|
109
|
+
const v = cf.val as number;
|
|
110
|
+
expect(v).toBeGreaterThan(1e308);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('i32 field round-trips with value equivalence', () => {
|
|
114
|
+
const Test_I32 = defineComponent('Test_RT_I32', { val: 'i32' });
|
|
115
|
+
|
|
116
|
+
const world = new World();
|
|
117
|
+
registerComponents(world, Test_I32);
|
|
118
|
+
const reg = makeRegistry();
|
|
119
|
+
const r0 = s(world, Test_I32, { val: -42 });
|
|
120
|
+
|
|
121
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
122
|
+
expect(collected.ok).toBe(true);
|
|
123
|
+
if (!collected.ok) return;
|
|
124
|
+
const scene = collected.value;
|
|
125
|
+
expect(scene.entities).toHaveLength(1);
|
|
126
|
+
|
|
127
|
+
const ent0 = scene.entities[0];
|
|
128
|
+
if (!ent0) throw new Error('entity 0 missing');
|
|
129
|
+
const comps = ent0.components as Record<string, Record<string, unknown>>;
|
|
130
|
+
const cf = comps.Test_RT_I32;
|
|
131
|
+
expect(cf).toBeDefined();
|
|
132
|
+
if (!cf) throw new Error('Test_RT_I32 missing');
|
|
133
|
+
expect(cf.val).toBe(-42);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('u32 field round-trips with value equivalence', () => {
|
|
137
|
+
const Test_U32 = defineComponent('Test_RT_U32', { val: 'u32' });
|
|
138
|
+
|
|
139
|
+
const world = new World();
|
|
140
|
+
registerComponents(world, Test_U32);
|
|
141
|
+
const reg = makeRegistry();
|
|
142
|
+
const r0 = s(world, Test_U32, { val: 4294967295 });
|
|
143
|
+
|
|
144
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
145
|
+
expect(collected.ok).toBe(true);
|
|
146
|
+
if (!collected.ok) return;
|
|
147
|
+
const scene = collected.value;
|
|
148
|
+
expect(scene.entities).toHaveLength(1);
|
|
149
|
+
|
|
150
|
+
const ent0 = scene.entities[0];
|
|
151
|
+
if (!ent0) throw new Error('entity 0 missing');
|
|
152
|
+
const comps = ent0.components as Record<string, Record<string, unknown>>;
|
|
153
|
+
const cf = comps.Test_RT_U32;
|
|
154
|
+
expect(cf).toBeDefined();
|
|
155
|
+
if (!cf) throw new Error('Test_RT_U32 missing');
|
|
156
|
+
expect(cf.val).toBe(4294967295);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('bool field round-trips with value equivalence', () => {
|
|
160
|
+
const Test_Bool = defineComponent('Test_RT_BOOL', { flag: 'bool' });
|
|
161
|
+
|
|
162
|
+
const world = new World();
|
|
163
|
+
registerComponents(world, Test_Bool, ChildOf);
|
|
164
|
+
const reg = makeRegistry();
|
|
165
|
+
const r0 = s(world, Test_Bool, { flag: true });
|
|
166
|
+
const r1 = s(world, Test_Bool, { flag: false });
|
|
167
|
+
linkChildren(world, r0 as EntityHandle, [r1 as EntityHandle]);
|
|
168
|
+
|
|
169
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
170
|
+
expect(collected.ok).toBe(true);
|
|
171
|
+
if (!collected.ok) return;
|
|
172
|
+
const scene = collected.value;
|
|
173
|
+
expect(scene.entities).toHaveLength(2);
|
|
174
|
+
|
|
175
|
+
const comps0 = (scene.entities[0]?.components as Record<string, Record<string, unknown>>)
|
|
176
|
+
.Test_RT_BOOL;
|
|
177
|
+
expect(comps0).toBeDefined();
|
|
178
|
+
if (!comps0) throw new Error('Test_RT_BOOL missing on e0');
|
|
179
|
+
expect(comps0.flag).toBe(true);
|
|
180
|
+
|
|
181
|
+
const comps1 = (scene.entities[1]?.components as Record<string, Record<string, unknown>>)
|
|
182
|
+
.Test_RT_BOOL;
|
|
183
|
+
expect(comps1).toBeDefined();
|
|
184
|
+
if (!comps1) throw new Error('Test_RT_BOOL missing on e1');
|
|
185
|
+
expect(comps1.flag).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('string field round-trips with value equivalence', () => {
|
|
189
|
+
const Test_Str = defineComponent('Test_RT_STR', { label: 'string' });
|
|
190
|
+
|
|
191
|
+
const world = new World();
|
|
192
|
+
registerComponents(world, Test_Str);
|
|
193
|
+
const reg = makeRegistry();
|
|
194
|
+
const r0 = s(world, Test_Str, { label: 'hello-primitive-test' });
|
|
195
|
+
|
|
196
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
197
|
+
expect(collected.ok).toBe(true);
|
|
198
|
+
if (!collected.ok) return;
|
|
199
|
+
const scene = collected.value;
|
|
200
|
+
expect(scene.entities).toHaveLength(1);
|
|
201
|
+
|
|
202
|
+
const ent0 = scene.entities[0];
|
|
203
|
+
if (!ent0) throw new Error('entity 0 missing');
|
|
204
|
+
const comps = ent0.components as Record<string, Record<string, unknown>>;
|
|
205
|
+
const cf = comps.Test_RT_STR;
|
|
206
|
+
expect(cf).toBeDefined();
|
|
207
|
+
if (!cf) throw new Error('Test_RT_STR missing');
|
|
208
|
+
expect(cf.label).toBe('hello-primitive-test');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
213
|
+
// m3-t3(b): entity + shared<> + primitive mixed entity full-chain value equivalence
|
|
214
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
215
|
+
|
|
216
|
+
describe('m3-t3(b): mixed entity+shared+primitive round-trip', () => {
|
|
217
|
+
it('entity with all primitive types + entity ref + shared ref survives round-trip', () => {
|
|
218
|
+
// Primitive component.
|
|
219
|
+
const Test_MixedPrim = defineComponent('Test_RT_MixedPrim', {
|
|
220
|
+
posX: 'f32',
|
|
221
|
+
posY: 'f32',
|
|
222
|
+
count: 'i32',
|
|
223
|
+
flags: 'u32',
|
|
224
|
+
active: 'bool',
|
|
225
|
+
name: 'string',
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Entity ref component.
|
|
229
|
+
const Test_EntityRef = defineComponent('Test_EntityRef', { target: 'entity' });
|
|
230
|
+
|
|
231
|
+
// Shared ref component.
|
|
232
|
+
const Test_HasShared = defineComponent('Test_HasShared', {
|
|
233
|
+
ref: { type: 'shared<TestAsset>' },
|
|
234
|
+
// biome-ignore lint/suspicious/noExplicitAny: defineComponent constraint too strict for shared<> schema
|
|
235
|
+
} as any);
|
|
236
|
+
|
|
237
|
+
// Register a catalogued asset.
|
|
238
|
+
const assetPayload = makePayload('skeleton');
|
|
239
|
+
const reg = makeRegistry();
|
|
240
|
+
const guid = AssetGuid.parse('d0000000-d000-0000-0000-000000000001');
|
|
241
|
+
if (!guid.ok) throw new Error('guid parse failed');
|
|
242
|
+
reg.catalog(guid.value, assetPayload);
|
|
243
|
+
|
|
244
|
+
const world = new World();
|
|
245
|
+
const handle = world.allocSharedRef('', assetPayload);
|
|
246
|
+
registerComponents(world, Test_MixedPrim, Test_EntityRef, Test_HasShared, ChildOf);
|
|
247
|
+
|
|
248
|
+
// Spawn entity A (primitive holder) as root.
|
|
249
|
+
const r0 = s(world, Test_MixedPrim, {
|
|
250
|
+
posX: 1.5,
|
|
251
|
+
posY: 2.5,
|
|
252
|
+
count: 7,
|
|
253
|
+
flags: 42,
|
|
254
|
+
active: true,
|
|
255
|
+
name: 'mixed-entity',
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Spawn entity B (with entity ref to A + shared ref).
|
|
259
|
+
const r1 = s(world, Test_EntityRef, { target: r0 as EntityHandle });
|
|
260
|
+
world.addComponent(r1 as EntityHandle, {
|
|
261
|
+
component: Test_HasShared,
|
|
262
|
+
// biome-ignore lint/suspicious/noExplicitAny: Handle branded type not assignable to component data for shared<> schema
|
|
263
|
+
data: { ref: handle as any },
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Link r0 → r1 via Children so both are in the BFS closure.
|
|
267
|
+
linkChildren(world, r0 as EntityHandle, [r1 as EntityHandle]);
|
|
268
|
+
|
|
269
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
270
|
+
expect(collected.ok).toBe(true);
|
|
271
|
+
if (!collected.ok) return;
|
|
272
|
+
const scene = collected.value;
|
|
273
|
+
expect(scene.entities).toHaveLength(2);
|
|
274
|
+
|
|
275
|
+
// Entity 0 (r0): primitives
|
|
276
|
+
const ent0 = scene.entities[0];
|
|
277
|
+
if (!ent0) throw new Error('e0 missing');
|
|
278
|
+
const mp = (ent0.components as Record<string, Record<string, unknown>>).Test_RT_MixedPrim;
|
|
279
|
+
expect(mp).toBeDefined();
|
|
280
|
+
if (!mp) throw new Error('Test_RT_MixedPrim missing');
|
|
281
|
+
expect(mp.posX).toBe(1.5);
|
|
282
|
+
expect(mp.posY).toBe(2.5);
|
|
283
|
+
expect(mp.count).toBe(7);
|
|
284
|
+
expect(mp.flags).toBe(42);
|
|
285
|
+
expect(mp.active).toBe(true);
|
|
286
|
+
expect(mp.name).toBe('mixed-entity');
|
|
287
|
+
|
|
288
|
+
// Entity 1 (r1): entity ref + shared ref
|
|
289
|
+
const ent1 = scene.entities[1];
|
|
290
|
+
if (!ent1) throw new Error('e1 missing');
|
|
291
|
+
const er = (ent1.components as Record<string, Record<string, unknown>>).Test_EntityRef;
|
|
292
|
+
expect(er).toBeDefined();
|
|
293
|
+
if (!er) throw new Error('Test_EntityRef missing');
|
|
294
|
+
// After localId renumbering, the target should be a valid localId number.
|
|
295
|
+
expect(typeof er.target).toBe('number');
|
|
296
|
+
expect(er.target as number).toBeGreaterThanOrEqual(0);
|
|
297
|
+
|
|
298
|
+
// shared<> field must resolve to GUID string.
|
|
299
|
+
const hs = (ent1.components as Record<string, Record<string, unknown>>).Test_HasShared;
|
|
300
|
+
expect(hs).toBeDefined();
|
|
301
|
+
if (!hs) throw new Error('Test_HasShared missing');
|
|
302
|
+
expect(typeof hs.ref).toBe('string');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
307
|
+
// m3-t3(c): Float32Array field round-trip as plain Array + value equivalence
|
|
308
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
309
|
+
|
|
310
|
+
describe('m3-t3(c): TypedArray->Array round-trip normalization', () => {
|
|
311
|
+
it('Float32Array field round-trips to plain Array with value equivalence', () => {
|
|
312
|
+
const Test_ArrF32 = defineComponent('Test_RT_ArrF32', {
|
|
313
|
+
data: 'array<f32>',
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
const world = new World();
|
|
317
|
+
registerComponents(world, Test_ArrF32);
|
|
318
|
+
const reg = makeRegistry();
|
|
319
|
+
const arr = new Float32Array([1.0, 2.5, 3.75, 4.0, 5.125]);
|
|
320
|
+
const r0 = s(world, Test_ArrF32, {
|
|
321
|
+
// biome-ignore lint/suspicious/noExplicitAny: Float32Array not directly assignable to component data field
|
|
322
|
+
data: arr as any,
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const collected = rootsToSceneAsset(reg, world, [r0 as EntityHandle]);
|
|
326
|
+
expect(collected.ok).toBe(true);
|
|
327
|
+
if (!collected.ok) return;
|
|
328
|
+
const scene = collected.value;
|
|
329
|
+
expect(scene.entities).toHaveLength(1);
|
|
330
|
+
|
|
331
|
+
const ent0 = scene.entities[0];
|
|
332
|
+
if (!ent0) throw new Error('entity 0 missing');
|
|
333
|
+
const comps = ent0.components as Record<string, Record<string, unknown>>;
|
|
334
|
+
const cf = comps.Test_RT_ArrF32;
|
|
335
|
+
expect(cf).toBeDefined();
|
|
336
|
+
if (!cf) throw new Error('Test_RT_ArrF32 missing');
|
|
337
|
+
const data = cf.data as unknown[];
|
|
338
|
+
|
|
339
|
+
// Round-trip output must be a plain Array.
|
|
340
|
+
expect(Array.isArray(data)).toBe(true);
|
|
341
|
+
expect(data).not.toBeInstanceOf(Float32Array);
|
|
342
|
+
|
|
343
|
+
// Values must be equivalent.
|
|
344
|
+
expect(data).toHaveLength(5);
|
|
345
|
+
expect(data[0]).toBe(1.0);
|
|
346
|
+
expect(data[1]).toBe(2.5);
|
|
347
|
+
expect(data[2]).toBe(3.75);
|
|
348
|
+
expect(data[3]).toBe(4.0);
|
|
349
|
+
expect(data[4]).toBeCloseTo(5.125, 5);
|
|
350
|
+
});
|
|
351
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// scene-bare-guid-refs-instantiate.test — regression for the prod Play
|
|
2
|
+
// instantiate crash (feedback 2026-06-23, root cause corrected 2026-06-24).
|
|
3
|
+
//
|
|
4
|
+
// Reproduces the production on-disk pack shape that in-process / unit tests
|
|
5
|
+
// never exercised: a catalogued scene envelope whose `refs[]` are *bare GUID
|
|
6
|
+
// edges* (`sceneEntityId` / `sourceField` stripped at the w7 D-10
|
|
7
|
+
// serialization boundary), with multiple entities referencing the same mesh
|
|
8
|
+
// GUID through `MeshFilter.assetHandle`.
|
|
9
|
+
//
|
|
10
|
+
// Before the fix, `_resolveSceneGuids` took Branch A (envelope.refs.length>0)
|
|
11
|
+
// but `continue`-skipped every bare edge (no sceneEntityId/sourceField) →
|
|
12
|
+
// `resolvedMap` stayed empty → the entity-walk fallback (only reachable on the
|
|
13
|
+
// `else` / no-refs branch) never ran → the GUID *string* passed through to
|
|
14
|
+
// spawn. There `col.view[row] = (guidString as number)` coerced to 0 and
|
|
15
|
+
// `retainSharedScalarHandle(guidString)` skipped the `< BUILTIN_BASE` guard
|
|
16
|
+
// (NaN compare is false) → `SharedRefStore.retain` routed `shared-ref-released`
|
|
17
|
+
// to the World error handler, and the field read back as the sentinel 0 (the
|
|
18
|
+
// per-frame `asset-not-registered` flood in the studio report).
|
|
19
|
+
//
|
|
20
|
+
// The fix falls through to the entity-walk fallback whenever the structured
|
|
21
|
+
// edges resolved nothing, so GUID strings resolve to live user-tier handles
|
|
22
|
+
// before spawn.
|
|
23
|
+
|
|
24
|
+
import { AssetRegistry } from '@forgeax/engine-assets-runtime';
|
|
25
|
+
import { World } from '@forgeax/engine-ecs';
|
|
26
|
+
import { createBoxGeometry } from '@forgeax/engine-geometry';
|
|
27
|
+
import { AssetGuid } from '@forgeax/engine-pack/guid';
|
|
28
|
+
import { MeshFilter, SceneInstance } from '@forgeax/engine-render';
|
|
29
|
+
import type { LocalEntityId, MeshAsset, SceneAsset, SceneEntity } from '@forgeax/engine-types';
|
|
30
|
+
import { BUILTIN_BASE } from '@forgeax/engine-types';
|
|
31
|
+
import { describe, expect, it } from 'vitest';
|
|
32
|
+
import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
|
|
33
|
+
import { registerSceneComponents } from './helpers/register-scene-components';
|
|
34
|
+
|
|
35
|
+
function localId(n: number): LocalEntityId {
|
|
36
|
+
return n as LocalEntityId;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function cubeMesh(): MeshAsset {
|
|
40
|
+
const res = createBoxGeometry(1, 1, 1);
|
|
41
|
+
if (!res.ok) throw new Error('createBoxGeometry(1,1,1) failed');
|
|
42
|
+
return res.value;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Two distinct mesh GUIDs referenced from N entities each — mirrors the studio
|
|
46
|
+
// report where engine builtin cube/sphere were among the unresolved handles.
|
|
47
|
+
const MESH_GUID_A = '00d274da-e863-41d8-bafe-10b97d1468d4';
|
|
48
|
+
const MESH_GUID_B = '95730fd2-1111-4222-8333-444455556666';
|
|
49
|
+
|
|
50
|
+
describe('regression — prod bare-GUID scene envelope.refs resolve before retain', () => {
|
|
51
|
+
it('instantiate resolves bare-GUID MeshFilter.assetHandle across N entities (no shared-ref-released)', () => {
|
|
52
|
+
const reg = new AssetRegistry(makeMockShaderRegistry());
|
|
53
|
+
const world = new World();
|
|
54
|
+
registerSceneComponents(world, [MeshFilter]);
|
|
55
|
+
|
|
56
|
+
// Catalogue the two mesh payloads (as loadByGuid would on the prod path).
|
|
57
|
+
const guidA = AssetGuid.parse(MESH_GUID_A);
|
|
58
|
+
const guidB = AssetGuid.parse(MESH_GUID_B);
|
|
59
|
+
if (!guidA.ok || !guidB.ok) throw new Error('GUID parse failed');
|
|
60
|
+
expect(reg.catalog(guidA.value, cubeMesh()).ok).toBe(true);
|
|
61
|
+
expect(reg.catalog(guidB.value, cubeMesh()).ok).toBe(true);
|
|
62
|
+
|
|
63
|
+
// Build a scene whose entities reference the meshes by GUID *string* —
|
|
64
|
+
// exactly the post-parseScenePayload intermediate state. Several entities
|
|
65
|
+
// share each GUID to exercise the dedup (one allocSharedRef per GUID).
|
|
66
|
+
const entities: SceneEntity[] = [];
|
|
67
|
+
for (let i = 0; i < 4; i++) {
|
|
68
|
+
entities.push({
|
|
69
|
+
localId: localId(i),
|
|
70
|
+
components: {
|
|
71
|
+
MeshFilter: { assetHandle: i % 2 === 0 ? MESH_GUID_A : MESH_GUID_B },
|
|
72
|
+
},
|
|
73
|
+
} as unknown as SceneEntity);
|
|
74
|
+
}
|
|
75
|
+
const scene: SceneAsset = { kind: 'scene', entities };
|
|
76
|
+
|
|
77
|
+
// Catalogue the scene as an envelope carrying BARE-GUID refs[] — no
|
|
78
|
+
// sceneEntityId / sourceField (the prod serialization shape). This forces
|
|
79
|
+
// Branch A of _resolveSceneGuids while leaving every edge unresolvable.
|
|
80
|
+
const SCENE_GUID = 'c1111111-2222-4333-8444-555566667777';
|
|
81
|
+
const sceneGuid = AssetGuid.parse(SCENE_GUID);
|
|
82
|
+
if (!sceneGuid.ok) throw new Error('scene GUID parse failed');
|
|
83
|
+
expect(
|
|
84
|
+
reg.catalog(sceneGuid.value, scene, [{ guid: MESH_GUID_A }, { guid: MESH_GUID_B }]).ok,
|
|
85
|
+
).toBe(true);
|
|
86
|
+
|
|
87
|
+
// Mint the scene handle and instantiate through the public sugar entry.
|
|
88
|
+
const sceneHandle = world.allocSharedRef('SceneAsset', scene);
|
|
89
|
+
const res = reg.instantiate<SceneAsset>(sceneHandle, world);
|
|
90
|
+
|
|
91
|
+
expect(res.ok).toBe(true);
|
|
92
|
+
if (!res.ok) return;
|
|
93
|
+
|
|
94
|
+
// Every spawned member's MeshFilter.assetHandle is a resolved
|
|
95
|
+
// user-tier slot (>= BUILTIN_BASE) — not the sentinel 0 a coerced GUID
|
|
96
|
+
// string would leave behind.
|
|
97
|
+
const inst = world.get(res.value, SceneInstance);
|
|
98
|
+
expect(inst.ok).toBe(true);
|
|
99
|
+
if (!inst.ok) return;
|
|
100
|
+
let seen = 0;
|
|
101
|
+
for (let i = 0; i < 4; i++) {
|
|
102
|
+
const member = inst.value.mapping[i] as unknown as number;
|
|
103
|
+
const mf = world.get(member as never, MeshFilter);
|
|
104
|
+
expect(mf.ok).toBe(true);
|
|
105
|
+
if (!mf.ok) continue;
|
|
106
|
+
const handle = mf.value.assetHandle as unknown as number;
|
|
107
|
+
expect(typeof handle).toBe('number');
|
|
108
|
+
expect(handle).toBeGreaterThanOrEqual(BUILTIN_BASE);
|
|
109
|
+
seen++;
|
|
110
|
+
}
|
|
111
|
+
expect(seen).toBe(4);
|
|
112
|
+
|
|
113
|
+
// Dedup: the two distinct GUIDs mint exactly two user-tier handles,
|
|
114
|
+
// shared across the four members (one allocSharedRef per unique GUID).
|
|
115
|
+
const handles = new Set<number>();
|
|
116
|
+
for (let i = 0; i < 4; i++) {
|
|
117
|
+
const member = inst.value.mapping[i] as unknown as number;
|
|
118
|
+
const mf = world.get(member as never, MeshFilter);
|
|
119
|
+
if (mf.ok) handles.add(mf.value.assetHandle as unknown as number);
|
|
120
|
+
}
|
|
121
|
+
expect(handles.size).toBe(2);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -1,8 +1,48 @@
|
|
|
1
|
+
// feat-20260630-equirect-kind-internalized-ibl-declarative-skyligh M3 / w15 —
|
|
2
|
+
// scene roundtrip + instantiate handle resolution for the declarative skylight
|
|
3
|
+
// (plan-strategy §5.3 key test point (4); requirements AC-07 / AC-04;
|
|
4
|
+
// research R-1 — scene-handle-fields generic `shared<` extraction auto-covers
|
|
5
|
+
// the equirect field, no per-field whitelist).
|
|
6
|
+
//
|
|
7
|
+
// Two assertions, both on the CONSUMER path (not `.test-d.ts`):
|
|
8
|
+
// (1) A SceneAsset whose Skylight references an equirect source by GUID
|
|
9
|
+
// string round-trips through instantiate: the GUID resolves to a live
|
|
10
|
+
// user-tier shared handle on the spawned Skylight column (AC-07). This
|
|
11
|
+
// exercises BOTH scene-resolution paths the equirect field rides:
|
|
12
|
+
// - extractSceneEntityHandleGuids (generic `shared<` detection, R-1)
|
|
13
|
+
// - parseScenePayload HANDLE_FIELD_NAMES allowlist (w27, second path)
|
|
14
|
+
// (2) `world.spawn(Skylight{equirect}).data.equirect` is typed
|
|
15
|
+
// `Handle<'EquirectAsset','shared'>` — verified by assigning a branded
|
|
16
|
+
// EquirectAsset handle into the spawn data and reading it back (a wrong
|
|
17
|
+
// field type would fail typecheck on this consumer path, AC-04).
|
|
18
|
+
//
|
|
19
|
+
// TDD red phase: the equirect field lands in w16 (Skylight component) +
|
|
20
|
+
// w27 (HANDLE_FIELD_NAMES). Until then the `shared<EquirectAsset>` field name
|
|
21
|
+
// is `cubemap` and this file fails to compile / resolve — that is the red.
|
|
22
|
+
|
|
23
|
+
import { AssetRegistry } from '@forgeax/engine-assets-runtime';
|
|
24
|
+
import type { EntityHandle } from '@forgeax/engine-ecs';
|
|
1
25
|
import { World } from '@forgeax/engine-ecs';
|
|
2
|
-
import { Skylight } from '@forgeax/engine-render
|
|
3
|
-
import type {
|
|
26
|
+
import { Skylight } from '@forgeax/engine-render';
|
|
27
|
+
import type {
|
|
28
|
+
EquirectAsset,
|
|
29
|
+
Handle,
|
|
30
|
+
LocalEntityId,
|
|
31
|
+
SceneAsset,
|
|
32
|
+
SceneEntity,
|
|
33
|
+
} from '@forgeax/engine-types';
|
|
34
|
+
import { BUILTIN_BASE } from '@forgeax/engine-types';
|
|
4
35
|
import { describe, expect, it } from 'vitest';
|
|
36
|
+
import { makeMockShaderRegistry } from './helpers/mock-shader-registry';
|
|
37
|
+
import { registerSceneComponents } from './helpers/register-scene-components';
|
|
38
|
+
|
|
39
|
+
function localId(n: number): LocalEntityId {
|
|
40
|
+
return n as LocalEntityId;
|
|
41
|
+
}
|
|
5
42
|
|
|
43
|
+
// A minimal valid EquirectAsset POD (kind:'equirect', single 2D rgba16float
|
|
44
|
+
// image). The roundtrip never decodes the bytes; a tiny tight-packed buffer is
|
|
45
|
+
// enough to catalogue + resolve the handle.
|
|
6
46
|
function equirectPod(width = 4, height = 2): EquirectAsset {
|
|
7
47
|
return {
|
|
8
48
|
kind: 'equirect',
|
|
@@ -14,20 +54,67 @@ function equirectPod(width = 4, height = 2): EquirectAsset {
|
|
|
14
54
|
};
|
|
15
55
|
}
|
|
16
56
|
|
|
17
|
-
|
|
18
|
-
|
|
57
|
+
const EQUIRECT_GUID = '019e4a26-3c29-7420-af5d-20f2724a16b0';
|
|
58
|
+
|
|
59
|
+
describe('scene equirect roundtrip + instantiate handle resolution (M3 / w15)', () => {
|
|
60
|
+
it('(1) Skylight{equirect: GUID} round-trips: instantiate resolves the GUID to a live user-tier shared handle (AC-07)', async () => {
|
|
61
|
+
const reg = new AssetRegistry(makeMockShaderRegistry());
|
|
62
|
+
const world = new World();
|
|
63
|
+
registerSceneComponents(world, [Skylight]);
|
|
64
|
+
|
|
65
|
+
// Catalogue the equirect payload exactly as loadByGuid would on the prod
|
|
66
|
+
// path, so the GUID string in the scene resolves to a real handle.
|
|
67
|
+
const { AssetGuid } = await import('@forgeax/engine-pack/guid');
|
|
68
|
+
const guid = AssetGuid.parse(EQUIRECT_GUID);
|
|
69
|
+
if (!guid.ok) throw new Error('equirect GUID parse failed');
|
|
70
|
+
expect(reg.catalog(guid.value, equirectPod()).ok).toBe(true);
|
|
71
|
+
|
|
72
|
+
// A scene whose single Skylight references the equirect source by GUID
|
|
73
|
+
// string — the post-parseScenePayload intermediate state where handle
|
|
74
|
+
// fields hold GUID strings awaiting resolution.
|
|
75
|
+
const entities: SceneEntity[] = [
|
|
76
|
+
{
|
|
77
|
+
localId: localId(0),
|
|
78
|
+
components: {
|
|
79
|
+
Skylight: { equirect: EQUIRECT_GUID, intensity: 1.0 },
|
|
80
|
+
},
|
|
81
|
+
} as unknown as SceneEntity,
|
|
82
|
+
];
|
|
83
|
+
const scene: SceneAsset = { kind: 'scene', entities };
|
|
84
|
+
|
|
85
|
+
const sceneHandle = world.allocSharedRef('SceneAsset', scene);
|
|
86
|
+
const res = reg.instantiate<SceneAsset>(sceneHandle, world);
|
|
87
|
+
expect(res.ok).toBe(true);
|
|
88
|
+
if (!res.ok) return;
|
|
89
|
+
|
|
90
|
+
// The spawned Skylight's equirect field must be a resolved user-tier slot
|
|
91
|
+
// (>= BUILTIN_BASE), not the sentinel 0 a coerced GUID string would leave.
|
|
92
|
+
const root = res.value as EntityHandle;
|
|
93
|
+
const { SceneInstance } = await import('@forgeax/engine-render');
|
|
94
|
+
const inst = world.get(root, SceneInstance);
|
|
95
|
+
expect(inst.ok).toBe(true);
|
|
96
|
+
if (!inst.ok) return;
|
|
97
|
+
const member = inst.value.mapping[0] as unknown as EntityHandle;
|
|
98
|
+
const sky = world.get(member, Skylight);
|
|
99
|
+
expect(sky.ok).toBe(true);
|
|
100
|
+
if (!sky.ok) return;
|
|
101
|
+
const equirectHandle = sky.value.equirect as unknown as number;
|
|
102
|
+
expect(typeof equirectHandle).toBe('number');
|
|
103
|
+
expect(equirectHandle).toBeGreaterThanOrEqual(BUILTIN_BASE);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('(2) world.spawn(Skylight{equirect}).data.equirect is typed Handle<EquirectAsset,shared> on the consumer path (AC-04)', () => {
|
|
19
107
|
const world = new World();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
expect(
|
|
31
|
-
if (resolved.ok) expect(resolved.value.kind).toBe('equirect');
|
|
108
|
+
registerSceneComponents(world, [Skylight]);
|
|
109
|
+
// Branded EquirectAsset handle — assigning it into the spawn `equirect`
|
|
110
|
+
// field is the consumer-path type assertion: a wrong field type (e.g. the
|
|
111
|
+
// retired CubeTextureAsset, or a non-handle column) would fail typecheck
|
|
112
|
+
// here, not in a separate .test-d.ts.
|
|
113
|
+
const equirect: Handle<'EquirectAsset', 'shared'> = 1024 as Handle<'EquirectAsset', 'shared'>;
|
|
114
|
+
const e = world.spawn({ component: Skylight, data: { equirect } }).unwrap();
|
|
115
|
+
const r = world.get(e, Skylight).unwrap();
|
|
116
|
+
// The read-back value carries the same handle (runtime confirms the column
|
|
117
|
+
// stored the shared handle, complementing the compile-time field type).
|
|
118
|
+
expect(r.equirect as unknown as number).toBe(1024);
|
|
32
119
|
});
|
|
33
120
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { instantiateFlat } from '../../../assets-runtime/src/registry/instantiate';
|
|
3
|
+
|
|
4
|
+
describe('scene authoring bridge', () => {
|
|
5
|
+
it('exposes the flat authoring entry without a runtime duplicate', () => {
|
|
6
|
+
expect(typeof instantiateFlat).toBe('function');
|
|
7
|
+
});
|
|
8
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { postSpawnResolveJoints } from '@forgeax/engine-render/internal';
|
|
2
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { postSpawnResolveJoints } from '../../../render/src/scene-instances/post-spawn-resolve-joints';
|
|
3
3
|
|
|
4
4
|
describe('scene instance skin bridge', () => {
|
|
5
5
|
it('exports a post-spawn resolver for nested mounts', () => {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// dynamic structure); plan-tasks §M2 / w15.
|
|
15
15
|
|
|
16
16
|
import { componentSchema } from '@forgeax/engine-ecs/internal';
|
|
17
|
-
import { SceneInstance } from '@forgeax/engine-render
|
|
17
|
+
import { SceneInstance } from '@forgeax/engine-render';
|
|
18
18
|
import { describe, expect, it } from 'vitest';
|
|
19
19
|
|
|
20
20
|
describe('SceneInstance component (w15)', () => {
|