@forgeax/engine-runtime 0.1.4 → 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
|
@@ -5,29 +5,66 @@
|
|
|
5
5
|
// Each original file body sits in its own block-scope so helper names
|
|
6
6
|
// cannot collide; describe() inside still registers globally with vitest.
|
|
7
7
|
|
|
8
|
+
import { HANDLE_CUBE } from '@forgeax/engine-assets-runtime';
|
|
8
9
|
import type { World as WorldType } from '@forgeax/engine-ecs';
|
|
10
|
+
import { World } from '@forgeax/engine-ecs';
|
|
9
11
|
import type { Renderer as RendererType } from '@forgeax/engine-render';
|
|
10
12
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
Camera,
|
|
14
|
+
DirectionalLight,
|
|
15
|
+
Instances,
|
|
16
|
+
MeshFilter,
|
|
17
|
+
MeshRenderer,
|
|
18
|
+
} from '@forgeax/engine-render';
|
|
19
|
+
import { Transform } from '@forgeax/engine-scene';
|
|
14
20
|
import type { Handle } from '@forgeax/engine-types';
|
|
15
21
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
import { extractFrame, prepareExtractContext } from '../../../render/src/render-system-extract';
|
|
23
|
+
import { drawWithOwners } from './renderer-test-utils';
|
|
24
|
+
|
|
25
|
+
type RendererErrorObservation = {
|
|
26
|
+
readonly code: string;
|
|
27
|
+
readonly detail?: unknown;
|
|
28
|
+
readonly hint?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
type RendererLike = RendererType;
|
|
32
|
+
|
|
33
|
+
function unwrapRendererError(value: unknown): RendererErrorObservation {
|
|
34
|
+
let current = value as RendererErrorObservation;
|
|
35
|
+
while (
|
|
36
|
+
current.detail !== undefined &&
|
|
37
|
+
typeof current.detail === 'object' &&
|
|
38
|
+
current.detail !== null
|
|
39
|
+
) {
|
|
40
|
+
const cause = (current.detail as { cause?: unknown }).cause;
|
|
41
|
+
if (
|
|
42
|
+
cause === undefined ||
|
|
43
|
+
typeof cause !== 'object' ||
|
|
44
|
+
cause === null ||
|
|
45
|
+
typeof (cause as { code?: unknown }).code !== 'string'
|
|
46
|
+
) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
current = cause as RendererErrorObservation;
|
|
29
50
|
}
|
|
30
|
-
return
|
|
51
|
+
return current;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function subscribeRendererErrors(
|
|
55
|
+
renderer: RendererType,
|
|
56
|
+
listener: (error: RendererErrorObservation) => void,
|
|
57
|
+
): () => void {
|
|
58
|
+
return renderer.subscribe((event) => {
|
|
59
|
+
if (event.kind === 'error') listener(unwrapRendererError(event.error));
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function drawPublished(renderer: RendererType, world: WorldType) {
|
|
64
|
+
const attached = renderer.attach(world);
|
|
65
|
+
if (!attached.ok) throw attached.error;
|
|
66
|
+
world.update().unwrap();
|
|
67
|
+
return drawWithOwners(renderer, world);
|
|
31
68
|
}
|
|
32
69
|
|
|
33
70
|
// ─── from render-system.test.ts ───
|
|
@@ -43,11 +80,11 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
43
80
|
//
|
|
44
81
|
// Charter proposition 4 mapping:
|
|
45
82
|
// case A (entity missing Transform / MeshRenderer): default
|
|
46
|
-
// values used; no
|
|
83
|
+
// values used; no error event fired (D-Q7 softening point).
|
|
47
84
|
// case B (world has 0 Camera entity): fires
|
|
48
85
|
// 'render-system-no-camera' + frame skipped.
|
|
49
86
|
// case C (world has 0 DirectionalLight): unlit fallback
|
|
50
|
-
// (intensity = 0); no
|
|
87
|
+
// (intensity = 0); no error event fired (D-Q7 softening point).
|
|
51
88
|
// case D (world has N>1 Camera / Light): fires
|
|
52
89
|
// 'render-system-multi-camera' / 'render-system-multi-light' +
|
|
53
90
|
// uses first archetype hit.
|
|
@@ -154,6 +191,7 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
154
191
|
log.writeBufferCount++;
|
|
155
192
|
},
|
|
156
193
|
writeTexture: () => undefined,
|
|
194
|
+
onSubmittedWorkDone: () => Promise.resolve(undefined),
|
|
157
195
|
},
|
|
158
196
|
createShaderModule: () => ({ getCompilationInfo: async () => ({ messages: [] }) }),
|
|
159
197
|
createBindGroupLayout: () => ({}),
|
|
@@ -172,7 +210,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
172
210
|
setPipeline: () => {
|
|
173
211
|
log.setPipelineCount++;
|
|
174
212
|
},
|
|
175
|
-
setViewport: () => undefined,
|
|
176
213
|
setVertexBuffer: () => undefined,
|
|
177
214
|
setIndexBuffer: () => undefined,
|
|
178
215
|
setBindGroup: (groupIndex: number, _bg: unknown, dynamicOffsets?: number[]) => {
|
|
@@ -235,17 +272,13 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
235
272
|
// w10: materialShaders[] entries are required so the record/extract path
|
|
236
273
|
// can validate material passes that reference forgeax::default-standard-pbr
|
|
237
274
|
// and forgeax::default-unlit. Each entry carries a minimal composedWgsl
|
|
238
|
-
// stub +
|
|
275
|
+
// stub + empty paramSchema + empty variants.
|
|
239
276
|
const materialShaderStub = (identifier: string) => ({
|
|
240
277
|
identifier,
|
|
241
278
|
sourcePath: `${identifier}.wgsl`,
|
|
242
279
|
composedWgsl: '/* stub */',
|
|
243
|
-
paramSchema:
|
|
244
|
-
variants:
|
|
245
|
-
(variant) =>
|
|
246
|
-
variant.defines.STORAGE_BUFFER_AVAILABLE === false &&
|
|
247
|
-
variant.defines.VERTEX_COLOR_AVAILABLE === false,
|
|
248
|
-
),
|
|
280
|
+
paramSchema: '[]',
|
|
281
|
+
variants: [],
|
|
249
282
|
});
|
|
250
283
|
const manifest = {
|
|
251
284
|
schemaVersion: '1.0.0',
|
|
@@ -292,19 +325,7 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
292
325
|
// Type-only import imports the public surface so we can assert RenderSystem
|
|
293
326
|
// is re-exported by `@forgeax/engine-runtime` (F-1 single-import contract part 3/3).
|
|
294
327
|
async function importEngine(): Promise<{
|
|
295
|
-
createRenderer: (
|
|
296
|
-
canvas: unknown,
|
|
297
|
-
opts?: unknown,
|
|
298
|
-
bundler?: unknown,
|
|
299
|
-
) => Promise<{
|
|
300
|
-
backend: string;
|
|
301
|
-
ready: Promise<void>;
|
|
302
|
-
draw: (worlds: unknown, opts: { cameraOwner: number; resourceOwner: number }) => void;
|
|
303
|
-
onError: (cb: (err: { code: string; detail?: unknown; hint?: string }) => void) => () => void;
|
|
304
|
-
assets: {
|
|
305
|
-
register: (asset: unknown) => { ok: boolean; value: unknown };
|
|
306
|
-
};
|
|
307
|
-
}>;
|
|
328
|
+
createRenderer: (...args: unknown[]) => Promise<{ unwrap(): RendererLike }>;
|
|
308
329
|
}> {
|
|
309
330
|
return (await import(ENGINE)) as never;
|
|
310
331
|
}
|
|
@@ -317,8 +338,7 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
317
338
|
allocSharedRef: (target: string, payload: unknown) => Handle<string, 'shared'>;
|
|
318
339
|
};
|
|
319
340
|
}> {
|
|
320
|
-
|
|
321
|
-
return { World: withPrimitiveMeshes(BaseWorld) } as never;
|
|
341
|
+
return (await import('@forgeax/engine-ecs')) as never;
|
|
322
342
|
}
|
|
323
343
|
|
|
324
344
|
async function importComponents(): Promise<{
|
|
@@ -336,27 +356,14 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
336
356
|
HANDLE_TRIANGLE: Handle<'MeshAsset', 'shared'>;
|
|
337
357
|
}> {
|
|
338
358
|
return {
|
|
339
|
-
...(await import('@forgeax/engine-render
|
|
359
|
+
...(await import('@forgeax/engine-render')),
|
|
340
360
|
...(await import('@forgeax/engine-scene')),
|
|
341
|
-
|
|
342
|
-
HANDLE_TRIANGLE: TEST_TRIANGLE_HANDLE,
|
|
361
|
+
...(await import('@forgeax/engine-assets-runtime')),
|
|
343
362
|
} as never;
|
|
344
363
|
}
|
|
345
364
|
|
|
346
365
|
interface TestSetup {
|
|
347
|
-
createRenderer: (
|
|
348
|
-
canvas: unknown,
|
|
349
|
-
opts?: unknown,
|
|
350
|
-
bundler?: unknown,
|
|
351
|
-
) => Promise<{
|
|
352
|
-
backend: string;
|
|
353
|
-
ready: Promise<void>;
|
|
354
|
-
draw: (worlds: unknown, opts: { cameraOwner: number; resourceOwner: number }) => void;
|
|
355
|
-
onError: (cb: (err: { code: string; detail?: unknown; hint?: string }) => void) => () => void;
|
|
356
|
-
assets: {
|
|
357
|
-
register: (asset: unknown) => { ok: boolean; value: unknown };
|
|
358
|
-
};
|
|
359
|
-
}>;
|
|
366
|
+
createRenderer: (...args: unknown[]) => Promise<RendererType>;
|
|
360
367
|
log: DeviceCallLog;
|
|
361
368
|
}
|
|
362
369
|
|
|
@@ -365,7 +372,10 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
365
372
|
const { device } = makeMockGPUDevice(log);
|
|
366
373
|
vi.stubGlobal('navigator', { ...baseNavigator, gpu: makeMockGPU(device) });
|
|
367
374
|
const engine = await importEngine();
|
|
368
|
-
return {
|
|
375
|
+
return {
|
|
376
|
+
createRenderer: async (...args: unknown[]) => (await engine.createRenderer(...args)).unwrap(),
|
|
377
|
+
log,
|
|
378
|
+
};
|
|
369
379
|
}
|
|
370
380
|
|
|
371
381
|
// ─── Tests ──────────────────────────────────────────────────────────────────
|
|
@@ -379,7 +389,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
379
389
|
{},
|
|
380
390
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
381
391
|
);
|
|
382
|
-
await renderer.ready;
|
|
383
392
|
const { World } = await importEcs();
|
|
384
393
|
const C = await importComponents();
|
|
385
394
|
const world = new World();
|
|
@@ -417,28 +426,24 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
417
426
|
);
|
|
418
427
|
|
|
419
428
|
const errors: { code: string }[] = [];
|
|
420
|
-
renderer
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
(world as WorldType)
|
|
425
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
429
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
430
|
+
drawPublished(renderer, world as WorldType);
|
|
431
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
432
|
+
Object.assign(log, makeLog());
|
|
433
|
+
drawPublished(renderer, world as WorldType);
|
|
426
434
|
|
|
427
435
|
// DirectionalLight with merged shadow fields.
|
|
428
436
|
expect(errors).toHaveLength(0);
|
|
429
|
-
//
|
|
430
|
-
//
|
|
431
|
-
expect(log.beginRenderPassCount).toBe(
|
|
432
|
-
|
|
433
|
-
expect(log.
|
|
434
|
-
//
|
|
435
|
-
|
|
436
|
-
expect(log.drawIndexedCount).toBeGreaterThanOrEqual(1);
|
|
437
|
-
expect(log.encoderFinishCount).toBe(8); // shadow fallback + 6 cube fallback faces + frame
|
|
438
|
-
expect(log.queueSubmitCount).toBe(8); // shadow fallback + 6 cube fallback faces + frame
|
|
437
|
+
// The current typed graph owns one shadow fallback, six cube fallback
|
|
438
|
+
// faces, and the frame attachment pass.
|
|
439
|
+
expect(log.beginRenderPassCount).toBe(8);
|
|
440
|
+
expect(log.setPipelineCount).toBe(1);
|
|
441
|
+
expect(log.drawIndexedCount).toBe(1);
|
|
442
|
+
expect(log.encoderFinishCount).toBe(1); // one typed graph command encoder
|
|
443
|
+
expect(log.queueSubmitCount).toBe(1); // one submission for the frame graph
|
|
439
444
|
// Three BindGroups recorded per entity (view / material / mesh-array).
|
|
440
445
|
expect(log.setBindGroupCount).toBeGreaterThanOrEqual(3);
|
|
441
|
-
}
|
|
446
|
+
});
|
|
442
447
|
|
|
443
448
|
it('AC-09: RenderSystem is NOT registered as an ECS schedule system', async () => {
|
|
444
449
|
const { createRenderer } = await setupWebGPU();
|
|
@@ -448,18 +453,18 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
448
453
|
{},
|
|
449
454
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
450
455
|
);
|
|
451
|
-
await renderer.ready;
|
|
452
456
|
const { World } = await importEcs();
|
|
453
457
|
const world = new World();
|
|
454
458
|
// RenderSystem must NOT be auto-attached: world.update(1 / 60).unwrap() does not run
|
|
455
459
|
// it (engine internal phase, plan-strategy D-S2).
|
|
456
460
|
expect(world.inspect().systemCount).toBe(0);
|
|
457
461
|
expect(world.inspect().systemCount).toBe(0);
|
|
458
|
-
|
|
462
|
+
await renderer.dispose();
|
|
463
|
+
});
|
|
459
464
|
});
|
|
460
465
|
|
|
461
466
|
describe('RenderSystem error tier table (D-S4..D-S8)', () => {
|
|
462
|
-
it('case A: entity missing Transform / MeshRenderer uses defaults; does NOT fire
|
|
467
|
+
it('case A: entity missing Transform / MeshRenderer uses defaults; does NOT fire an error event', async () => {
|
|
463
468
|
const { createRenderer } = await setupWebGPU();
|
|
464
469
|
const canvas = makeMockCanvas({ webgl2: 'context', webgpu: 'context' });
|
|
465
470
|
const renderer = await createRenderer(
|
|
@@ -467,7 +472,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
467
472
|
{},
|
|
468
473
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
469
474
|
);
|
|
470
|
-
await renderer.ready;
|
|
471
475
|
const { World } = await importEcs();
|
|
472
476
|
const C = await importComponents();
|
|
473
477
|
const world = new World();
|
|
@@ -494,12 +498,8 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
494
498
|
world.spawn({ component: C.MeshFilter, data: { assetHandle: C.HANDLE_CUBE } });
|
|
495
499
|
|
|
496
500
|
const errors: { code: string }[] = [];
|
|
497
|
-
renderer
|
|
498
|
-
|
|
499
|
-
throw new Error('World attachment failed');
|
|
500
|
-
}
|
|
501
|
-
(world as WorldType).update().unwrap();
|
|
502
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
501
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
502
|
+
drawPublished(renderer, world as WorldType);
|
|
503
503
|
expect(errors).toHaveLength(0);
|
|
504
504
|
});
|
|
505
505
|
|
|
@@ -518,7 +518,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
518
518
|
{},
|
|
519
519
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
520
520
|
);
|
|
521
|
-
await renderer.ready;
|
|
522
521
|
const { World } = await importEcs();
|
|
523
522
|
const C = await importComponents();
|
|
524
523
|
const world = new World();
|
|
@@ -530,12 +529,8 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
530
529
|
);
|
|
531
530
|
|
|
532
531
|
const errors: { code: string }[] = [];
|
|
533
|
-
renderer
|
|
534
|
-
|
|
535
|
-
throw new Error('World attachment failed');
|
|
536
|
-
}
|
|
537
|
-
(world as WorldType).update().unwrap();
|
|
538
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
532
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
533
|
+
drawPublished(renderer, world as WorldType);
|
|
539
534
|
|
|
540
535
|
expect(errors.some((e) => e.code === 'render-system-no-camera')).toBe(true);
|
|
541
536
|
// Clear pass executed under the synthetic camera path; the frame is
|
|
@@ -544,13 +539,13 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
544
539
|
// through the identity projection — that's an acceptable AI-user
|
|
545
540
|
// signal (something paints + diagnostic fires) over the previous
|
|
546
541
|
// "blank canvas + console error" silent skip. Assert at least one
|
|
547
|
-
// additional submit landed beyond the renderer
|
|
542
|
+
// additional submit landed beyond the renderer construction baseline
|
|
548
543
|
// (shadowFallback).
|
|
549
544
|
expect(log.queueSubmitCount).toBeGreaterThanOrEqual(2);
|
|
550
545
|
expect(log.beginRenderPassCount).toBeGreaterThanOrEqual(2);
|
|
551
546
|
});
|
|
552
547
|
|
|
553
|
-
it('case E: world has Camera + 0 renderables emits clear-pass-only frame; does NOT fire
|
|
548
|
+
it('case E: world has Camera + 0 renderables emits clear-pass-only frame; does NOT fire an error event', async () => {
|
|
554
549
|
// LO §1.1 hello-window minimum semantic: `Engine.create({ clearColor })`
|
|
555
550
|
// must paint the swap-chain even when no entity carries MeshFilter +
|
|
556
551
|
// MeshRenderer. The engine softens the empty-renderables case (Case E,
|
|
@@ -565,7 +560,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
565
560
|
{},
|
|
566
561
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
567
562
|
);
|
|
568
|
-
await renderer.ready;
|
|
569
563
|
const { World } = await importEcs();
|
|
570
564
|
const C = await importComponents();
|
|
571
565
|
const world = new World();
|
|
@@ -591,23 +585,19 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
591
585
|
);
|
|
592
586
|
|
|
593
587
|
const errors: { code: string }[] = [];
|
|
594
|
-
renderer
|
|
595
|
-
|
|
596
|
-
throw new Error('World attachment failed');
|
|
597
|
-
}
|
|
598
|
-
(world as WorldType).update().unwrap();
|
|
599
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
588
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
589
|
+
drawPublished(renderer, world as WorldType);
|
|
600
590
|
|
|
601
591
|
// Soft path: no error fired (D-Q7 mirroring; LO §1.1 minimum semantic).
|
|
602
592
|
expect(errors).toHaveLength(0);
|
|
603
593
|
// Empty geometry does not remove graph-owned shadow and output passes.
|
|
604
|
-
expect(log.beginRenderPassCount).toBe(
|
|
594
|
+
expect(log.beginRenderPassCount).toBe(12);
|
|
605
595
|
expect(log.queueSubmitCount).toBe(8); // shadow fallback + 6 cube faces + frame
|
|
606
596
|
// No geometry submitted.
|
|
607
597
|
expect(log.drawIndexedCount).toBe(0);
|
|
608
598
|
});
|
|
609
599
|
|
|
610
|
-
it('case C: world has 0 DirectionalLight renders unlit; does NOT fire
|
|
600
|
+
it('case C: world has 0 DirectionalLight renders unlit; does NOT fire an error event', async () => {
|
|
611
601
|
const { createRenderer, log } = await setupWebGPU();
|
|
612
602
|
const canvas = makeMockCanvas({ webgl2: 'context', webgpu: 'context' });
|
|
613
603
|
const renderer = await createRenderer(
|
|
@@ -615,7 +605,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
615
605
|
{},
|
|
616
606
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
617
607
|
);
|
|
618
|
-
await renderer.ready;
|
|
619
608
|
const { World } = await importEcs();
|
|
620
609
|
const C = await importComponents();
|
|
621
610
|
const world = new World();
|
|
@@ -644,16 +633,14 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
644
633
|
// No DirectionalLight.
|
|
645
634
|
|
|
646
635
|
const errors: { code: string }[] = [];
|
|
647
|
-
renderer
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
(world as WorldType)
|
|
652
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
636
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
637
|
+
drawPublished(renderer, world as WorldType);
|
|
638
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
639
|
+
Object.assign(log, makeLog());
|
|
640
|
+
drawPublished(renderer, world as WorldType);
|
|
653
641
|
|
|
654
642
|
expect(errors).toHaveLength(0);
|
|
655
|
-
|
|
656
|
-
expect(log.drawIndexedCount).toBeGreaterThanOrEqual(1);
|
|
643
|
+
expect(log.drawIndexedCount).toBe(1);
|
|
657
644
|
});
|
|
658
645
|
|
|
659
646
|
it('case D: world has N>1 Camera fires render-system-multi-camera + uses first hit', async () => {
|
|
@@ -664,7 +651,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
664
651
|
{},
|
|
665
652
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
666
653
|
);
|
|
667
|
-
await renderer.ready;
|
|
668
654
|
const { World } = await importEcs();
|
|
669
655
|
const C = await importComponents();
|
|
670
656
|
const world = new World();
|
|
@@ -709,12 +695,11 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
709
695
|
);
|
|
710
696
|
|
|
711
697
|
const errors: { code: string; hint?: string }[] = [];
|
|
712
|
-
renderer
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
(world as WorldType)
|
|
717
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
698
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
699
|
+
drawPublished(renderer, world as WorldType);
|
|
700
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
701
|
+
Object.assign(log, makeLog());
|
|
702
|
+
drawPublished(renderer, world as WorldType);
|
|
718
703
|
|
|
719
704
|
expect(errors.some((e) => e.code === 'render-system-multi-camera')).toBe(true);
|
|
720
705
|
// First archetype hit still rendered.
|
|
@@ -735,7 +720,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
735
720
|
{},
|
|
736
721
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
737
722
|
);
|
|
738
|
-
await renderer.ready;
|
|
739
723
|
const { World } = await importEcs();
|
|
740
724
|
const C = await importComponents();
|
|
741
725
|
const world = new World();
|
|
@@ -768,11 +752,10 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
768
752
|
);
|
|
769
753
|
|
|
770
754
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
(world as WorldType)
|
|
775
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
755
|
+
drawPublished(renderer, world as WorldType);
|
|
756
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
757
|
+
Object.assign(log, makeLog());
|
|
758
|
+
drawPublished(renderer, world as WorldType);
|
|
776
759
|
|
|
777
760
|
const multiLightCalls = warnSpy.mock.calls.filter(
|
|
778
761
|
(c) =>
|
|
@@ -786,7 +769,7 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
786
769
|
});
|
|
787
770
|
|
|
788
771
|
describe('RenderSystem asset-not-registered + internal exception (.detail F-3 contract)', () => {
|
|
789
|
-
it('asset-not-registered fires
|
|
772
|
+
it('asset-not-registered fires an error event with .detail = { assetHandle } and skips entity', async () => {
|
|
790
773
|
const { createRenderer, log } = await setupWebGPU();
|
|
791
774
|
const canvas = makeMockCanvas({ webgl2: 'context', webgpu: 'context' });
|
|
792
775
|
const renderer = await createRenderer(
|
|
@@ -794,7 +777,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
794
777
|
{},
|
|
795
778
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
796
779
|
);
|
|
797
|
-
await renderer.ready;
|
|
798
780
|
const { World } = await importEcs();
|
|
799
781
|
const C = await importComponents();
|
|
800
782
|
const world = new World();
|
|
@@ -822,18 +804,16 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
822
804
|
{ component: C.Transform, data: identityTransform() },
|
|
823
805
|
);
|
|
824
806
|
|
|
825
|
-
const errors:
|
|
826
|
-
renderer
|
|
827
|
-
|
|
828
|
-
throw new Error('World attachment failed');
|
|
829
|
-
}
|
|
830
|
-
(world as WorldType).update().unwrap();
|
|
831
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
807
|
+
const errors: RendererErrorObservation[] = [];
|
|
808
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
809
|
+
drawPublished(renderer, world as WorldType);
|
|
832
810
|
|
|
833
811
|
const assetErr = errors.find((e) => e.code === 'asset-not-registered');
|
|
834
812
|
expect(assetErr).toBeDefined();
|
|
835
813
|
expect(assetErr?.detail).toBeDefined();
|
|
836
|
-
expect(assetErr?.detail?.assetHandle).toBe(
|
|
814
|
+
expect((assetErr?.detail as { assetHandle?: number } | undefined)?.assetHandle).toBe(
|
|
815
|
+
BAD_HANDLE,
|
|
816
|
+
);
|
|
837
817
|
// The bad entity is skipped; no draw recorded for it (only entity).
|
|
838
818
|
expect(log.drawIndexedCount).toBe(0);
|
|
839
819
|
// Case E secondary-fix: even when every renderable fails asset
|
|
@@ -841,7 +821,7 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
841
821
|
// the cleared canvas rather than a stale frame).
|
|
842
822
|
// The invalid entity is skipped, while graph-owned attachment passes are
|
|
843
823
|
// still recorded after the seven boot fallback clears.
|
|
844
|
-
expect(log.beginRenderPassCount).toBe(
|
|
824
|
+
expect(log.beginRenderPassCount).toBe(12);
|
|
845
825
|
expect(log.queueSubmitCount).toBe(8); // shadow fallback + 6 cube faces + frame
|
|
846
826
|
});
|
|
847
827
|
|
|
@@ -883,12 +863,9 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
883
863
|
vi.stubGlobal('navigator', { ...baseNavigator, gpu: makeMockGPU(device) });
|
|
884
864
|
const engine = await importEngine();
|
|
885
865
|
const canvas = makeMockCanvas({ webgl2: 'context', webgpu: 'context' });
|
|
886
|
-
const renderer =
|
|
887
|
-
canvas,
|
|
888
|
-
|
|
889
|
-
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
890
|
-
);
|
|
891
|
-
await renderer.ready;
|
|
866
|
+
const renderer = (
|
|
867
|
+
await engine.createRenderer(canvas, {}, { shaderManifestUrl: buildManifestDataUrl() })
|
|
868
|
+
).unwrap();
|
|
892
869
|
|
|
893
870
|
const { World } = await importEcs();
|
|
894
871
|
const C = await importComponents();
|
|
@@ -916,23 +893,19 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
916
893
|
{ component: C.Transform, data: identityTransform() },
|
|
917
894
|
);
|
|
918
895
|
|
|
919
|
-
const errors:
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
}[] = [];
|
|
923
|
-
renderer.onError((e) => errors.push(e as never));
|
|
924
|
-
if (!(renderer as unknown as RendererType).attachWorld(world as WorldType).ok) {
|
|
925
|
-
throw new Error('World attachment failed');
|
|
926
|
-
}
|
|
927
|
-
(world as WorldType).update().unwrap();
|
|
928
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
896
|
+
const errors: RendererErrorObservation[] = [];
|
|
897
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
898
|
+
drawPublished(renderer, world as WorldType);
|
|
929
899
|
|
|
930
900
|
const runtimeErr = errors.find((e) => e.code === 'webgpu-runtime-error');
|
|
931
901
|
expect(runtimeErr).toBeDefined();
|
|
932
902
|
expect(runtimeErr?.detail).toBeDefined();
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
903
|
+
const runtimeDetail = runtimeErr?.detail as
|
|
904
|
+
| { error?: { code: string; message: string } }
|
|
905
|
+
| undefined;
|
|
906
|
+
expect(runtimeDetail?.error).toBeDefined();
|
|
907
|
+
expect(typeof runtimeDetail?.error?.message).toBe('string');
|
|
908
|
+
expect(runtimeDetail?.error?.message).toContain('writeBuffer');
|
|
936
909
|
});
|
|
937
910
|
});
|
|
938
911
|
|
|
@@ -1019,11 +992,10 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1019
992
|
{},
|
|
1020
993
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
1021
994
|
);
|
|
1022
|
-
await renderer.ready;
|
|
1023
995
|
const { World } = await importEcs();
|
|
1024
996
|
const C = await importComponents();
|
|
1025
997
|
const { setTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE } = await import(
|
|
1026
|
-
'
|
|
998
|
+
'../../../render/src/systems/transparent-sort-config'
|
|
1027
999
|
);
|
|
1028
1000
|
const { RenderQueue } = await import('@forgeax/engine-types');
|
|
1029
1001
|
|
|
@@ -1115,12 +1087,8 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1115
1087
|
expect(cfgRes.ok).toBe(true);
|
|
1116
1088
|
|
|
1117
1089
|
const errors: { code: string }[] = [];
|
|
1118
|
-
renderer
|
|
1119
|
-
|
|
1120
|
-
throw new Error('World attachment failed');
|
|
1121
|
-
}
|
|
1122
|
-
(world as WorldType).update().unwrap();
|
|
1123
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
1090
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
1091
|
+
drawPublished(renderer, world as WorldType);
|
|
1124
1092
|
|
|
1125
1093
|
expect(errors).toHaveLength(0);
|
|
1126
1094
|
// All 3 transparent entities are drawn.
|
|
@@ -1169,11 +1137,10 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1169
1137
|
{},
|
|
1170
1138
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
1171
1139
|
);
|
|
1172
|
-
await renderer.ready;
|
|
1173
1140
|
const { World } = await importEcs();
|
|
1174
1141
|
const C = await importComponents();
|
|
1175
1142
|
const { setTransparentSortConfig, TRANSPARENT_SORT_MODE_DISTANCE } = await import(
|
|
1176
|
-
'
|
|
1143
|
+
'../../../render/src/systems/transparent-sort-config'
|
|
1177
1144
|
);
|
|
1178
1145
|
|
|
1179
1146
|
// Register a MaterialAsset with Geometry-queue pass.
|
|
@@ -1241,12 +1208,8 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1241
1208
|
expect(cfgRes.ok).toBe(true);
|
|
1242
1209
|
|
|
1243
1210
|
const errors: { code: string }[] = [];
|
|
1244
|
-
renderer
|
|
1245
|
-
|
|
1246
|
-
throw new Error('World attachment failed');
|
|
1247
|
-
}
|
|
1248
|
-
(world as WorldType).update().unwrap();
|
|
1249
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
1211
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
1212
|
+
drawPublished(renderer, world as WorldType);
|
|
1250
1213
|
|
|
1251
1214
|
expect(errors).toHaveLength(0);
|
|
1252
1215
|
// Both opaque entities are drawn (structural).
|
|
@@ -1266,7 +1229,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1266
1229
|
{},
|
|
1267
1230
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
1268
1231
|
);
|
|
1269
|
-
await renderer.ready;
|
|
1270
1232
|
const { World } = await importEcs();
|
|
1271
1233
|
const C = await importComponents();
|
|
1272
1234
|
const { RenderQueue } = await import('@forgeax/engine-types');
|
|
@@ -1330,12 +1292,8 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1330
1292
|
);
|
|
1331
1293
|
|
|
1332
1294
|
const errors: { code: string }[] = [];
|
|
1333
|
-
renderer
|
|
1334
|
-
|
|
1335
|
-
throw new Error('World attachment failed');
|
|
1336
|
-
}
|
|
1337
|
-
(world as WorldType).update().unwrap();
|
|
1338
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
1295
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
1296
|
+
drawPublished(renderer, world as WorldType);
|
|
1339
1297
|
|
|
1340
1298
|
expect(errors).toHaveLength(0);
|
|
1341
1299
|
expect(log.drawIndexedCount).toBe(1);
|
|
@@ -1356,7 +1314,6 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1356
1314
|
{},
|
|
1357
1315
|
{ shaderManifestUrl: buildManifestDataUrl() },
|
|
1358
1316
|
);
|
|
1359
|
-
await renderer.ready;
|
|
1360
1317
|
const { World } = await importEcs();
|
|
1361
1318
|
const C = await importComponents();
|
|
1362
1319
|
|
|
@@ -1396,16 +1353,14 @@ function canonicalMaterialParamSchema(identifier: string): string {
|
|
|
1396
1353
|
);
|
|
1397
1354
|
|
|
1398
1355
|
const errors: { code: string }[] = [];
|
|
1399
|
-
renderer
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
(world as WorldType)
|
|
1404
|
-
renderer.draw([world], { cameraOwner: 0, resourceOwner: 0 });
|
|
1356
|
+
subscribeRendererErrors(renderer, (e) => errors.push(e));
|
|
1357
|
+
drawPublished(renderer, world as WorldType);
|
|
1358
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1359
|
+
Object.assign(log, makeLog());
|
|
1360
|
+
drawPublished(renderer, world as WorldType);
|
|
1405
1361
|
|
|
1406
1362
|
expect(errors).toHaveLength(0);
|
|
1407
|
-
|
|
1408
|
-
expect(log.drawIndexedCount).toBeGreaterThanOrEqual(1);
|
|
1363
|
+
expect(log.drawIndexedCount).toBe(1);
|
|
1409
1364
|
|
|
1410
1365
|
// Without stencilReference, the draw loop should call
|
|
1411
1366
|
// setStencilReference(0) (harmless WebGPU default) or not call it at
|
|
@@ -1550,7 +1505,7 @@ describe('RenderSystem Skylight record phase (AC-11)', () => {
|
|
|
1550
1505
|
// brdfLutBakeCount === 1 after the first frame that has Skylight.
|
|
1551
1506
|
//
|
|
1552
1507
|
// When t26 lands:
|
|
1553
|
-
// const cache = getOrCreateIblCache(
|
|
1508
|
+
// const cache = getOrCreateIblCache(deviceScope);
|
|
1554
1509
|
// expect(cache.irradianceBakeCount).toBe(1);
|
|
1555
1510
|
// expect(cache.prefilterBakeCount).toBe(1);
|
|
1556
1511
|
// expect(cache.brdfLutBakeCount).toBe(1);
|
|
@@ -1576,3 +1531,150 @@ describe('RenderSystem Skylight extract + record phase contract (plan-strategy D
|
|
|
1576
1531
|
expect(noSeparateSystem).toBe(true);
|
|
1577
1532
|
});
|
|
1578
1533
|
});
|
|
1534
|
+
|
|
1535
|
+
// ─── from render-system-stride.test.ts ───
|
|
1536
|
+
{
|
|
1537
|
+
// w14 - RenderSystem extract entry stride defensive test (M3, AC-06).
|
|
1538
|
+
//
|
|
1539
|
+
// Locks the AC-06 invariant: when an entity carries an `Instances` component
|
|
1540
|
+
// whose `transforms` array<f32> snapshot has a length that is NOT a multiple
|
|
1541
|
+
// of 16, the RenderSystem extract stage MUST emit a structured `EcsError`
|
|
1542
|
+
// with `code: 'instance-transforms-stride-mismatch'` BEFORE the GPU upload
|
|
1543
|
+
// path is reached. The error carries a discriminated `.detail` per
|
|
1544
|
+
// `EcsErrorDetail`:
|
|
1545
|
+
//
|
|
1546
|
+
// detail = { actualLength: number, expectedStride: 16 }
|
|
1547
|
+
//
|
|
1548
|
+
// Coverage matrix:
|
|
1549
|
+
// (a) length === 16 -> pass; no error fires; renderable lands.
|
|
1550
|
+
// (b) length === 32 -> pass; no error fires; renderable lands.
|
|
1551
|
+
// (c) length === 15 -> fail; structured error fires with detail; no
|
|
1552
|
+
// renderable lands.
|
|
1553
|
+
// (d) length === 17 -> fail; structured error fires with detail; no
|
|
1554
|
+
// renderable lands.
|
|
1555
|
+
//
|
|
1556
|
+
// The defensive lives in `packages/runtime/src/render-system-extract.ts`
|
|
1557
|
+
// inside the `Instances` archetype loop, immediately after the
|
|
1558
|
+
// `world.get(entity, Instances)` snapshot is extracted but BEFORE any
|
|
1559
|
+
// per-element copy / GPU upload. Violation routes through Layer-3
|
|
1560
|
+
// `World._errorHandler` (set via `world.setErrorHandler`); the renderable
|
|
1561
|
+
// MUST NOT be pushed (fail-fast halts the per-entity branch).
|
|
1562
|
+
|
|
1563
|
+
interface CollectedError {
|
|
1564
|
+
readonly code: string;
|
|
1565
|
+
readonly detail: unknown;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
function makeIdentityTransform(): {
|
|
1569
|
+
pos: number[];
|
|
1570
|
+
quat: number[];
|
|
1571
|
+
scale: number[];
|
|
1572
|
+
} {
|
|
1573
|
+
return { pos: [0, 0, 0], quat: [0, 0, 0, 1], scale: [1, 1, 1] };
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
function makeWorld(): { world: World; collected: CollectedError[] } {
|
|
1577
|
+
const collected: CollectedError[] = [];
|
|
1578
|
+
const world = new World();
|
|
1579
|
+
vi.spyOn(console, 'error').mockImplementation((...args: unknown[]) => {
|
|
1580
|
+
const e = args[args.length - 1] as { code?: string; detail?: unknown };
|
|
1581
|
+
if (e.code !== undefined) collected.push({ code: e.code, detail: e.detail });
|
|
1582
|
+
});
|
|
1583
|
+
// Camera + light so extractFrame's pre-loop short-circuit does not skip
|
|
1584
|
+
// the Instances archetype walk.
|
|
1585
|
+
world
|
|
1586
|
+
.spawn({
|
|
1587
|
+
component: Camera,
|
|
1588
|
+
data: {
|
|
1589
|
+
fov: 1.0,
|
|
1590
|
+
aspect: 1.0,
|
|
1591
|
+
near: 0.1,
|
|
1592
|
+
far: 100.0,
|
|
1593
|
+
projection: 0,
|
|
1594
|
+
left: -1,
|
|
1595
|
+
right: 1,
|
|
1596
|
+
bottom: -1,
|
|
1597
|
+
top: 1,
|
|
1598
|
+
},
|
|
1599
|
+
})
|
|
1600
|
+
.unwrap();
|
|
1601
|
+
world
|
|
1602
|
+
.spawn({
|
|
1603
|
+
component: DirectionalLight,
|
|
1604
|
+
data: {
|
|
1605
|
+
direction: [0, -1, 0],
|
|
1606
|
+
color: [1, 1, 1],
|
|
1607
|
+
intensity: 1,
|
|
1608
|
+
},
|
|
1609
|
+
})
|
|
1610
|
+
.unwrap();
|
|
1611
|
+
return { world, collected };
|
|
1612
|
+
}
|
|
1613
|
+
|
|
1614
|
+
function spawnInstancedEntity(world: World, transforms: Float32Array): void {
|
|
1615
|
+
world
|
|
1616
|
+
.spawn(
|
|
1617
|
+
{ component: Transform, data: makeIdentityTransform() },
|
|
1618
|
+
{
|
|
1619
|
+
component: MeshFilter,
|
|
1620
|
+
data: { assetHandle: HANDLE_CUBE },
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
component: MeshRenderer,
|
|
1624
|
+
data: {} as never,
|
|
1625
|
+
},
|
|
1626
|
+
{ component: Instances, data: { transforms } },
|
|
1627
|
+
)
|
|
1628
|
+
.unwrap();
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
describe('render-system-extract stride defensive (w14, AC-06)', () => {
|
|
1632
|
+
it('(a) length === 16: no error; renderable lands', () => {
|
|
1633
|
+
const { world, collected } = makeWorld();
|
|
1634
|
+
const transforms = new Float32Array(16);
|
|
1635
|
+
spawnInstancedEntity(world, transforms);
|
|
1636
|
+
const frame = extractFrame(world, prepareExtractContext(world));
|
|
1637
|
+
expect(collected.filter((c) => c.code === 'instance-transforms-stride-mismatch').length).toBe(
|
|
1638
|
+
0,
|
|
1639
|
+
);
|
|
1640
|
+
expect(frame.renderables.length).toBe(1);
|
|
1641
|
+
});
|
|
1642
|
+
|
|
1643
|
+
it('(b) length === 32: no error; renderable lands', () => {
|
|
1644
|
+
const { world, collected } = makeWorld();
|
|
1645
|
+
const transforms = new Float32Array(32);
|
|
1646
|
+
spawnInstancedEntity(world, transforms);
|
|
1647
|
+
const frame = extractFrame(world, prepareExtractContext(world));
|
|
1648
|
+
expect(collected.filter((c) => c.code === 'instance-transforms-stride-mismatch').length).toBe(
|
|
1649
|
+
0,
|
|
1650
|
+
);
|
|
1651
|
+
expect(frame.renderables.length).toBe(1);
|
|
1652
|
+
});
|
|
1653
|
+
|
|
1654
|
+
it('(c) length === 15: structured error fires; detail.actualLength === 15; expectedStride === 16; no renderable', () => {
|
|
1655
|
+
const { world, collected } = makeWorld();
|
|
1656
|
+
const transforms = new Float32Array(15);
|
|
1657
|
+
spawnInstancedEntity(world, transforms);
|
|
1658
|
+
const frame = extractFrame(world, prepareExtractContext(world));
|
|
1659
|
+
const stride = collected.filter((c) => c.code === 'instance-transforms-stride-mismatch');
|
|
1660
|
+
expect(stride.length).toBe(1);
|
|
1661
|
+
const detail = stride[0]?.detail as { actualLength: number; expectedStride: 16 };
|
|
1662
|
+
expect(detail.actualLength).toBe(15);
|
|
1663
|
+
expect(detail.expectedStride).toBe(16);
|
|
1664
|
+
expect(frame.renderables.length).toBe(0);
|
|
1665
|
+
});
|
|
1666
|
+
|
|
1667
|
+
it('(d) length === 17: structured error fires; detail.actualLength === 17; expectedStride === 16; no renderable', () => {
|
|
1668
|
+
const { world, collected } = makeWorld();
|
|
1669
|
+
const transforms = new Float32Array(17);
|
|
1670
|
+
spawnInstancedEntity(world, transforms);
|
|
1671
|
+
const frame = extractFrame(world, prepareExtractContext(world));
|
|
1672
|
+
const stride = collected.filter((c) => c.code === 'instance-transforms-stride-mismatch');
|
|
1673
|
+
expect(stride.length).toBe(1);
|
|
1674
|
+
const detail = stride[0]?.detail as { actualLength: number; expectedStride: 16 };
|
|
1675
|
+
expect(detail.actualLength).toBe(17);
|
|
1676
|
+
expect(detail.expectedStride).toBe(16);
|
|
1677
|
+
expect(frame.renderables.length).toBe(0);
|
|
1678
|
+
});
|
|
1679
|
+
});
|
|
1680
|
+
}
|