@forgeax/engine-assets-runtime 0.1.6 → 0.1.7

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.
@@ -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,CAkBtB;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;;;;;;;;;;;;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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/engine-assets-runtime",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
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.6",
30
- "@forgeax/engine-ecs": "0.1.6",
31
- "@forgeax/engine-geometry": "0.1.6",
32
- "@forgeax/engine-graphics-extras": "0.1.6",
33
- "@forgeax/engine-image": "0.1.6",
34
- "@forgeax/engine-pack": "0.1.6",
35
- "@forgeax/engine-plugin": "0.1.6",
36
- "@forgeax/engine-rhi": "0.1.6",
37
- "@forgeax/engine-scene": "0.1.6",
38
- "@forgeax/engine-shader": "0.1.6",
39
- "@forgeax/engine-types": "0.1.6",
40
- "@forgeax/engine-ui": "0.1.6",
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",
41
41
  "@webgpu/types": "^0.1.71"
42
42
  },
43
43
  "devDependencies": {
44
- "@forgeax/engine-skinning": "0.1.6",
44
+ "@forgeax/engine-skinning": "0.1.7",
45
45
  "@webgpu/types": "^0.1.71"
46
46
  },
47
47
  "forgeax": {
@@ -19,7 +19,7 @@ const PRODUCTION_GUID = '019f0000-0000-7000-8000-000000000701';
19
19
  function cookedRecord(guid = MATERIAL_GUID): CookedMaterialRecord {
20
20
  const artifactDigest = createMaterialArtifactDigest(ARTIFACT_BYTES);
21
21
  return {
22
- schemaVersion: 'material-cook/2',
22
+ schemaVersion: 'material-cook/3',
23
23
  guid,
24
24
  materialGuid: guid,
25
25
  publicationGeneration: 7,
@@ -36,15 +36,31 @@ function cookedRecord(guid = MATERIAL_GUID): CookedMaterialRecord {
36
36
  bytes: ARTIFACT_BYTES,
37
37
  },
38
38
  receipt: {
39
- schemaVersion: 'material-cook/2',
39
+ schemaVersion: 'material-cook/3',
40
40
  sourceClosure: ['materials/ready.material.json', 'shaders/ready.wgsl'],
41
41
  profile: 'webgpu/v1',
42
42
  compilerVersion: 'compiler/1',
43
- inputDigest: 'input-digest',
44
- outputDigest: artifactDigest,
45
- layoutIdentity: 'sha256:ready-layout',
43
+ identity: {
44
+ materialContractDigest: 'sha256:ready-contract',
45
+ sourceRevision: 'sha256:ready-source',
46
+ sourceClosureDigest: 'sha256:ready-closure',
47
+ layoutIdentity: 'sha256:ready-layout',
48
+ programIdentity: 'sha256:ready-program',
49
+ pipelineIdentity: 'sha256:ready-pipeline',
50
+ materialPublicationIdentity: 'sha256:ready-publication',
51
+ cookIdentity: 'sha256:ready-cook',
52
+ compilerFingerprint: 'sha256:ready-compiler',
53
+ wasm: {
54
+ sourceContentKey: 'unavailable',
55
+ artifactSha256: 'unavailable',
56
+ glueSha256: 'unavailable',
57
+ },
58
+ artifactDigest,
59
+ valueGeneration: 7,
60
+ dependencyGeneration: 7,
61
+ cookGeneration: 7,
62
+ },
46
63
  derivedInterface: { layoutIdentity: 'sha256:ready-layout' },
47
- publicationGeneration: 7,
48
64
  },
49
65
  };
50
66
  }
@@ -30,7 +30,6 @@ function createCookedMaterialLoader() {
30
30
  guid,
31
31
  record: {
32
32
  ...raw,
33
- schemaVersion: 'material-cook/2',
34
33
  materialGuid: raw.guid,
35
34
  publicationGeneration: 1,
36
35
  specializationKey: SPECIALIZATION_KEY,
@@ -40,11 +39,7 @@ function createCookedMaterialLoader() {
40
39
  artifact: { ...raw.artifact, digest, bytes },
41
40
  receipt: {
42
41
  ...raw.receipt,
43
- schemaVersion: 'material-cook/2',
44
- layoutIdentity: 'sha256:pulse-layout',
45
- derivedInterface: { layoutIdentity: 'sha256:pulse-layout' },
46
- publicationGeneration: 1,
47
- outputDigest: digest,
42
+ identity: { ...raw.receipt.identity, artifactDigest: digest, cookGeneration: 1 },
48
43
  },
49
44
  },
50
45
  artifact: { bytes },
@@ -167,7 +167,7 @@ describe('walkMaterialPassesOverSharedRefs', () => {
167
167
  const child = mat({
168
168
  parent: 'p-guid' as never,
169
169
  parameters: [
170
- { name: 'roughness', type: 'f32', static: true },
170
+ { name: 'roughness', type: 'f32' },
171
171
  { name: 'normalTexture', type: 'texture' },
172
172
  ],
173
173
  });
@@ -1,8 +1,10 @@
1
1
  import type {
2
2
  AnimationGraph,
3
3
  AssetRegistry,
4
+ AssetRegistryResolver,
4
5
  AudioClipAsset,
5
6
  ParticleEffectAsset,
7
+ RuntimeAssetRegistry,
6
8
  TilesetAsset,
7
9
  } from '@forgeax/engine-assets-runtime';
8
10
  import { expectTypeOf, it } from 'vitest';
@@ -14,3 +16,12 @@ it('exports concrete loadByGuid payload types from the runtime entry point', ()
14
16
  expectTypeOf<AudioClipAsset['mediaType']>().toMatchTypeOf<`audio/${string}`>();
15
17
  expectTypeOf<ParticleEffectAsset['program']>().toMatchTypeOf<ParticleEffectAsset['program']>();
16
18
  });
19
+
20
+ it('exports the five-action runtime registry and its resolver from the root entry point', () => {
21
+ expectTypeOf<RuntimeAssetRegistry>().toHaveProperty('installDecoder');
22
+ expectTypeOf<RuntimeAssetRegistry>().toHaveProperty('load');
23
+ expectTypeOf<RuntimeAssetRegistry>().toHaveProperty('snapshot');
24
+ expectTypeOf<RuntimeAssetRegistry>().toHaveProperty('subscribe');
25
+ expectTypeOf<AssetRegistryResolver>().toHaveProperty('lookup');
26
+ expectTypeOf<AssetRegistryResolver>().toHaveProperty('guidOf');
27
+ });
@@ -64,7 +64,7 @@ describe('validateMaterialCookIdentity', () => {
64
64
  const record = {
65
65
  guid: 'mat-child',
66
66
  receipt: {
67
- layoutIdentity: 'sha256:root-layout',
67
+ identity: { layoutIdentity: 'sha256:root-layout' },
68
68
  derivedInterface: { layoutIdentity: 'sha256:root-layout' },
69
69
  },
70
70
  } as never;
@@ -611,6 +611,11 @@ export class AssetRegistry {
611
611
  return this._originIndex.get(asset as object);
612
612
  }
613
613
 
614
+ /** Public identity projection consumed by scene collection boundaries. */
615
+ guidOf(asset: Asset): string | undefined {
616
+ return this._guidForAsset(asset);
617
+ }
618
+
614
619
  /** Return the production MaterialReady/Error result for one material GUID. */
615
620
  getMaterialReadiness(guid: string): MaterialReady | MaterialLoadError | undefined {
616
621
  return this.materialReadiness.get(guid.toLowerCase());
package/src/handles.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  // straight-cut). Pure move from asset-registry.ts; zero identifier changes.
4
4
 
5
5
  import type { Handle } from '@forgeax/engine-types';
6
- import { toShared } from '@forgeax/engine-types';
6
+ import { handleSlot, toShared } from '@forgeax/engine-types';
7
7
 
8
8
  // ─── Builtin handles (D-S9 / backward compat with hello-triangle + hello-cube) ─
9
9
 
@@ -146,6 +146,12 @@ export const BUILTIN_MESH_GUIDS: ReadonlyArray<readonly [Handle<'MeshAsset', 'sh
146
146
  [HANDLE_CYLINDER, 'ab20af21-0764-55be-a7f2-b80ab3d46a0a'],
147
147
  ];
148
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
+
149
155
  /**
150
156
  * Field names known to carry handle<> schema-vocab references (plan-strategy
151
157
  * D-4). parseScenePayload uses this allowlist to replace integer values
package/src/index.ts CHANGED
@@ -76,6 +76,7 @@ export {
76
76
  } from './errors/asset';
77
77
  // ─── Builtin mesh handles (re-exported by asset-registry from ./handles) ─────
78
78
  export {
79
+ builtinMeshGuid,
79
80
  HANDLE_CUBE,
80
81
  HANDLE_CYLINDER,
81
82
  HANDLE_NINESLICE_QUAD,
@@ -83,7 +84,15 @@ export {
83
84
  HANDLE_SPHERE,
84
85
  HANDLE_TRIANGLE,
85
86
  } from './handles';
86
- export { createAssetRegistry } from './internal/load-asset.js';
87
+ // The five-action runtime registry is distinct from the legacy authoring
88
+ // AssetRegistry class above. Keep its resolver on the public package boundary
89
+ // so render/VFX hosts never reach through `/internal` to inspect loaded assets.
90
+ export {
91
+ type AssetRegistry as RuntimeAssetRegistry,
92
+ type AssetRegistryResolver,
93
+ createAssetRegistry,
94
+ getAssetRegistryResolver,
95
+ } from './internal/load-asset.js';
87
96
  // ─── Loader-injection surface ───────────────────────────────────────────────
88
97
  export { LoaderRegistry } from './loader-registry';
89
98
  // ─── Default loader tables + individual loaders (pre-w14 consumer face) ──────
@@ -29,7 +29,7 @@ export function inspectMaterialRuntime(ready: MaterialReady): MaterialRuntimeInf
29
29
  publicationGeneration: ready.publicationGeneration,
30
30
  specializationKey: ready.specializationKey,
31
31
  artifactDigest: ready.artifactDigest,
32
- layoutIdentity: ready.record.receipt.layoutIdentity,
32
+ layoutIdentity: ready.record.receipt.identity.layoutIdentity,
33
33
  dependencies: [
34
34
  ...ready.record.refs.parent,
35
35
  ...ready.record.refs.textures,
@@ -108,7 +108,7 @@ function missingCook(request: MaterialLoadRequest): MaterialLoadError {
108
108
  function recordError(
109
109
  request: MaterialLoadRequest,
110
110
  field: string,
111
- expected = 'a complete material-cook/2 publication record',
111
+ expected = 'a complete material-cook/3 publication record',
112
112
  ): MaterialLoadError {
113
113
  return materialError(
114
114
  request,
@@ -174,18 +174,18 @@ function completeTupleField(record: CookedMaterialRecord): string | undefined {
174
174
  receipt.profile.length === 0 ||
175
175
  typeof receipt.compilerVersion !== 'string' ||
176
176
  receipt.compilerVersion.length === 0 ||
177
- typeof receipt.inputDigest !== 'string' ||
178
- receipt.inputDigest.length === 0 ||
179
- receipt.outputDigest !== record.artifactDigest ||
180
- receipt.publicationGeneration !== record.publicationGeneration
177
+ typeof receipt.identity.cookIdentity !== 'string' ||
178
+ receipt.identity.cookIdentity.length === 0 ||
179
+ receipt.identity.artifactDigest !== record.artifactDigest ||
180
+ receipt.identity.cookGeneration !== record.publicationGeneration
181
181
  )
182
182
  return 'receipt';
183
183
  if (
184
- typeof receipt.layoutIdentity !== 'string' ||
185
- receipt.layoutIdentity.length === 0 ||
186
- receipt.derivedInterface?.layoutIdentity !== receipt.layoutIdentity
184
+ typeof receipt.identity.layoutIdentity !== 'string' ||
185
+ receipt.identity.layoutIdentity.length === 0 ||
186
+ receipt.derivedInterface?.layoutIdentity !== receipt.identity.layoutIdentity
187
187
  )
188
- return 'receipt.layoutIdentity';
188
+ return 'receipt.identity.layoutIdentity';
189
189
  if (
190
190
  typeof record.artifact.mediaType !== 'string' ||
191
191
  record.artifact.mediaType.length === 0 ||
@@ -22,7 +22,7 @@ export function materialParametersToParamSchema(
22
22
  ? ENGINE_INJECTED_TEXTURE_FIELDS
23
23
  : undefined;
24
24
  return parameters.flatMap((parameter): ParamSchemaEntry[] => {
25
- if (parameter.static || parameter.type === 'bool') return [];
25
+ if (parameter.type === 'bool') return [];
26
26
  if (parameter.type === 'texture') {
27
27
  if (engineInjectedTextureFields?.has(parameter.name) === true) return [];
28
28
  return [{ name: parameter.name, type: 'texture2d' }];
@@ -104,7 +104,7 @@ export async function loadByGuid<T = Asset>(
104
104
  }
105
105
 
106
106
  function cookedRecordFromPayload(payload: Record<string, unknown>): unknown {
107
- if (payload.schemaVersion === 'material-cook/2') return payload;
107
+ if (payload.schemaVersion === 'material-cook/3') return payload;
108
108
  if (payload.cooked !== null && typeof payload.cooked === 'object') return payload.cooked;
109
109
  if (payload.record !== null && typeof payload.record === 'object') return payload.record;
110
110
  return undefined;
@@ -121,11 +121,10 @@ export function validateMaterialCookIdentity(
121
121
  record: Pick<CookedMaterialRecord, 'guid' | 'receipt'>,
122
122
  root: MaterialEffectiveRootIdentity,
123
123
  ): MaterialError | null {
124
- const actual = record.receipt.layoutIdentity;
124
+ const actual = record.receipt.identity.layoutIdentity;
125
125
  if (
126
126
  actual !== root.layoutIdentity ||
127
- (record.receipt as { readonly derivedInterface?: { readonly layoutIdentity?: string } })
128
- .derivedInterface?.layoutIdentity !== root.layoutIdentity
127
+ record.receipt.derivedInterface.layoutIdentity !== root.layoutIdentity
129
128
  ) {
130
129
  return createMaterialError('material-derived-interface-mismatch', {
131
130
  code: 'material-derived-interface-mismatch',