@forgeax/engine-assets-runtime 0.0.0-dev.8d955ade1c79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +491 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/aabb.unit.test.d.ts +2 -0
- package/dist/__tests__/aabb.unit.test.d.ts.map +1 -0
- package/dist/__tests__/artifact-integrity.unit.test.d.ts +2 -0
- package/dist/__tests__/artifact-integrity.unit.test.d.ts.map +1 -0
- package/dist/__tests__/artifact-io.unit.test.d.ts +2 -0
- package/dist/__tests__/artifact-io.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts +2 -0
- package/dist/__tests__/asset-evidence-sdk.integration.test.d.ts.map +1 -0
- package/dist/__tests__/asset-evidence.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-evidence.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-kind.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-kind.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.integration.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-catalog-reconcile.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-registry-catalog.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry-catalog.unit.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.unit.test.d.ts +2 -0
- package/dist/__tests__/asset-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts +2 -0
- package/dist/__tests__/asset-runtime-error-code-owner.test-d.d.ts.map +1 -0
- package/dist/__tests__/catalog-replica.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-replica.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-source-v2.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-source-v2.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-source.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-source.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-subscription-order.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-subscription-order.unit.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-subscription.unit.test.d.ts +2 -0
- package/dist/__tests__/catalog-subscription.unit.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes-pass-through.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes.browser.test.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes.browser.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes.test-d.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes.test-d.d.ts.map +1 -0
- package/dist/__tests__/decode-image-bytes.test.d.ts +2 -0
- package/dist/__tests__/decode-image-bytes.test.d.ts.map +1 -0
- package/dist/__tests__/decode-image-mime-owner.test.d.ts +2 -0
- package/dist/__tests__/decode-image-mime-owner.test.d.ts.map +1 -0
- 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-asset.unit.test.d.ts +2 -0
- package/dist/__tests__/errors-asset.unit.test.d.ts.map +1 -0
- package/dist/__tests__/inline-pack-loaders.unit.test.d.ts +2 -0
- package/dist/__tests__/inline-pack-loaders.unit.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-context.unit.test.d.ts +2 -0
- package/dist/__tests__/instantiate-context.unit.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts +2 -0
- package/dist/__tests__/instantiate-publication-fence.unit.test.d.ts.map +1 -0
- package/dist/__tests__/instantiate.unit.test.d.ts +2 -0
- package/dist/__tests__/instantiate.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-input-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/loader-input-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/loader-registry.unit.test.d.ts +2 -0
- package/dist/__tests__/loader-registry.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts +2 -0
- package/dist/__tests__/material-dependency-invalidation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-generation-cache.unit.test.d.ts +2 -0
- package/dist/__tests__/material-generation-cache.unit.test.d.ts.map +1 -0
- package/dist/__tests__/material-load-consumer.test-d.d.ts +2 -0
- package/dist/__tests__/material-load-consumer.test-d.d.ts.map +1 -0
- package/dist/__tests__/material-ready.integration.test.d.ts +2 -0
- package/dist/__tests__/material-ready.integration.test.d.ts.map +1 -0
- package/dist/__tests__/material-stale-generation.unit.test.d.ts +2 -0
- package/dist/__tests__/material-stale-generation.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin-morph-v3.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin-morph-v3.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-bin.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-bin.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mipmap-generator.unit.test.d.ts +2 -0
- package/dist/__tests__/mipmap-generator.unit.test.d.ts.map +1 -0
- package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts +2 -0
- package/dist/__tests__/pack-artifact-transcode-model-owner.test.d.ts.map +1 -0
- package/dist/__tests__/pack-basis-load.integration.test.d.ts +2 -0
- package/dist/__tests__/pack-basis-load.integration.test.d.ts.map +1 -0
- package/dist/__tests__/payload-validate.unit.test.d.ts +2 -0
- package/dist/__tests__/payload-validate.unit.test.d.ts.map +1 -0
- package/dist/__tests__/plugin.test.d.ts +2 -0
- package/dist/__tests__/plugin.test.d.ts.map +1 -0
- package/dist/__tests__/registry-concurrency.bench.test.d.ts +2 -0
- package/dist/__tests__/registry-concurrency.bench.test.d.ts.map +1 -0
- package/dist/__tests__/registry-failure-retry.integration.test.d.ts +2 -0
- package/dist/__tests__/registry-failure-retry.integration.test.d.ts.map +1 -0
- package/dist/__tests__/registry-load-graph.integration.test.d.ts +2 -0
- package/dist/__tests__/registry-load-graph.integration.test.d.ts.map +1 -0
- package/dist/__tests__/registry-load-state.unit.test.d.ts +2 -0
- package/dist/__tests__/registry-load-state.unit.test.d.ts.map +1 -0
- package/dist/__tests__/registry-package-cache.unit.test.d.ts +2 -0
- package/dist/__tests__/registry-package-cache.unit.test.d.ts.map +1 -0
- package/dist/__tests__/registry-public-ready.unit.test.d.ts +2 -0
- package/dist/__tests__/registry-public-ready.unit.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__/scene-handle-fields.unit.test.d.ts +2 -0
- package/dist/__tests__/scene-handle-fields.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-payload.unit.test.d.ts +2 -0
- package/dist/__tests__/scene-payload.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scene-publication-fence.test.d.ts +2 -0
- package/dist/__tests__/scene-publication-fence.test.d.ts.map +1 -0
- package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-public-surface.test-d.d.ts.map +1 -0
- package/dist/__tests__/static-rig.integration.test.d.ts +2 -0
- package/dist/__tests__/static-rig.integration.test.d.ts.map +1 -0
- package/dist/__tests__/validate-material.unit.test.d.ts +2 -0
- package/dist/__tests__/validate-material.unit.test.d.ts.map +1 -0
- package/dist/__tests__/video-pack-loader.integration.test.d.ts +2 -0
- package/dist/__tests__/video-pack-loader.integration.test.d.ts.map +1 -0
- package/dist/aabb.d.ts +3 -0
- package/dist/aabb.d.ts.map +1 -0
- package/dist/asset-kind.d.ts +4 -0
- package/dist/asset-kind.d.ts.map +1 -0
- package/dist/asset-registry.d.ts +554 -0
- package/dist/asset-registry.d.ts.map +1 -0
- package/dist/builtin-asset-registry.d.ts +22 -0
- package/dist/builtin-asset-registry.d.ts.map +1 -0
- package/dist/catalog-source.d.ts +24 -0
- package/dist/catalog-source.d.ts.map +1 -0
- package/dist/decode-image-bytes.d.ts +57 -0
- package/dist/decode-image-bytes.d.ts.map +1 -0
- package/dist/dynamic-texture-store.d.ts +89 -0
- package/dist/dynamic-texture-store.d.ts.map +1 -0
- package/dist/errors/asset.d.ts +201 -0
- package/dist/errors/asset.d.ts.map +1 -0
- package/dist/handles.d.ts +143 -0
- package/dist/handles.d.ts.map +1 -0
- package/dist/image-error.d.ts +6 -0
- package/dist/image-error.d.ts.map +1 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +8359 -0
- package/dist/index.mjs.map +1 -0
- package/dist/internal/artifact-cache.d.ts +17 -0
- package/dist/internal/artifact-cache.d.ts.map +1 -0
- package/dist/internal/asset-graph.d.ts +70 -0
- package/dist/internal/asset-graph.d.ts.map +1 -0
- package/dist/internal/catalog-session.d.ts +60 -0
- package/dist/internal/catalog-session.d.ts.map +1 -0
- package/dist/internal/decoder-registry.d.ts +19 -0
- package/dist/internal/decoder-registry.d.ts.map +1 -0
- package/dist/internal/immutable-payload.d.ts +9 -0
- package/dist/internal/immutable-payload.d.ts.map +1 -0
- package/dist/internal/load-asset.d.ts +31 -0
- package/dist/internal/load-asset.d.ts.map +1 -0
- package/dist/internal/pack-reader.d.ts +18 -0
- package/dist/internal/pack-reader.d.ts.map +1 -0
- package/dist/internal/validate-runtime-row.d.ts +7 -0
- package/dist/internal/validate-runtime-row.d.ts.map +1 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.mjs +329 -0
- package/dist/internal.mjs.map +1 -0
- package/dist/loader-registry.d.ts +63 -0
- package/dist/loader-registry.d.ts.map +1 -0
- package/dist/loaders/inline-pack.d.ts +72 -0
- package/dist/loaders/inline-pack.d.ts.map +1 -0
- package/dist/loaders/mesh-bin.d.ts +21 -0
- package/dist/loaders/mesh-bin.d.ts.map +1 -0
- package/dist/loaders/pack-artifact.d.ts +20 -0
- package/dist/loaders/pack-artifact.d.ts.map +1 -0
- package/dist/material/dependency-graph.d.ts +9 -0
- package/dist/material/dependency-graph.d.ts.map +1 -0
- package/dist/material/generation-cache.d.ts +24 -0
- package/dist/material/generation-cache.d.ts.map +1 -0
- package/dist/material/inspection.d.ts +24 -0
- package/dist/material/inspection.d.ts.map +1 -0
- package/dist/material/loader.d.ts +59 -0
- package/dist/material/loader.d.ts.map +1 -0
- package/dist/material/runtime-shader.d.ts +14 -0
- package/dist/material/runtime-shader.d.ts.map +1 -0
- package/dist/mesh-bin.d.ts +3 -0
- package/dist/mesh-bin.d.ts.map +1 -0
- package/dist/mipmap-generator.d.ts +132 -0
- package/dist/mipmap-generator.d.ts.map +1 -0
- package/dist/payload-validate.d.ts +60 -0
- package/dist/payload-validate.d.ts.map +1 -0
- package/dist/plugin.d.ts +16 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/registry/artifact-io.d.ts +16 -0
- package/dist/registry/artifact-io.d.ts.map +1 -0
- package/dist/registry/asset-evidence.d.ts +13 -0
- package/dist/registry/asset-evidence.d.ts.map +1 -0
- package/dist/registry/catalog-state.d.ts +47 -0
- package/dist/registry/catalog-state.d.ts.map +1 -0
- package/dist/registry/catalog.d.ts +48 -0
- package/dist/registry/catalog.d.ts.map +1 -0
- package/dist/registry/instantiate.d.ts +153 -0
- package/dist/registry/instantiate.d.ts.map +1 -0
- package/dist/registry/load-by-guid.d.ts +247 -0
- package/dist/registry/load-by-guid.d.ts.map +1 -0
- package/dist/registry/load-state.d.ts +26 -0
- package/dist/registry/load-state.d.ts.map +1 -0
- package/dist/registry/runtime-projection.d.ts +16 -0
- package/dist/registry/runtime-projection.d.ts.map +1 -0
- package/dist/registry/scene-publication-fence.d.ts +38 -0
- package/dist/registry/scene-publication-fence.d.ts.map +1 -0
- package/dist/registry/validate-material.d.ts +77 -0
- package/dist/registry/validate-material.d.ts.map +1 -0
- package/dist/resolve-asset-handle.d.ts +43 -0
- package/dist/resolve-asset-handle.d.ts.map +1 -0
- package/dist/resolve-tileset-runtime.d.ts +23 -0
- package/dist/resolve-tileset-runtime.d.ts.map +1 -0
- package/dist/scene-handle-fields.d.ts +88 -0
- package/dist/scene-handle-fields.d.ts.map +1 -0
- package/dist/scene-payload.d.ts +15 -0
- package/dist/scene-payload.d.ts.map +1 -0
- package/dist/wire-default-loaders.d.ts +29 -0
- package/dist/wire-default-loaders.d.ts.map +1 -0
- package/package.json +76 -0
- package/src/__tests__/aabb.unit.test.ts +97 -0
- package/src/__tests__/artifact-integrity.unit.test.ts +99 -0
- package/src/__tests__/artifact-io.unit.test.ts +127 -0
- package/src/__tests__/asset-evidence-sdk.integration.test.ts +32 -0
- package/src/__tests__/asset-evidence.unit.test.ts +32 -0
- package/src/__tests__/asset-kind.unit.test.ts +14 -0
- package/src/__tests__/asset-registry-catalog-reconcile.integration.test.ts +74 -0
- package/src/__tests__/asset-registry-catalog-reconcile.unit.test.ts +89 -0
- package/src/__tests__/asset-registry-catalog.unit.test.ts +170 -0
- package/src/__tests__/asset-registry.pack-cache.test.ts +96 -0
- package/src/__tests__/asset-registry.unit.test.ts +511 -0
- package/src/__tests__/asset-runtime-error-code-owner.test-d.ts +63 -0
- package/src/__tests__/catalog-replica.unit.test.ts +196 -0
- package/src/__tests__/catalog-source-v2.unit.test.ts +158 -0
- package/src/__tests__/catalog-source.unit.test.ts +126 -0
- package/src/__tests__/catalog-subscription-order.unit.test.ts +65 -0
- package/src/__tests__/catalog-subscription.unit.test.ts +28 -0
- package/src/__tests__/decode-image-bytes-pass-through.test.ts +34 -0
- package/src/__tests__/decode-image-bytes.browser.test.ts +102 -0
- package/src/__tests__/decode-image-bytes.test-d.ts +108 -0
- package/src/__tests__/decode-image-bytes.test.ts +90 -0
- package/src/__tests__/decode-image-mime-owner.test.ts +38 -0
- package/src/__tests__/dynamic-texture-store.unit.test.ts +115 -0
- package/src/__tests__/errors-asset.unit.test.ts +92 -0
- package/src/__tests__/inline-pack-loaders.unit.test.ts +548 -0
- package/src/__tests__/instantiate-context.unit.test.ts +65 -0
- package/src/__tests__/instantiate-publication-fence.unit.test.ts +158 -0
- package/src/__tests__/instantiate.unit.test.ts +684 -0
- package/src/__tests__/loader-input-contract.unit.test.ts +89 -0
- package/src/__tests__/loader-registry.unit.test.ts +101 -0
- package/src/__tests__/material-dependency-invalidation.unit.test.ts +14 -0
- package/src/__tests__/material-generation-cache.unit.test.ts +46 -0
- package/src/__tests__/material-load-consumer.test-d.ts +42 -0
- package/src/__tests__/material-ready.integration.test.ts +508 -0
- package/src/__tests__/material-stale-generation.unit.test.ts +147 -0
- package/src/__tests__/mesh-bin-morph-v3.test.ts +22 -0
- package/src/__tests__/mesh-bin.unit.test.ts +152 -0
- package/src/__tests__/mipmap-generator.unit.test.ts +202 -0
- package/src/__tests__/pack-artifact-transcode-model-owner.test.ts +32 -0
- package/src/__tests__/pack-basis-load.integration.test.ts +168 -0
- package/src/__tests__/payload-validate.unit.test.ts +285 -0
- package/src/__tests__/plugin.test.ts +55 -0
- package/src/__tests__/registry-concurrency.bench.test.ts +40 -0
- package/src/__tests__/registry-failure-retry.integration.test.ts +69 -0
- package/src/__tests__/registry-load-graph.integration.test.ts +246 -0
- package/src/__tests__/registry-load-state.unit.test.ts +35 -0
- package/src/__tests__/registry-package-cache.unit.test.ts +53 -0
- package/src/__tests__/registry-public-ready.unit.test.ts +38 -0
- package/src/__tests__/resolve-asset-handle.unit.test.ts +238 -0
- package/src/__tests__/scene-handle-fields.unit.test.ts +129 -0
- package/src/__tests__/scene-payload.unit.test.ts +151 -0
- package/src/__tests__/scene-publication-fence.test.ts +129 -0
- package/src/__tests__/scriptable-pack-public-surface.test-d.ts +27 -0
- package/src/__tests__/static-rig.integration.test.ts +8 -0
- package/src/__tests__/validate-material.unit.test.ts +359 -0
- package/src/__tests__/video-pack-loader.integration.test.ts +83 -0
- package/src/aabb.ts +107 -0
- package/src/asset-kind.ts +6 -0
- package/src/asset-registry.ts +2045 -0
- package/src/builtin-asset-registry.ts +164 -0
- package/src/catalog-source.ts +89 -0
- package/src/decode-image-bytes.ts +126 -0
- package/src/dynamic-texture-store.ts +234 -0
- package/src/errors/asset.ts +347 -0
- package/src/handles.ts +186 -0
- package/src/image-error.ts +45 -0
- package/src/index.ts +189 -0
- package/src/internal/artifact-cache.ts +65 -0
- package/src/internal/asset-graph.ts +420 -0
- package/src/internal/catalog-session.ts +345 -0
- package/src/internal/decoder-registry.ts +175 -0
- package/src/internal/immutable-payload.ts +20 -0
- package/src/internal/load-asset.ts +254 -0
- package/src/internal/pack-reader.ts +183 -0
- package/src/internal/validate-runtime-row.ts +51 -0
- package/src/internal.ts +6 -0
- package/src/loader-registry.ts +157 -0
- package/src/loaders/inline-pack.ts +837 -0
- package/src/loaders/mesh-bin.ts +304 -0
- package/src/loaders/pack-artifact.ts +665 -0
- package/src/material/dependency-graph.ts +46 -0
- package/src/material/generation-cache.ts +177 -0
- package/src/material/inspection.ts +46 -0
- package/src/material/loader.ts +326 -0
- package/src/material/runtime-shader.ts +133 -0
- package/src/mesh-bin.ts +5 -0
- package/src/mipmap-generator.ts +450 -0
- package/src/payload-validate.ts +573 -0
- package/src/plugin.ts +48 -0
- package/src/registry/artifact-io.ts +259 -0
- package/src/registry/asset-evidence.ts +51 -0
- package/src/registry/catalog-state.ts +409 -0
- package/src/registry/catalog.ts +369 -0
- package/src/registry/instantiate.ts +1056 -0
- package/src/registry/load-by-guid.ts +1657 -0
- package/src/registry/load-state.ts +115 -0
- package/src/registry/runtime-projection.ts +63 -0
- package/src/registry/scene-publication-fence.ts +256 -0
- package/src/registry/validate-material.ts +385 -0
- package/src/resolve-asset-handle.ts +147 -0
- package/src/resolve-tileset-runtime.ts +72 -0
- package/src/scene-handle-fields.ts +221 -0
- package/src/scene-payload.ts +207 -0
- package/src/wire-default-loaders.ts +79 -0
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
// @forgeax/engine-assets-runtime -- asset cluster error classes.
|
|
2
|
+
//
|
|
3
|
+
// feat-20260704-runtime-tier1-decomposition M2 / w8 (D-3): asset-resolution
|
|
4
|
+
// cluster -- material parent-chain resolve, mesh-SSBO grow ceiling, and
|
|
5
|
+
// scene-collect GUID / forest-closure fail-fast errors. Class names, .code
|
|
6
|
+
// literals, and .detail shapes preserved byte-for-byte (OOS-4).
|
|
7
|
+
//
|
|
8
|
+
// The cluster union type is named AssetRuntimeError / AssetRuntimeErrorCode
|
|
9
|
+
// (not AssetError / AssetErrorCode) because @forgeax/engine-types already owns
|
|
10
|
+
// the AssetError class + AssetErrorCode union (asset-system-v1); D-8 grep
|
|
11
|
+
// uniqueness forbids the collision.
|
|
12
|
+
|
|
13
|
+
import type { MeshBinHeaderV4 } from '@forgeax/engine-pack';
|
|
14
|
+
import {
|
|
15
|
+
AssetError,
|
|
16
|
+
type AssetErrorDetail,
|
|
17
|
+
type AssetMeshBinContractFacts,
|
|
18
|
+
type AssetMeshBinContractViolationReason,
|
|
19
|
+
} from '@forgeax/engine-types';
|
|
20
|
+
|
|
21
|
+
export class MeshBinAssetError extends AssetError {
|
|
22
|
+
readonly subject = 'mesh-bin' as const;
|
|
23
|
+
readonly sourceKey: string;
|
|
24
|
+
readonly actual: string;
|
|
25
|
+
readonly recovery = 're-cook the source with its Meta sidecar through the build-time importer';
|
|
26
|
+
|
|
27
|
+
constructor(args: {
|
|
28
|
+
readonly sourceKey: string;
|
|
29
|
+
readonly expected: string;
|
|
30
|
+
readonly actual: string;
|
|
31
|
+
readonly header?: Partial<MeshBinHeaderV4> & { readonly byteLength?: number };
|
|
32
|
+
readonly reason?: AssetMeshBinContractViolationReason;
|
|
33
|
+
readonly expectedFacts?: AssetMeshBinContractFacts;
|
|
34
|
+
readonly actualFacts?: AssetMeshBinContractFacts;
|
|
35
|
+
}) {
|
|
36
|
+
const expectedFacts: AssetMeshBinContractFacts = args.expectedFacts ?? {
|
|
37
|
+
version: 4,
|
|
38
|
+
projectionVersion: 1,
|
|
39
|
+
};
|
|
40
|
+
const actualFacts: AssetMeshBinContractFacts = {
|
|
41
|
+
...(args.header ?? {}),
|
|
42
|
+
...(args.actualFacts ?? {}),
|
|
43
|
+
};
|
|
44
|
+
const detail: AssetErrorDetail = {
|
|
45
|
+
code: 'mesh-bin-contract-violation',
|
|
46
|
+
sourceKey: args.sourceKey,
|
|
47
|
+
reason: args.reason ?? 'header-invalid',
|
|
48
|
+
expected: expectedFacts,
|
|
49
|
+
actual: actualFacts,
|
|
50
|
+
};
|
|
51
|
+
super({
|
|
52
|
+
code: 'mesh-bin-contract-violation',
|
|
53
|
+
expected: args.expected,
|
|
54
|
+
hint: 're-cook the source with its Meta sidecar through the build-time importer',
|
|
55
|
+
detail,
|
|
56
|
+
});
|
|
57
|
+
this.sourceKey = args.sourceKey;
|
|
58
|
+
this.actual = args.actual;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ── MaterialResolvedEmptyPassesError ──────────────────────────────────────
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Detail for `RuntimeErrorCode 'material-resolved-empty-passes'`.
|
|
66
|
+
*
|
|
67
|
+
* Emitted at material parent chain walk time when the resolved passes list
|
|
68
|
+
* is empty. Two reasons: `'missing-parent'` (a parent handle is not
|
|
69
|
+
* registered) and `'no-pass-in-chain'` (the entire parent chain has no
|
|
70
|
+
* pass declarations). AI users switch on `.detail.reason` to surface the
|
|
71
|
+
* right recovery guidance.
|
|
72
|
+
*
|
|
73
|
+
* plan-strategy D-2/D-3: empty-passes is a runtime-layer error
|
|
74
|
+
* (RuntimeErrorCode, not AssetErrorCode).
|
|
75
|
+
*/
|
|
76
|
+
export interface MaterialResolvedEmptyPassesDetail {
|
|
77
|
+
/** GUID of the material whose resolve produced empty passes. */
|
|
78
|
+
readonly materialGuid: string;
|
|
79
|
+
/** Root cause of the empty passes: missing parent vs entire chain has no passes. */
|
|
80
|
+
readonly reason: 'missing-parent' | 'no-pass-in-chain';
|
|
81
|
+
/** The raw numeric handle id of the unregistered parent. Only populated when reason='missing-parent'. */
|
|
82
|
+
readonly missingParentHandle?: number;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Structured error for material parent chain resolve yielding zero passes.
|
|
87
|
+
*
|
|
88
|
+
* Emitted by `AssetRegistry.passesOf` when the parent chain walk produces
|
|
89
|
+
* an empty passes list (AC-09, D-3 two-reason). Four-field surface:
|
|
90
|
+
* - `.code = 'material-resolved-empty-passes'` (closed RuntimeErrorCode)
|
|
91
|
+
* - `.expected` — expected-state description
|
|
92
|
+
* - `.hint` — actionable recovery guidance (differs per reason)
|
|
93
|
+
* - `.detail = { materialGuid, reason, missingParentHandle? }`
|
|
94
|
+
*/
|
|
95
|
+
export class MaterialResolvedEmptyPassesError extends Error {
|
|
96
|
+
readonly code = 'material-resolved-empty-passes' as const;
|
|
97
|
+
readonly expected: string;
|
|
98
|
+
readonly hint: string;
|
|
99
|
+
readonly detail: MaterialResolvedEmptyPassesDetail;
|
|
100
|
+
|
|
101
|
+
constructor(
|
|
102
|
+
materialGuid: string,
|
|
103
|
+
reason: 'missing-parent' | 'no-pass-in-chain',
|
|
104
|
+
missingParentHandle?: number,
|
|
105
|
+
) {
|
|
106
|
+
const expected =
|
|
107
|
+
reason === 'missing-parent'
|
|
108
|
+
? `parent handle ${missingParentHandle} present in AssetRegistry`
|
|
109
|
+
: 'at least one material in the parent chain declares passes';
|
|
110
|
+
const hint =
|
|
111
|
+
reason === 'missing-parent'
|
|
112
|
+
? `material ${materialGuid} references parent handle ${missingParentHandle} which is not registered; inspect AssetRegistry, register the parent first, or rebuild the material chain`
|
|
113
|
+
: `material ${materialGuid} has no passes and its entire parent chain also has no pass declarations; inspect the chain, add pass declarations to one member, then rebuild`;
|
|
114
|
+
const message =
|
|
115
|
+
reason === 'missing-parent'
|
|
116
|
+
? `material ${materialGuid} parent handle ${missingParentHandle} not registered`
|
|
117
|
+
: `material ${materialGuid} parent chain resolves to zero passes`;
|
|
118
|
+
|
|
119
|
+
super(message);
|
|
120
|
+
this.name = 'MaterialResolvedEmptyPassesError';
|
|
121
|
+
this.expected = expected;
|
|
122
|
+
this.hint = hint;
|
|
123
|
+
this.detail = {
|
|
124
|
+
materialGuid,
|
|
125
|
+
reason,
|
|
126
|
+
...(reason === 'missing-parent' && missingParentHandle !== undefined
|
|
127
|
+
? { missingParentHandle }
|
|
128
|
+
: {}),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// ── MeshSsboCapacityExceededError ────────────────────────────────────────────
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Detail for `RuntimeErrorCode 'mesh-ssbo-capacity-exceeded'`.
|
|
137
|
+
*
|
|
138
|
+
* Fired by `growMeshSsbo` (createRenderer.ts grow factory) when, after
|
|
139
|
+
* attempting pow2 doubling, the resulting `slotCount` still cannot
|
|
140
|
+
* accommodate the requested `requested` slot count under the device's
|
|
141
|
+
* `maxStorageBufferBindingSize` ceiling. This is a defensive fallback —
|
|
142
|
+
* the primary path for "request past device limit" is
|
|
143
|
+
* `mesh-ssbo-ceiling-reached`. The two codes share the same detail shape so
|
|
144
|
+
* AI users handle both arms identically; the discriminant identifies which
|
|
145
|
+
* branch fired so diagnostics can distinguish the primary vs defensive
|
|
146
|
+
* surface (research §F6.c).
|
|
147
|
+
*
|
|
148
|
+
* - `requested` — slot count requested by the caller (entity count for the frame)
|
|
149
|
+
* - `capacity` — current `slotCount` in the grow controller's state
|
|
150
|
+
* - `ceiling` — `device.limits.maxStorageBufferBindingSize` in BYTES (not slots)
|
|
151
|
+
*/
|
|
152
|
+
export interface MeshSsboCapacityExceededDetail {
|
|
153
|
+
readonly requested: number;
|
|
154
|
+
readonly capacity: number;
|
|
155
|
+
readonly ceiling: number;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Structured error for the post-grow defensive fallback when mesh-SSBO
|
|
160
|
+
* capacity cannot accommodate the requested slot count.
|
|
161
|
+
*
|
|
162
|
+
* Emitted by `growMeshSsbo` in `createRenderer.ts` (D-5: fire, never
|
|
163
|
+
* throw). Four-field surface aligned with `SkinPaletteOverflowError`:
|
|
164
|
+
* - `.code = 'mesh-ssbo-capacity-exceeded'`
|
|
165
|
+
* - `.expected` — capacity >= requested
|
|
166
|
+
* - `.hint` — reduce per-frame entity count or split work across frames
|
|
167
|
+
* - `.detail = { requested, capacity, ceiling }`
|
|
168
|
+
*/
|
|
169
|
+
export class MeshSsboCapacityExceededError extends Error {
|
|
170
|
+
readonly code = 'mesh-ssbo-capacity-exceeded' as const;
|
|
171
|
+
readonly expected: string;
|
|
172
|
+
readonly hint: string;
|
|
173
|
+
readonly detail: MeshSsboCapacityExceededDetail;
|
|
174
|
+
|
|
175
|
+
constructor(requested: number, capacity: number, ceiling: number) {
|
|
176
|
+
const expected = `mesh SSBO slotCount >= ${requested} (currently ${capacity}; device ceiling ${ceiling} B)`;
|
|
177
|
+
const hint =
|
|
178
|
+
`mesh SSBO grow could not satisfy needed=${requested} slots (capacity=${capacity}, ceiling=${ceiling} B); ` +
|
|
179
|
+
'reduce per-frame entity count or split work across frames (defensive fallback path)';
|
|
180
|
+
super(
|
|
181
|
+
`mesh SSBO capacity exceeded: needed ${requested} slots, capacity ${capacity}, ceiling ${ceiling} B`,
|
|
182
|
+
);
|
|
183
|
+
this.name = 'MeshSsboCapacityExceededError';
|
|
184
|
+
this.expected = expected;
|
|
185
|
+
this.hint = hint;
|
|
186
|
+
this.detail = { requested, capacity, ceiling };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ── MeshSsboCeilingReachedError ──────────────────────────────────────────────
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Detail for `RuntimeErrorCode 'mesh-ssbo-ceiling-reached'`.
|
|
194
|
+
*
|
|
195
|
+
* Fired by `growMeshSsbo` when the requested slot count would exceed the
|
|
196
|
+
* device's `maxStorageBufferBindingSize` (the only ceiling per D-1; engine
|
|
197
|
+
* carries no private capacity constant). Same detail shape as
|
|
198
|
+
* `MeshSsboCapacityExceededDetail`.
|
|
199
|
+
*
|
|
200
|
+
* - `requested` — slot count requested by the caller
|
|
201
|
+
* - `capacity` — current `slotCount` in the grow controller's state
|
|
202
|
+
* - `ceiling` — `device.limits.maxStorageBufferBindingSize` in BYTES
|
|
203
|
+
*/
|
|
204
|
+
export interface MeshSsboCeilingReachedDetail {
|
|
205
|
+
readonly requested: number;
|
|
206
|
+
readonly capacity: number;
|
|
207
|
+
readonly ceiling: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Structured error for mesh-SSBO grow refused because the request exceeds
|
|
212
|
+
* `device.limits.maxStorageBufferBindingSize`.
|
|
213
|
+
*
|
|
214
|
+
* Emitted by `growMeshSsbo` (D-5: fire, never throw). The frame renders a
|
|
215
|
+
* degraded subset (truncated to pre-grow capacity) per plan-strategy D-2 —
|
|
216
|
+
* no black frame. Four-field surface aligned with `SkinPaletteOverflowError`:
|
|
217
|
+
* - `.code = 'mesh-ssbo-ceiling-reached'`
|
|
218
|
+
* - `.expected` — requested * stride <= device.limits.maxStorageBufferBindingSize
|
|
219
|
+
* - `.hint` — reduce per-frame entity count or pick a higher-tier adapter
|
|
220
|
+
* - `.detail = { requested, capacity, ceiling }`
|
|
221
|
+
*/
|
|
222
|
+
export class MeshSsboCeilingReachedError extends Error {
|
|
223
|
+
readonly code = 'mesh-ssbo-ceiling-reached' as const;
|
|
224
|
+
readonly expected: string;
|
|
225
|
+
readonly hint: string;
|
|
226
|
+
readonly detail: MeshSsboCeilingReachedDetail;
|
|
227
|
+
|
|
228
|
+
constructor(requested: number, capacity: number, ceiling: number) {
|
|
229
|
+
const expected = `mesh SSBO slot byte size <= device.limits.maxStorageBufferBindingSize (${ceiling} B)`;
|
|
230
|
+
const hint =
|
|
231
|
+
`requested ${requested} mesh SSBO slots would exceed device.limits.maxStorageBufferBindingSize (${ceiling} B); ` +
|
|
232
|
+
'reduce per-frame entity count or run on an adapter with a larger storage buffer binding size';
|
|
233
|
+
super(
|
|
234
|
+
`mesh SSBO ceiling reached: needed ${requested} slots; capacity ${capacity}; ceiling ${ceiling} B`,
|
|
235
|
+
);
|
|
236
|
+
this.name = 'MeshSsboCeilingReachedError';
|
|
237
|
+
this.expected = expected;
|
|
238
|
+
this.hint = hint;
|
|
239
|
+
this.detail = { requested, capacity, ceiling };
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ── SceneCollectEntityRefOutOfClosureError ──────────────────────────
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Detail for `RuntimeErrorCode 'scene-collect-entity-ref-out-of-closure'`.
|
|
247
|
+
*
|
|
248
|
+
* Emitted during rootsToSceneAsset when an entity field references a target
|
|
249
|
+
* outside the collected forest closure.
|
|
250
|
+
*/
|
|
251
|
+
export interface SceneCollectEntityRefOutOfClosureDetail {
|
|
252
|
+
readonly entity: number;
|
|
253
|
+
readonly field: string;
|
|
254
|
+
readonly target: number;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Structured error for entity ref pointing outside the forest closure.
|
|
259
|
+
*
|
|
260
|
+
* Emitted during rootsToSceneAsset collect; fail-fast per charter P3.
|
|
261
|
+
* - `.code = 'scene-collect-entity-ref-out-of-closure'`
|
|
262
|
+
* - `.expected` — all entity refs resolve within the closure
|
|
263
|
+
* - `.hint` — Expand roots to include the target entity, or remove the reference.
|
|
264
|
+
* - `.detail = { entity, field, target }`
|
|
265
|
+
*/
|
|
266
|
+
export class SceneCollectEntityRefOutOfClosureError extends Error {
|
|
267
|
+
readonly code = 'scene-collect-entity-ref-out-of-closure' as const;
|
|
268
|
+
readonly expected: string;
|
|
269
|
+
readonly hint: string;
|
|
270
|
+
readonly detail: SceneCollectEntityRefOutOfClosureDetail;
|
|
271
|
+
|
|
272
|
+
constructor(entity: number, field: string, target: number) {
|
|
273
|
+
const expected = `entity ${entity}.${field} references entity ${target} which is inside the forest closure`;
|
|
274
|
+
const hint = 'Expand roots to include the target entity, or remove the reference.';
|
|
275
|
+
super(`${expected} — ${hint}`);
|
|
276
|
+
this.name = 'SceneCollectEntityRefOutOfClosureError';
|
|
277
|
+
this.expected = expected;
|
|
278
|
+
this.hint = hint;
|
|
279
|
+
this.detail = { entity, field, target };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ── SceneCollectAssetGuidUnresolvedError ────────────────────────────
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Detail for `RuntimeErrorCode 'scene-collect-asset-guid-unresolved'`.
|
|
287
|
+
*
|
|
288
|
+
* Emitted at two points with different context on hand:
|
|
289
|
+
* - collect (handle→GUID): the shared handle is known → `.handle` is set.
|
|
290
|
+
* - serialize (GUID→refs): the GUID string is known but absent from the
|
|
291
|
+
* refs index → `.guid` is set. (`.handle` is meaningless there.)
|
|
292
|
+
* Exactly one of `handle` / `guid` is present per instance.
|
|
293
|
+
*/
|
|
294
|
+
export interface SceneCollectAssetGuidUnresolvedDetail {
|
|
295
|
+
readonly field: string;
|
|
296
|
+
readonly handle?: number;
|
|
297
|
+
readonly guid?: string;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Structured error for a shared asset reference whose GUID cannot be resolved.
|
|
302
|
+
*
|
|
303
|
+
* Emitted during rootsToSceneAsset collect (handle) or
|
|
304
|
+
* serializeSceneAssetToPack (guid); fail-fast per charter P3.
|
|
305
|
+
* - `.code = 'scene-collect-asset-guid-unresolved'`
|
|
306
|
+
* - `.expected` — every shared asset reference has a catalogued GUID
|
|
307
|
+
* - `.hint` — Register the asset in AssetRegistry before collecting.
|
|
308
|
+
* - `.detail = { field, handle }` (collect) or `{ field, guid }` (serialize)
|
|
309
|
+
*/
|
|
310
|
+
export class SceneCollectAssetGuidUnresolvedError extends Error {
|
|
311
|
+
readonly code = 'scene-collect-asset-guid-unresolved' as const;
|
|
312
|
+
readonly expected: string;
|
|
313
|
+
readonly hint: string;
|
|
314
|
+
readonly detail: SceneCollectAssetGuidUnresolvedDetail;
|
|
315
|
+
|
|
316
|
+
constructor(field: string, ref: number | string) {
|
|
317
|
+
const where = typeof ref === 'number' ? `handle ${ref}` : `guid '${ref}'`;
|
|
318
|
+
const expected = `shared field '${field}' (${where}) resolves to an asset whose GUID is catalogued`;
|
|
319
|
+
const hint =
|
|
320
|
+
'source SceneAsset is not catalogued: call registry.catalog(guid, payload) first, ' +
|
|
321
|
+
'or load through loadByGuid() which auto-catalogs GUID-scoped assets';
|
|
322
|
+
super(`${expected} — ${hint}`);
|
|
323
|
+
this.name = 'SceneCollectAssetGuidUnresolvedError';
|
|
324
|
+
this.expected = expected;
|
|
325
|
+
this.hint = hint;
|
|
326
|
+
this.detail = typeof ref === 'number' ? { field, handle: ref } : { field, guid: ref };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// -- AssetRuntimeErrorCode / AssetRuntimeError closed unions --------------------
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* Closed union of asset-cluster error codes. AI users perform exhaustive
|
|
334
|
+
* `switch (err.code)` without default; TS guards completeness.
|
|
335
|
+
*/
|
|
336
|
+
export type AssetRuntimeErrorCode = AssetRuntimeError['code'];
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Closed union of the asset-cluster structured error classes, each carrying
|
|
340
|
+
* an `AssetRuntimeErrorCode` discriminant on `.code`.
|
|
341
|
+
*/
|
|
342
|
+
export type AssetRuntimeError =
|
|
343
|
+
| MaterialResolvedEmptyPassesError
|
|
344
|
+
| MeshSsboCapacityExceededError
|
|
345
|
+
| MeshSsboCeilingReachedError
|
|
346
|
+
| SceneCollectEntityRefOutOfClosureError
|
|
347
|
+
| SceneCollectAssetGuidUnresolvedError;
|
package/src/handles.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
// @forgeax/engine-assets-runtime -- builtin mesh handles + scene-parse handle field
|
|
2
|
+
// name sets (feat-20260705-runtime-tier2-decomposition M1 / w4, D-4 F1
|
|
3
|
+
// straight-cut). Pure move from asset-registry.ts; zero identifier changes.
|
|
4
|
+
|
|
5
|
+
import type { Handle } from '@forgeax/engine-types';
|
|
6
|
+
import { handleSlot, toShared } from '@forgeax/engine-types';
|
|
7
|
+
|
|
8
|
+
// ─── Builtin handles (D-S9 / backward compat with hello-triangle + hello-cube) ─
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Builtin unit-cube mesh handle (8 vertices + 36 indices, pos+normal
|
|
12
|
+
* interleaved). Pair with `MeshFilter` to spawn a cube entity.
|
|
13
|
+
*
|
|
14
|
+
* @remarks Typed as `Handle<'MeshAsset', 'shared'>` — feat-20260517
|
|
15
|
+
* unifies the engine-types and engine-ecs Handle brand SSOT into a single
|
|
16
|
+
* `Handle<T extends string, M extends 'unique'|'shared'>` declaration
|
|
17
|
+
* (research Finding 4 import-path-decoupled identity), and constructs the
|
|
18
|
+
* value via the brand-creation factory `toShared<'MeshAsset'>(N)` so
|
|
19
|
+
* the caller-side `as unknown as` cast is eliminated (AC-05). The
|
|
20
|
+
* `'shared'` mode signals the AssetRegistry owns the lifecycle — the
|
|
21
|
+
* ECS does not release the slot on despawn / removeComponent / set.
|
|
22
|
+
* Runtime value is a small u32 (1).
|
|
23
|
+
*/
|
|
24
|
+
export const HANDLE_CUBE: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(1);
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Builtin triangle mesh handle (3 vertices). Pair with `MeshFilter`.
|
|
28
|
+
*
|
|
29
|
+
* @remarks Typed as `Handle<'MeshAsset', 'shared'>` (same narrow brand
|
|
30
|
+
* as HANDLE_CUBE; constructed via the `toShared<'MeshAsset'>(N)`
|
|
31
|
+
* factory per AC-05).
|
|
32
|
+
*/
|
|
33
|
+
export const HANDLE_TRIANGLE: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(2);
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Builtin unit-quad mesh handle — 4 vertices, 6 indices, 2 triangles on
|
|
37
|
+
* the XY plane facing +Z. Pair with `MeshFilter` to spawn a sprite quad
|
|
38
|
+
* (feat-20260520-2d-sprite-layer-mvp / M-1 / w06).
|
|
39
|
+
*
|
|
40
|
+
* @derives Same-shape sibling of {@link HANDLE_CUBE} / {@link HANDLE_TRIANGLE}
|
|
41
|
+
* per requirements §2.1.C: built via the `toShared<'MeshAsset'>(N)`
|
|
42
|
+
* brand-creation factory; reserved-id 3 fills the namespace hole between
|
|
43
|
+
* HANDLE_TRIANGLE=2 and FIRST_USER_HANDLE=1024 (no `BUILTIN_HANDLE_`
|
|
44
|
+
* prefix per Q2 naming decision — discoverable next to existing
|
|
45
|
+
* builtins in IDE autocomplete; charter F1 single-entry indexability).
|
|
46
|
+
*
|
|
47
|
+
* @reuses {@link createPlaneGeometry}(1, 1) — the procedural plane factory
|
|
48
|
+
* already produces 8-floats-per-vertex interleaved (position + normal +
|
|
49
|
+
* uv) and is then expanded to the runtime 12-floats layout (adds
|
|
50
|
+
* tangent vec4) by {@link meshFromInterleaved}. This funnels HANDLE_QUAD
|
|
51
|
+
* onto the exact same vertex pipeline branch as BUILTIN_CUBE /
|
|
52
|
+
* BUILTIN_TRIANGLE and the procedural geometry factories — zero new
|
|
53
|
+
* layout discriminator (plan-strategy §3 RT4 + D-9 + charter P4
|
|
54
|
+
* consistent abstraction).
|
|
55
|
+
*
|
|
56
|
+
* @reuses `PROCEDURAL_FLOATS_PER_VERTEX` = 12 from
|
|
57
|
+
* `@forgeax/engine-geometry` (the single layout SSOT; the procedural
|
|
58
|
+
* `createPlaneGeometry` factory already returns 12F via
|
|
59
|
+
* `meshFromInterleaved`).
|
|
60
|
+
*/
|
|
61
|
+
export const HANDLE_QUAD: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(3);
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Id=4 reserved builtin; occupies the next available slot under
|
|
65
|
+
* FIRST_USER_HANDLE=1024. BUILTIN_SPHERE is synthesised from
|
|
66
|
+
* `createSphereGeometry(1, 16, 12)` through the same
|
|
67
|
+
* `meshFromInterleaved` path as BUILTIN_QUAD, so the runtime
|
|
68
|
+
* 12-float stride is byte-identical to procedural output — zero
|
|
69
|
+
* new layout discriminator (charter P4 consistent abstraction).
|
|
70
|
+
*/
|
|
71
|
+
export const HANDLE_SPHERE: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(4);
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Builtin cylinder mesh handle — procedural open cylinder (unit-height,
|
|
75
|
+
* radius=0.5, 16 radial segments, no caps). Pair with `MeshFilter`.
|
|
76
|
+
*
|
|
77
|
+
* @derives Same-shape sibling of {@link HANDLE_SPHERE}: synthesised from
|
|
78
|
+
* `createCylinderGeometry(0.5, 0.5, 1, 16, 1)` through the same
|
|
79
|
+
* `meshFromInterleaved` path as BUILTIN_SPHERE, so the runtime
|
|
80
|
+
* 12-float stride is byte-identical to all other built-in meshes —
|
|
81
|
+
* zero new layout discriminator (charter P4 consistent abstraction).
|
|
82
|
+
*
|
|
83
|
+
* @remarks Id=6 follows {@link HANDLE_NINESLICE_QUAD}=5 in the builtin slot
|
|
84
|
+
* sequence (FIRST_USER_HANDLE=1024 untouched).
|
|
85
|
+
* feat-20260701-editor-world-container-doc-ecs-collapse M0 / AC-16:
|
|
86
|
+
* GUID = deriveBuiltin('HANDLE_CYLINDER') UUIDv5
|
|
87
|
+
* (plan-strategy §2 D-6 + §5.6 builtin-guid-ssot gate)
|
|
88
|
+
*/
|
|
89
|
+
export const HANDLE_CYLINDER: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(6);
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Builtin 9-slice quad mesh handle — 4×4 grid (16 vertices, 9 sub-quads,
|
|
93
|
+
* 54 indices) on the XY plane facing +Z. Pair with `MeshFilter` and a
|
|
94
|
+
* `MaterialAsset` whose first pass shader is `'forgeax::sprite'` and whose
|
|
95
|
+
* `values.slices` is non-zero to render a 9-sliced UI panel
|
|
96
|
+
* (feat-20260527-sprite-nineslice / M2 / w9).
|
|
97
|
+
*
|
|
98
|
+
* @derives Same-shape sibling of {@link HANDLE_QUAD}: synthesised from
|
|
99
|
+
* `createPlaneGeometry(1, 1, 3, 3)` which subdivides the unit quad into
|
|
100
|
+
* 3×3 sub-quads (9 cells). The 16 grid points and 54 indices feed
|
|
101
|
+
* {@link meshFromInterleaved} so the runtime 12-float vertex stride is
|
|
102
|
+
* byte-identical to all other built-in / procedural meshes — zero new
|
|
103
|
+
* layout discriminator (charter P4 consistent abstraction).
|
|
104
|
+
*
|
|
105
|
+
* @remarks Id=5 follows {@link HANDLE_SPHERE}=4 in the builtin slot
|
|
106
|
+
* sequence (FIRST_USER_HANDLE=1024 untouched). The vertex shader uses
|
|
107
|
+
* `vertex_index % 4` / `vertex_index / 4` to recover (i, j) grid
|
|
108
|
+
* coordinates and four anchor vec4s to map each grid cell to the right
|
|
109
|
+
* region of the source texture; only required when the sprite material
|
|
110
|
+
* declares non-zero `slices`. For the legacy zero-slice sprite path use
|
|
111
|
+
* {@link HANDLE_QUAD}.
|
|
112
|
+
*
|
|
113
|
+
* @reuses `PROCEDURAL_FLOATS_PER_VERTEX` = 12 from
|
|
114
|
+
* `@forgeax/engine-geometry` (sprite-pipeline binding table / vertex layout
|
|
115
|
+
* untouched). plan-strategy §D-2 NOTE clarifies
|
|
116
|
+
* the id=5 vs original-plan id=4 drift: HANDLE_SPHERE took id=4 in
|
|
117
|
+
* feat-20260529-fxaa-sphere-builtin before this feat landed.
|
|
118
|
+
*/
|
|
119
|
+
export const HANDLE_NINESLICE_QUAD: Handle<'MeshAsset', 'shared'> = toShared<'MeshAsset'>(5);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Stable GUIDs for the builtin meshes — the dash-form of
|
|
123
|
+
* `deriveBuiltin('HANDLE_<NAME>')` (UUIDv5, ForgeaX namespace) in
|
|
124
|
+
* `@forgeax/engine-pack`. They are inlined here (not imported) because the
|
|
125
|
+
* pack derivation runs under top-level `await` (async SubtleCrypto) and
|
|
126
|
+
* dragging that into the AssetRegistry constructor — a synchronous hot path
|
|
127
|
+
* consumed engine-wide — would make the whole runtime module graph async.
|
|
128
|
+
*
|
|
129
|
+
* The single source of truth remains `deriveBuiltin`: a cross-package
|
|
130
|
+
* guard test (`builtin-guid-ssot.test.ts`) asserts each literal equals the
|
|
131
|
+
* derived value, so any drift in the derivation reds the suite. This pairs
|
|
132
|
+
* the previously-disconnected dual truths (the u32 `HANDLE_*` constants and
|
|
133
|
+
* the pack GUID strings) into one bidirectionally-resolvable table, so
|
|
134
|
+
* `guidOf(HANDLE_CUBE)` no longer returns `undefined`
|
|
135
|
+
* (docs/feedbacks/2026-06-03 §6.2 Tier 0).
|
|
136
|
+
*/
|
|
137
|
+
export const BUILTIN_MESH_GUIDS: ReadonlyArray<readonly [Handle<'MeshAsset', 'shared'>, string]> = [
|
|
138
|
+
[HANDLE_CUBE, 'cbe42beb-8975-5096-b3a1-3dda4cb4c077'],
|
|
139
|
+
[HANDLE_TRIANGLE, '22592f07-d967-5116-b29c-fa9781929ba8'],
|
|
140
|
+
[HANDLE_QUAD, '339338aa-a338-581c-9fc5-744267ef8a51'],
|
|
141
|
+
[HANDLE_SPHERE, '95730fd2-9846-5f84-8658-0b3c971eb263'],
|
|
142
|
+
[HANDLE_NINESLICE_QUAD, '692d38b4-8cac-5fb2-9dcf-f389e076d6bf'],
|
|
143
|
+
// feat-20260701-editor-world-container-doc-ecs-collapse M0 / AC-16:
|
|
144
|
+
// cylinder builtin handle=6, GUID = deriveBuiltin('HANDLE_CYLINDER') UUIDv5
|
|
145
|
+
// (plan-strategy §5.6 builtin-guid-ssot gate)
|
|
146
|
+
[HANDLE_CYLINDER, 'ab20af21-0764-55be-a7f2-b80ab3d46a0a'],
|
|
147
|
+
];
|
|
148
|
+
|
|
149
|
+
/** Resolve the stable producer GUID for one process-static builtin mesh handle. */
|
|
150
|
+
export function builtinMeshGuid(handle: Handle<string, 'shared'>): string | undefined {
|
|
151
|
+
const slot = handleSlot(handle);
|
|
152
|
+
return BUILTIN_MESH_GUIDS.find(([candidate]) => handleSlot(candidate) === slot)?.[1];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Field names known to carry handle<> schema-vocab references (plan-strategy
|
|
157
|
+
* D-4). parseScenePayload uses this allowlist to replace integer values
|
|
158
|
+
* with GUID strings from refs[] only for handle fields — a Transform.pos lane of 0,
|
|
159
|
+
* ChildOf.parent=0 and similar non-handle integers are left untouched.
|
|
160
|
+
*
|
|
161
|
+
* When a new handle<> field is added to a runtime component, its field name
|
|
162
|
+
* MUST be added here so parseScenePayload correctly resolves it.
|
|
163
|
+
*/
|
|
164
|
+
export const HANDLE_FIELD_NAMES: ReadonlySet<string> = new Set([
|
|
165
|
+
'assetHandle',
|
|
166
|
+
'material',
|
|
167
|
+
'skeleton',
|
|
168
|
+
'clip',
|
|
169
|
+
// ParticleEffectPlayer.effect (shared<ParticleEffectAsset>) uses the same
|
|
170
|
+
// scene-pack refs[] index contract as every other scalar shared field.
|
|
171
|
+
'effect',
|
|
172
|
+
// feat-20260630-equirect-kind-internalized-ibl-declarative-skyligh M3 / w27:
|
|
173
|
+
// Skylight.equirect + SkyboxBackground.equirect (shared<EquirectAsset>). The
|
|
174
|
+
// generic extractSceneEntityHandleGuids path already covers shared< fields by
|
|
175
|
+
// schema; this allowlist is the second scene-parse path (parseScenePayload),
|
|
176
|
+
// so the new handle field name is registered here too (R-1).
|
|
177
|
+
'equirect',
|
|
178
|
+
]);
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Field names known to carry `array<handle<X>>` schema-vocab references
|
|
182
|
+
* (feat-20260608 M2 / w7: MeshRenderer.materials). Each element is a refs
|
|
183
|
+
* index that resolves to a GUID string. Coexists with HANDLE_FIELD_NAMES;
|
|
184
|
+
* a field name lives in exactly one set.
|
|
185
|
+
*/
|
|
186
|
+
export const HANDLE_ARRAY_FIELD_NAMES: ReadonlySet<string> = new Set(['materials']);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// @forgeax/engine-assets-runtime -- runtime-local ImageError constructor
|
|
2
|
+
// (feat-20260705-runtime-tier2-decomposition M1 / w4, D-4 F1 straight-cut).
|
|
3
|
+
// Pure move from asset-registry.ts; zero identifier changes.
|
|
4
|
+
|
|
5
|
+
import type { ImageErrorDetailFor, ImageErrorFor } from '@forgeax/engine-types';
|
|
6
|
+
import { IMAGE_ERROR_HINTS } from '@forgeax/engine-types';
|
|
7
|
+
|
|
8
|
+
// Local minimal `ImageError` constructor (charter P5 producer / consumer
|
|
9
|
+
// split: the runtime AssetRegistry should not import @forgeax/engine-image
|
|
10
|
+
// errors module because the image package is the disk-side decoder; the
|
|
11
|
+
// runtime is the GPU consumer. Both packages share the `ImageError`
|
|
12
|
+
// interface SSOT in @forgeax/engine-types so runtime constructs the
|
|
13
|
+
// 4-field surface (.code / .expected / .hint / .detail) directly without
|
|
14
|
+
// duplicating the @forgeax/engine-image errors.ts class).
|
|
15
|
+
type UnsupportedMimeImageError = ImageErrorFor<'image-format-unsupported'>;
|
|
16
|
+
type UnsupportedMimeImageErrorDetail = ImageErrorDetailFor<'image-format-unsupported'>;
|
|
17
|
+
|
|
18
|
+
const IMAGE_ERROR_EXPECTED_LOCAL: Readonly<
|
|
19
|
+
Record<UnsupportedMimeImageErrorDetail['code'], string>
|
|
20
|
+
> = {
|
|
21
|
+
'image-format-unsupported':
|
|
22
|
+
"mime is one of ['image/png', 'image/jpeg', 'image/x-tga']; texture format <-> colorSpace family agrees",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
class RuntimeImageError extends Error implements UnsupportedMimeImageError {
|
|
26
|
+
readonly code: UnsupportedMimeImageError['code'];
|
|
27
|
+
readonly expected: string;
|
|
28
|
+
readonly hint: string;
|
|
29
|
+
readonly detail: UnsupportedMimeImageErrorDetail;
|
|
30
|
+
constructor(detail: UnsupportedMimeImageErrorDetail) {
|
|
31
|
+
const code = detail.code;
|
|
32
|
+
const expected = IMAGE_ERROR_EXPECTED_LOCAL[code];
|
|
33
|
+
const hint = IMAGE_ERROR_HINTS[code];
|
|
34
|
+
super(`[ImageError ${code}] expected: ${expected}; hint: ${hint}`);
|
|
35
|
+
this.name = 'ImageError';
|
|
36
|
+
this.code = code;
|
|
37
|
+
this.expected = expected;
|
|
38
|
+
this.hint = hint;
|
|
39
|
+
this.detail = detail;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function makeImageError(detail: UnsupportedMimeImageErrorDetail): UnsupportedMimeImageError {
|
|
44
|
+
return new RuntimeImageError(detail);
|
|
45
|
+
}
|