@forgeax/engine-assets-runtime 0.1.7 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/__tests__/texture-pack-loader.unit.test.d.ts +2 -0
  3. package/dist/__tests__/texture-pack-loader.unit.test.d.ts.map +1 -0
  4. package/dist/decode-image-bytes.d.ts +2 -2
  5. package/dist/decode-image-bytes.d.ts.map +1 -1
  6. package/dist/errors/asset.d.ts +20 -0
  7. package/dist/errors/asset.d.ts.map +1 -1
  8. package/dist/index.d.ts +2 -3
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.mjs +264 -198
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/loaders/pack-artifact.d.ts +25 -1
  13. package/dist/loaders/pack-artifact.d.ts.map +1 -1
  14. package/dist/mipmap-generator.d.ts +3 -1
  15. package/dist/mipmap-generator.d.ts.map +1 -1
  16. package/dist/registry/instantiate.d.ts +2 -0
  17. package/dist/registry/instantiate.d.ts.map +1 -1
  18. package/dist/registry/validate-material.d.ts +26 -0
  19. package/dist/registry/validate-material.d.ts.map +1 -1
  20. package/package.json +14 -14
  21. package/src/__tests__/catalog-replica.unit.test.ts +36 -0
  22. package/src/__tests__/decode-image-bytes.browser.test.ts +5 -8
  23. package/src/__tests__/inline-pack-loaders.unit.test.ts +37 -0
  24. package/src/__tests__/instantiate-publication-fence.unit.test.ts +59 -1
  25. package/src/__tests__/material-ready.integration.test.ts +65 -0
  26. package/src/__tests__/pack-basis-load.integration.test.ts +66 -7
  27. package/src/__tests__/texture-pack-loader.unit.test.ts +145 -0
  28. package/src/__tests__/validate-material.unit.test.ts +45 -0
  29. package/src/decode-image-bytes.ts +6 -11
  30. package/src/errors/asset.ts +33 -0
  31. package/src/index.ts +7 -2
  32. package/src/loaders/pack-artifact.ts +218 -17
  33. package/src/mipmap-generator.ts +43 -1
  34. package/src/registry/instantiate.ts +14 -4
  35. package/src/registry/validate-material.ts +148 -0
@@ -1,4 +1,26 @@
1
- import type { Loader } from '@forgeax/engine-types';
1
+ import type { LoadContext, Loader, TextureAsset } from '@forgeax/engine-types';
2
+ import { AssetError } from '@forgeax/engine-types';
3
+ import { TexturePackVerificationError } from '../errors/asset.js';
4
+ import type { PackLoaderInput } from '../loader-registry';
5
+ export interface TexturePackLoadInput {
6
+ readonly pack: PackLoaderInput;
7
+ readonly sourceKey: string;
8
+ readonly generation: number;
9
+ readonly expectedDigest: string;
10
+ }
11
+ export type VerifiedTexturePack = {
12
+ readonly asset: TextureAsset;
13
+ readonly sourceKey: string;
14
+ readonly generation: number;
15
+ readonly digest: string;
16
+ };
17
+ export type VerifiedTexturePackResult = {
18
+ readonly ok: true;
19
+ readonly value: VerifiedTexturePack;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly error: TexturePackVerificationError | AssetError;
23
+ };
2
24
  export type CodecContextFailure = {
3
25
  readonly code: 'basis-profile-unsupported';
4
26
  readonly detail: {
@@ -11,6 +33,8 @@ export type CodecContextFailure = {
11
33
  readonly dfdColorSpace: 'srgb' | 'linear' | 'unknown';
12
34
  };
13
35
  };
36
+ /** Verify producer facts and then expose one accepted texture projection. */
37
+ export declare function loadVerifiedTexturePack(input: TexturePackLoadInput, ctx: LoadContext): Promise<VerifiedTexturePackResult>;
14
38
  export declare const textureLoader: Loader;
15
39
  export declare const equirectLoader: Loader;
16
40
  export declare const fontLoader: Loader;
@@ -1 +1 @@
1
- {"version":3,"file":"pack-artifact.d.ts","sourceRoot":"","sources":["../../src/loaders/pack-artifact.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAMV,MAAM,EAKP,MAAM,uBAAuB,CAAC;AA+L/B,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;KACvD,CAAC;CACH,CAAC;AAyXN,eAAO,MAAM,aAAa,EAAE,MAI3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAI5B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,MAIxB,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAkBlC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MA0B3B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAMlD,CAAC"}
1
+ {"version":3,"file":"pack-artifact.d.ts","sourceRoot":"","sources":["../../src/loaders/pack-artifact.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAKV,WAAW,EACX,MAAM,EAGN,YAAY,EAEb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,UAAU,EAAuB,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAEL,4BAA4B,EAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI1D,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,yBAAyB,GACjC;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAA;CAAE,GAC1D;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,4BAA4B,GAAG,UAAU,CAAA;CAAE,CAAC;AAkPtF,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE;QACf,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,QAAQ,CAAC;QAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;KACvD,CAAC;CACH,CAAC;AAkRN,6EAA6E;AAC7E,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,oBAAoB,EAC3B,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,yBAAyB,CAAC,CAiHpC;AA8GD,eAAO,MAAM,aAAa,EAAE,MAI3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,MAI5B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,MAIxB,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,MAkBlC,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MA0B3B,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAMlD,CAAC"}
@@ -1,4 +1,4 @@
1
- import { type Result, RhiError } from '@forgeax/engine-rhi';
1
+ import { type Result, RhiError, type RhiRenderPassEncoder } from '@forgeax/engine-rhi';
2
2
  /**
3
3
  * Subset of `RhiDevice` consumed by the mipmap utility (charter F2: only
4
4
  * the methods the algorithm actually invokes; the dawn integration tests
@@ -129,4 +129,6 @@ export declare function blitMipmapsSync(device: MipmapBlitDevice, texture: any,
129
129
  readonly height: number;
130
130
  readonly levels?: number;
131
131
  }): Result<void, RhiError>;
132
+ /** Encode one prewarmed mip level into a caller-owned graph render pass. */
133
+ export declare function encodeMipmapLevel(device: MipmapBlitDevice, pass: RhiRenderPassEncoder, sourceView: unknown, format: GPUTextureFormat): Result<void, RhiError>;
132
134
  //# sourceMappingURL=mipmap-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mipmap-generator.d.ts","sourceRoot":"","sources":["../src/mipmap-generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mipmap-generator.d.ts","sourceRoot":"","sources":["../src/mipmap-generator.ts"],"names":[],"mappings":"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"}
@@ -12,6 +12,8 @@ import { type ScenePublicationFence, type ScenePublicationFenceError } from './s
12
12
  export interface SkinJointResolver {
13
13
  resolveSkinAsset(skeletonHandleRaw: number): SkinAsset | undefined;
14
14
  }
15
+ /** Derive a publication fence from the registry's unified live projections. */
16
+ export declare function scenePublicationFenceFromRegistry(registry: AssetRegistry, outputGuid: string): Result<ScenePublicationFence, ScenePublicationFenceError>;
15
17
  /**
16
18
  * Post-spawn hook contract (D-1). A hook runs after instantiate spawns the
17
19
  * scene subtree; the shipped implementation is runtime's `postSpawnResolveJoints`
@@ -1 +1 @@
1
- {"version":3,"file":"instantiate.d.ts","sourceRoot":"","sources":["../../src/registry/instantiate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"instantiate.d.ts","sourceRoot":"","sources":["../../src/registry/instantiate.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,31 @@
1
1
  import type { CookedMaterialRecord } from '@forgeax/engine-pack';
2
2
  import { AssetError, type MaterialAsset, type MaterialError } from '@forgeax/engine-types';
3
3
  import type { AssetRegistry } from '../asset-registry';
4
+ export interface TexturePublicationStateSnapshot {
5
+ readonly guid: string;
6
+ readonly sourceKey: string;
7
+ readonly acceptedGeneration: number;
8
+ readonly acceptedDigest: string;
9
+ readonly candidateGeneration?: number;
10
+ readonly candidateFailure?: string;
11
+ }
12
+ export interface TexturePublicationState {
13
+ reject(candidate: {
14
+ readonly generation: number;
15
+ readonly reason: string;
16
+ }): TexturePublicationStateSnapshot;
17
+ accept(candidate: {
18
+ readonly generation: number;
19
+ readonly digest: string;
20
+ }): TexturePublicationStateSnapshot;
21
+ }
22
+ /** Candidate/accepted state that keeps the last known good publication honest. */
23
+ export declare function createTexturePublicationState(input: {
24
+ readonly guid: string;
25
+ readonly sourceKey: string;
26
+ readonly generation: number;
27
+ readonly digest: string;
28
+ }): TexturePublicationState;
4
29
  /**
5
30
  * Validate a MaterialAsset's passes[] against the ShaderRegistry's
6
31
  * paramSchema (union semantics: all declared params across all passes
@@ -15,6 +40,7 @@ import type { AssetRegistry } from '../asset-registry';
15
40
  * @returns AssetError on failure, null on success
16
41
  */
17
42
  export declare function validateMaterialPasses(registry: AssetRegistry, asset: MaterialAsset): AssetError | null;
43
+ export declare function validateMaterialTransmissionContract(asset: MaterialAsset): MaterialError | null;
18
44
  export interface MaterialEffectiveRootIdentity {
19
45
  readonly guid: string;
20
46
  readonly layoutIdentity: string;
@@ -1 +1 @@
1
- {"version":3,"file":"validate-material.d.ts","sourceRoot":"","sources":["../../src/registry/validate-material.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,UAAU,EAEV,KAAK,aAAa,EAClB,KAAK,aAAa,EAEnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,aAAa,GACnB,UAAU,GAAG,IAAI,CAoFnB;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC,EACtD,IAAI,EAAE,6BAA6B,GAClC,aAAa,GAAG,IAAI,CAiBtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,aAAa,GACnB,UAAU,GAAG,IAAI,CA8GnB;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,OAAO,CAgCT;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CA8BhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,MAAM,GACf,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,CAIjC"}
1
+ {"version":3,"file":"validate-material.d.ts","sourceRoot":"","sources":["../../src/registry/validate-material.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EACL,UAAU,EAEV,KAAK,aAAa,EAClB,KAAK,aAAa,EAEnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAEvD,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,SAAS,EAAE;QAChB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,GAAG,+BAA+B,CAAC;IACpC,MAAM,CAAC,SAAS,EAAE;QAChB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,GAAG,+BAA+B,CAAC;CACrC;AAED,kFAAkF;AAClF,wBAAgB,6BAA6B,CAAC,KAAK,EAAE;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GAAG,uBAAuB,CA0B1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,aAAa,GACnB,UAAU,GAAG,IAAI,CAoFnB;AA4CD,wBAAgB,oCAAoC,CAAC,KAAK,EAAE,aAAa,GAAG,aAAa,GAAG,IAAI,CAkD/F;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,IAAI,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC,EACtD,IAAI,EAAE,6BAA6B,GAClC,aAAa,GAAG,IAAI,CAiBtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,aAAa,GACnB,UAAU,GAAG,IAAI,CA8GnB;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,OAAO,CAgCT;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,IAAI,CA8BhG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,aAAa,EACvB,QAAQ,EAAE,MAAM,GACf,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,CAIjC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/engine-assets-runtime",
3
- "version": "0.1.7",
3
+ "version": "0.1.20",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -26,22 +26,22 @@
26
26
  "LICENSE"
27
27
  ],
28
28
  "dependencies": {
29
- "@forgeax/engine-codec": "0.1.7",
30
- "@forgeax/engine-ecs": "0.1.7",
31
- "@forgeax/engine-geometry": "0.1.7",
32
- "@forgeax/engine-graphics-extras": "0.1.7",
33
- "@forgeax/engine-image": "0.1.7",
34
- "@forgeax/engine-pack": "0.1.7",
35
- "@forgeax/engine-plugin": "0.1.7",
36
- "@forgeax/engine-rhi": "0.1.7",
37
- "@forgeax/engine-scene": "0.1.7",
38
- "@forgeax/engine-shader": "0.1.7",
39
- "@forgeax/engine-types": "0.1.7",
40
- "@forgeax/engine-ui": "0.1.7",
29
+ "@forgeax/engine-codec": "0.1.20",
30
+ "@forgeax/engine-ecs": "0.1.20",
31
+ "@forgeax/engine-geometry": "0.1.20",
32
+ "@forgeax/engine-graphics-extras": "0.1.20",
33
+ "@forgeax/engine-image": "0.1.20",
34
+ "@forgeax/engine-pack": "0.1.20",
35
+ "@forgeax/engine-plugin": "0.1.20",
36
+ "@forgeax/engine-rhi": "0.1.20",
37
+ "@forgeax/engine-scene": "0.1.20",
38
+ "@forgeax/engine-shader": "0.1.20",
39
+ "@forgeax/engine-types": "0.1.20",
40
+ "@forgeax/engine-ui": "0.1.20",
41
41
  "@webgpu/types": "^0.1.71"
42
42
  },
43
43
  "devDependencies": {
44
- "@forgeax/engine-skinning": "0.1.7",
44
+ "@forgeax/engine-skinning": "0.1.20",
45
45
  "@webgpu/types": "^0.1.71"
46
46
  },
47
47
  "forgeax": {
@@ -193,4 +193,40 @@ describe('CatalogReplica', () => {
193
193
  diagnostics: [{ code: 'catalog-revision-conflict', severity: 'blocking' }],
194
194
  });
195
195
  });
196
+
197
+ it('applies a failed lifecycle projection when the producer advances its observation revision', async () => {
198
+ const fixture = source();
199
+ const replica = new CatalogReplica(fixture.source as never);
200
+ await replica.start();
201
+
202
+ fixture.emit({
203
+ added: [],
204
+ changed: [
205
+ {
206
+ ...base,
207
+ lifecycle: 'failed',
208
+ revision: {
209
+ digest: 'failure:source-package-ddc-failed:sha256:old',
210
+ observedAt: 2,
211
+ rootId: base.revision.rootId,
212
+ },
213
+ diagnostics: [
214
+ {
215
+ code: 'source-package-ddc-failed',
216
+ severity: 'blocking',
217
+ hint: 'repair and retry',
218
+ },
219
+ ],
220
+ },
221
+ ],
222
+ removed: [],
223
+ });
224
+
225
+ expect(replica.snapshot().entries[0]).toMatchObject({
226
+ guid: base.guid,
227
+ lifecycle: 'failed',
228
+ revision: { observedAt: 2 },
229
+ });
230
+ expect(replica.snapshot().stale).toBe(false);
231
+ });
196
232
  });
@@ -30,7 +30,6 @@ import { World } from '@forgeax/engine-ecs';
30
30
  import type { TextureAsset } from '@forgeax/engine-types';
31
31
  import { describe, expect, it } from 'vitest';
32
32
  import { decodeImageBytes } from '../decode-image-bytes';
33
- import { numMipLevels } from '../mipmap-generator';
34
33
 
35
34
  // 1x1 red PNG (RGBA 8-bit). Universally decodable by browser createImageBitmap.
36
35
  const PNG_1X1_RED_BASE64 =
@@ -50,14 +49,13 @@ describe('decodeImageBytes browser real-PNG happy path (AC-01)', () => {
50
49
  if (!result.ok) return;
51
50
  const pod = result.value;
52
51
  expect(pod.kind).toBe('texture');
53
- expect(pod.width).toBeGreaterThan(0);
54
- expect(pod.height).toBeGreaterThan(0);
52
+ expect(pod.shape.extent.width).toBeGreaterThan(0);
53
+ expect(pod.shape.extent.height).toBeGreaterThan(0);
55
54
  // RGBA8 tight-packed: width * height * 4 bytes.
56
- expect(pod.data.length).toBe(pod.width * pod.height * 4);
55
+ expect(pod.data.length).toBe(pod.shape.extent.width * pod.shape.extent.height * 4);
57
56
  expect(pod.format).toBe('rgba8unorm-srgb');
58
57
  expect(pod.colorSpace).toBe('srgb');
59
- expect(pod.mipmap).toBe(true);
60
- expect(pod.mipLevelCount).toBe(numMipLevels({ width: pod.width, height: pod.height }));
58
+ expect(pod.mips).toEqual({ kind: 'generate' });
61
59
  });
62
60
 
63
61
  it('AC-01: opts.colorSpace="linear" + opts.mipmap=false narrows format + mipLevelCount', async () => {
@@ -70,8 +68,7 @@ describe('decodeImageBytes browser real-PNG happy path (AC-01)', () => {
70
68
  const pod = result.value;
71
69
  expect(pod.format).toBe('rgba8unorm');
72
70
  expect(pod.colorSpace).toBe('linear');
73
- expect(pod.mipmap).toBe(false);
74
- expect(pod.mipLevelCount).toBe(1);
71
+ expect(pod.mips).toEqual({ kind: 'none' });
75
72
  });
76
73
  });
77
74
 
@@ -279,6 +279,43 @@ describe('materialLoader', () => {
279
279
  });
280
280
  });
281
281
 
282
+ it('resolves transmission and thickness texture refs through authored contract', () => {
283
+ const out = materialLoader.load(
284
+ {
285
+ passes: [{ name: 'Forward', program: { module: 'forgeax::default-standard-pbr' } }],
286
+ parameters: [
287
+ { name: 'transmissionTexture', type: 'texture' },
288
+ { name: 'thicknessTexture', type: 'texture' },
289
+ ],
290
+ values: {
291
+ transmission: 0.8,
292
+ ior: 1.45,
293
+ thickness: 0.25,
294
+ transmissionTexture: { texture: 0, sampler: 1, coordinates: { set: 2 } },
295
+ thicknessTexture: { texture: 2, sampler: 3, coordinates: { set: 3 } },
296
+ },
297
+ },
298
+ ['texture-transmission', 'sampler-linear', 'texture-thickness', 'sampler-nearest'],
299
+ emptyCtx,
300
+ ) as MaterialAsset;
301
+
302
+ expect(out.values).toMatchObject({
303
+ transmission: 0.8,
304
+ ior: 1.45,
305
+ thickness: 0.25,
306
+ transmissionTexture: {
307
+ texture: 'texture-transmission',
308
+ sampler: 'sampler-linear',
309
+ coordinates: { set: 2 },
310
+ },
311
+ thicknessTexture: {
312
+ texture: 'texture-thickness',
313
+ sampler: 'sampler-nearest',
314
+ coordinates: { set: 3 },
315
+ },
316
+ });
317
+ });
318
+
282
319
  it('resolves nested texture values when the shader schema is present but empty', () => {
283
320
  const out = materialLoader.load(
284
321
  {
@@ -6,7 +6,7 @@ import {
6
6
  } from '@forgeax/engine-types';
7
7
  import { describe, expect, it } from 'vitest';
8
8
  import type { AssetRegistry } from '../asset-registry';
9
- import { resolveMountsRec } from '../registry/instantiate';
9
+ import { resolveMountsRec, scenePublicationFenceFromRegistry } from '../registry/instantiate';
10
10
  import { createScenePublicationFence } from '../registry/scene-publication-fence';
11
11
 
12
12
  const SCENE_GUID = '019ffdb4-1000-7000-8000-000000000008';
@@ -155,4 +155,62 @@ describe('resolveMountsRec publication fence identity', () => {
155
155
  );
156
156
  expect(result).toMatchObject({ ok: true, value: [{ source: 6 }] });
157
157
  });
158
+
159
+ it('prefers the complete pack-index tuple during a CatalogReplica handoff', () => {
160
+ const world = new World();
161
+ const currentSourcePath = 'assets/current.glb';
162
+ const currentPublication = {
163
+ ...publication(),
164
+ sourcePath: currentSourcePath,
165
+ receipt: { ...publication().receipt, sourcePath: currentSourcePath },
166
+ };
167
+ const fence = createScenePublicationFence(currentPublication);
168
+ expect(fence.ok).toBe(true);
169
+ if (!fence.ok) return;
170
+ const registry = {
171
+ assetCatalog: new Map(),
172
+ // The replica may still expose the prior complete tuple while the
173
+ // latest pack-index has already been hydrated after a source write.
174
+ catalogSnapshot: () => ({
175
+ entries: [
176
+ {
177
+ guid: SCENE_GUID,
178
+ kind: 'scene',
179
+ sourcePath: publication().sourcePath,
180
+ packageUrl: '/assets/scene.pack.json',
181
+ publication: publication(),
182
+ },
183
+ ],
184
+ }),
185
+ packIndexCache: new Map([
186
+ [
187
+ SCENE_GUID,
188
+ {
189
+ guid: SCENE_GUID,
190
+ kind: 'scene',
191
+ sourcePath: currentSourcePath,
192
+ packageUrl: '/assets/current.pack.json',
193
+ publication: currentPublication,
194
+ },
195
+ ],
196
+ ]),
197
+ _guidForAsset: () => undefined,
198
+ } as unknown as AssetRegistry;
199
+ const result = resolveMountsRec(
200
+ registry,
201
+ [
202
+ {
203
+ localId: 0 as never,
204
+ source: 6,
205
+ memberFirst: 0 as never,
206
+ memberCount: 0,
207
+ publicationFence: fence.value,
208
+ },
209
+ ],
210
+ world,
211
+ new Set(),
212
+ );
213
+ expect(result).toMatchObject({ ok: true, value: [{ source: 6 }] });
214
+ expect(scenePublicationFenceFromRegistry(registry, SCENE_GUID)).toEqual(fence);
215
+ });
158
216
  });
@@ -5,6 +5,7 @@ import {
5
5
  } from '@forgeax/engine-pack';
6
6
  import { AssetGuid } from '@forgeax/engine-pack/guid';
7
7
  import { ShaderRegistry } from '@forgeax/engine-shader';
8
+ import type { MaterialParameter } from '@forgeax/engine-types';
8
9
  import { describe, expect, it, vi } from 'vitest';
9
10
  import { AssetRegistry } from '../asset-registry';
10
11
  import { MaterialGenerationCache } from '../material/generation-cache';
@@ -103,6 +104,70 @@ describe('material runtime readiness', () => {
103
104
  ]);
104
105
  });
105
106
 
107
+ it('keeps the Standard transmission contract in the published snapshot', async () => {
108
+ const parameters: readonly MaterialParameter[] = [
109
+ { name: 'transmission', type: 'f32', default: 0 },
110
+ { name: 'ior', type: 'f32', default: 1.5 },
111
+ { name: 'thickness', type: 'f32', default: 0 },
112
+ { name: 'attenuationColor', type: 'vec3', default: [1, 1, 1] },
113
+ { name: 'attenuationDistance', type: 'f32' },
114
+ { name: 'transmissionTexture', type: 'texture' },
115
+ { name: 'thicknessTexture', type: 'texture' },
116
+ ];
117
+ expect(materialParametersToParamSchema(parameters, 'published::standard')).toEqual([
118
+ { name: 'transmission', type: 'f32', default: 0 },
119
+ { name: 'ior', type: 'f32', default: 1.5 },
120
+ { name: 'thickness', type: 'f32', default: 0 },
121
+ { name: 'attenuationColor', type: 'vec3', default: [1, 1, 1] },
122
+ { name: 'attenuationDistance', type: 'f32' },
123
+ { name: 'transmissionTexture', type: 'texture2d' },
124
+ { name: 'thicknessTexture', type: 'texture2d' },
125
+ ]);
126
+ const baseRecord = cookedRecord(PRODUCTION_GUID);
127
+ const record: CookedMaterialRecord = {
128
+ ...baseRecord,
129
+ parameterContract: {
130
+ parameters,
131
+ values: {
132
+ transmission: 0.8,
133
+ ior: 1.45,
134
+ thickness: 0.25,
135
+ attenuationColor: [0.9, 0.95, 1],
136
+ attenuationDistance: 4,
137
+ transmissionTexture: { texture: 'texture/transmission' },
138
+ thicknessTexture: { texture: 'texture/thickness' },
139
+ },
140
+ },
141
+ resolved: {
142
+ ...baseRecord.resolved,
143
+ parameters,
144
+ values: {
145
+ transmission: 0.8,
146
+ ior: 1.45,
147
+ thickness: 0.25,
148
+ attenuationColor: [0.9, 0.95, 1],
149
+ attenuationDistance: 4,
150
+ transmissionTexture: { texture: 'texture/transmission' },
151
+ thicknessTexture: { texture: 'texture/thickness' },
152
+ },
153
+ },
154
+ };
155
+ const loader = createMaterialLoader({
156
+ loadPublication: async () => ({ ...publication(), guid: PRODUCTION_GUID, record }),
157
+ loadReference: async () => true,
158
+ });
159
+
160
+ const result = await loader.load({
161
+ guid: PRODUCTION_GUID,
162
+ specializationKey: 'material-specialization/7/ready',
163
+ });
164
+
165
+ expect(result.status).toBe('Ready');
166
+ if (result.status !== 'Ready') return;
167
+ expect(result.parameterContract).toEqual(record.parameterContract);
168
+ expect(inspectMaterialRuntime(result).parameterContract).toEqual(record.parameterContract);
169
+ });
170
+
106
171
  it('loads only a cooked record with its artifact and complete references', async () => {
107
172
  const loader = createLoader(async () => publication());
108
173
 
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { existsSync } from 'node:fs';
2
3
  import { fileURLToPath } from 'node:url';
3
4
  import type { LoadContext, TextureAsset } from '@forgeax/engine-types';
@@ -7,7 +8,11 @@ import type {
7
8
  BasisModuleFactory,
8
9
  } from '../../../codec/src/wasm/basis-types.js';
9
10
  import type { CodecContextFailure } from '../loaders/pack-artifact.js';
10
- import { PACK_ARTIFACT_LOADERS, textureLoader } from '../loaders/pack-artifact.js';
11
+ import {
12
+ loadVerifiedTexturePack,
13
+ PACK_ARTIFACT_LOADERS,
14
+ textureLoader,
15
+ } from '../loaders/pack-artifact.js';
11
16
 
12
17
  const TRANSCODER_GLUE = new URL('../../../codec/pkg/basis_transcoder.mjs', import.meta.url);
13
18
  const ENCODER_GLUE = new URL('../../../codec/pkg/encode/basis_encoder.mjs', import.meta.url);
@@ -52,6 +57,10 @@ const context: LoadContext = {
52
57
  device: undefined,
53
58
  };
54
59
 
60
+ function digest(bytes: Uint8Array): string {
61
+ return `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
62
+ }
63
+
55
64
  describe.skipIf(!pkgBuilt)('Pack runtime raw Basis loader', () => {
56
65
  it('keeps context failure code and detail correlated as a closed union', () => {
57
66
  type ExpectedContextFailure =
@@ -79,7 +88,11 @@ describe.skipIf(!pkgBuilt)('Pack runtime raw Basis loader', () => {
79
88
  {
80
89
  guid: '019f0000-0000-7000-8000-000000000304',
81
90
  kind: 'texture',
82
- payload: { width: 4, height: 4, colorSpace: 'linear' },
91
+ payload: {
92
+ shape: { viewDimension: '2d', extent: { width: 4, height: 4 } },
93
+ colorSpace: 'linear',
94
+ mips: { kind: 'none' },
95
+ },
83
96
  refs: [],
84
97
  artifacts: {
85
98
  body: {
@@ -101,12 +114,10 @@ describe.skipIf(!pkgBuilt)('Pack runtime raw Basis loader', () => {
101
114
  if (!result.ok) return;
102
115
  expect(result.value).toMatchObject({
103
116
  kind: 'texture',
104
- width: 4,
105
- height: 4,
117
+ shape: { viewDimension: '2d', extent: { width: 4, height: 4 } },
106
118
  format: 'rgba8unorm',
107
119
  colorSpace: 'linear',
108
- mipmap: false,
109
- mipLevelCount: 1,
120
+ mips: { kind: 'packed', levelCount: 1 },
110
121
  });
111
122
  expect(result.value.data.byteLength).toBeGreaterThan(0);
112
123
  });
@@ -119,7 +130,11 @@ describe.skipIf(!pkgBuilt)('Pack runtime raw Basis loader', () => {
119
130
  {
120
131
  guid: '019f0000-0000-7000-8000-000000000305',
121
132
  kind: 'texture',
122
- payload: { width: 4, height: 4, colorSpace: 'srgb' },
133
+ payload: {
134
+ shape: { viewDimension: '2d', extent: { width: 4, height: 4 } },
135
+ colorSpace: 'srgb',
136
+ mips: { kind: 'none' },
137
+ },
123
138
  refs: [],
124
139
  artifacts: {
125
140
  body: {
@@ -165,4 +180,48 @@ describe('Pack artifact loader matrix', () => {
165
180
  ['equirect', 'font', 'render-pipeline', 'texture', 'tileset'].sort(),
166
181
  );
167
182
  });
183
+
184
+ it('preserves array shape and generation provenance through verified loading', async () => {
185
+ const bytes = new Uint8Array(8 * 4 * 3).fill(91);
186
+ const artifactDigest = digest(bytes);
187
+ const result = await loadVerifiedTexturePack(
188
+ {
189
+ sourceKey: 'array/layers',
190
+ generation: 4,
191
+ expectedDigest: artifactDigest,
192
+ pack: {
193
+ guid: '019f0000-0000-7000-8000-000000000306',
194
+ kind: 'texture',
195
+ payload: {
196
+ shape: { viewDimension: '2d-array', extent: { width: 8, height: 4, layers: 3 } },
197
+ format: 'r8unorm',
198
+ colorSpace: 'linear',
199
+ mips: { kind: 'none' },
200
+ },
201
+ refs: [],
202
+ artifacts: {
203
+ body: {
204
+ bytes,
205
+ descriptor: {
206
+ path: 'array.raw',
207
+ mediaType: 'application/x-forgeax-r8',
208
+ byteLength: bytes.byteLength,
209
+ integrity: { algorithm: 'sha256', digest: artifactDigest },
210
+ },
211
+ },
212
+ },
213
+ },
214
+ },
215
+ context,
216
+ );
217
+
218
+ expect(result.ok).toBe(true);
219
+ if (!result.ok) return;
220
+ expect(result.value.asset.shape).toEqual({
221
+ viewDimension: '2d-array',
222
+ extent: { width: 8, height: 4, layers: 3 },
223
+ });
224
+ expect(result.value.generation).toBe(4);
225
+ expect(result.value.sourceKey).toBe('array/layers');
226
+ });
168
227
  });