@forgeax/engine-import 0.1.20 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -3
- package/dist/__tests__/ies-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/ies-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/ies-producer.unit.test.d.ts +2 -0
- package/dist/__tests__/ies-producer.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-lod-contract.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-lod-contract.unit.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-lod-reimport.integration.test.d.ts +2 -0
- package/dist/__tests__/mesh-lod-reimport.integration.test.d.ts.map +1 -0
- package/dist/__tests__/parameterized-scriptable-pack.unit.test.d.ts +2 -0
- package/dist/__tests__/parameterized-scriptable-pack.unit.test.d.ts.map +1 -0
- package/dist/__tests__/scriptable-pack-file-snapshot.unit.test.d.ts +2 -0
- package/dist/__tests__/scriptable-pack-file-snapshot.unit.test.d.ts.map +1 -0
- package/dist/__tests__/source-package-publication-lod.integration.test.d.ts +2 -0
- package/dist/__tests__/source-package-publication-lod.integration.test.d.ts.map +1 -0
- package/dist/browser.d.ts +1 -0
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.mjs +230 -3
- package/dist/browser.mjs.map +1 -1
- package/dist/build-production.d.ts +1 -8
- package/dist/build-production.d.ts.map +1 -1
- package/dist/ies/ies-importer.d.ts +4 -0
- package/dist/ies/ies-importer.d.ts.map +1 -0
- package/dist/ies/parse-lm63.d.ts +13 -0
- package/dist/ies/parse-lm63.d.ts.map +1 -0
- package/dist/ies/resample-type-c.d.ts +4 -0
- package/dist/ies/resample-type-c.d.ts.map +1 -0
- package/dist/import-runner.d.ts.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +2550 -1029
- package/dist/index.mjs.map +1 -1
- package/dist/mesh-bin.d.ts.map +1 -1
- package/dist/mesh-bin.mjs +29 -1
- package/dist/mesh-bin.mjs.map +1 -1
- package/dist/mesh-lod.d.ts +60 -0
- package/dist/mesh-lod.d.ts.map +1 -0
- package/dist/parameterized-scriptable-pack.d.ts +68 -0
- package/dist/parameterized-scriptable-pack.d.ts.map +1 -0
- package/dist/scriptable-pack-file-snapshot.d.ts +71 -0
- package/dist/scriptable-pack-file-snapshot.d.ts.map +1 -0
- package/dist/scriptable-pack-host.d.ts +70 -39
- package/dist/scriptable-pack-host.d.ts.map +1 -1
- package/dist/scriptable-pack-output-producers.d.ts +1 -0
- package/dist/scriptable-pack-output-producers.d.ts.map +1 -1
- package/dist/scriptable-pack-staged-snapshot.d.ts +2 -2
- package/dist/scriptable-pack-staged-snapshot.d.ts.map +1 -1
- package/dist/scriptable-pack.d.ts +13 -26
- package/dist/scriptable-pack.d.ts.map +1 -1
- package/dist/source-package-errors.d.ts.map +1 -1
- package/dist/source-package-publication.d.ts.map +1 -1
- package/package.json +8 -7
- package/src/__tests__/ies-contract.unit.test.ts +31 -0
- package/src/__tests__/ies-producer.unit.test.ts +104 -0
- package/src/__tests__/mesh-bin.test.ts +69 -0
- package/src/__tests__/mesh-lod-contract.unit.test.ts +92 -0
- package/src/__tests__/mesh-lod-reimport.integration.test.ts +15 -0
- package/src/__tests__/parameterized-scriptable-pack.unit.test.ts +270 -0
- package/src/__tests__/scriptable-pack-file-snapshot.unit.test.ts +177 -0
- package/src/__tests__/scriptable-pack-host.unit.test.ts +196 -4
- package/src/__tests__/scriptable-pack-production-producers.unit.test.ts +7 -1
- package/src/__tests__/scriptable-pack-staged-snapshot.unit.test.ts +43 -12
- package/src/__tests__/source-package-publication-lod.integration.test.ts +29 -0
- package/src/__tests__/source-package-publication.integration.test.ts +26 -1
- package/src/browser.ts +5 -0
- package/src/build-production.ts +498 -141
- package/src/ies/ies-importer.ts +126 -0
- package/src/ies/parse-lm63.ts +98 -0
- package/src/ies/resample-type-c.ts +108 -0
- package/src/import-runner.ts +58 -0
- package/src/index.ts +49 -19
- package/src/mesh-bin.ts +38 -0
- package/src/mesh-lod.ts +265 -0
- package/src/parameterized-scriptable-pack.ts +725 -0
- package/src/scriptable-pack-file-snapshot.ts +346 -0
- package/src/scriptable-pack-host.ts +790 -343
- package/src/scriptable-pack-output-producers.ts +58 -1
- package/src/scriptable-pack-staged-snapshot.ts +12 -11
- package/src/scriptable-pack.ts +16 -485
- package/src/source-package-errors.ts +6 -0
- package/src/source-package-publication.ts +32 -2
- package/dist/.tsbuildinfo +0 -1
- package/dist/__tests__/scriptable-pack-product.contract.test.d.ts +0 -2
- package/dist/__tests__/scriptable-pack-product.contract.test.d.ts.map +0 -1
- package/dist/__tests__/scriptable-pack.integration.test.d.ts +0 -2
- package/dist/__tests__/scriptable-pack.integration.test.d.ts.map +0 -1
- package/dist/scriptable-source-package.d.ts +0 -14
- package/dist/scriptable-source-package.d.ts.map +0 -1
- package/src/__tests__/scriptable-pack-product.contract.test.ts +0 -46
- package/src/__tests__/scriptable-pack.integration.test.ts +0 -435
- package/src/scriptable-source-package.ts +0 -88
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import type { AnimationGraph, Asset, AssetGuid as AssetGuidType, AssetPublicationEnvelope, FontAsset, MaterialAsset, MeshAsset, Result, TilesetAsset } from '@forgeax/engine-types';
|
|
1
|
+
import type { ScriptablePackAssetKind } from '@forgeax/engine-pack';
|
|
2
|
+
import type { AssetReader, PackAuthoringError, ScriptablePackReadError } from '@forgeax/engine-pack/source';
|
|
3
|
+
import type { AnimationGraph, Asset, AssetGuid as AssetGuidType, AssetPublicationEnvelope, FontAsset, ImportError, ImportedAsset, MaterialAsset, MeshAsset, Result, TilesetAsset } from '@forgeax/engine-types';
|
|
4
|
+
import type { ImportAssetProduct, TerminalImportProduct } from './import-product.js';
|
|
4
5
|
export type { ScriptablePackSourceClosureEntry } from '@forgeax/engine-pack/source';
|
|
5
|
-
import { AssetError, ImportError } from '@forgeax/engine-types';
|
|
6
|
-
import { type ImportAssetProduct, type TerminalImportProduct } from './import-product.js';
|
|
7
6
|
export interface ScriptablePackAssetSnapshot {
|
|
8
7
|
readonly asset: Asset;
|
|
9
8
|
readonly generation: number;
|
|
@@ -11,8 +10,7 @@ export interface ScriptablePackAssetSnapshot {
|
|
|
11
10
|
}
|
|
12
11
|
export interface ScriptablePackStagedOutput {
|
|
13
12
|
readonly guid: AssetGuidType;
|
|
14
|
-
|
|
15
|
-
readonly sourceKey?: string;
|
|
13
|
+
readonly sourceKey: string;
|
|
16
14
|
readonly asset: Asset;
|
|
17
15
|
readonly digest?: string;
|
|
18
16
|
}
|
|
@@ -48,7 +46,7 @@ type AnimationGraphPackPayload = Omit<AnimationGraph, 'nodes'> & {
|
|
|
48
46
|
readonly clip: number;
|
|
49
47
|
}))[];
|
|
50
48
|
};
|
|
51
|
-
/** Serialized
|
|
49
|
+
/** Serialized producer payloads; runtime Assets never carry ref indices. */
|
|
52
50
|
export type AssetOutputPayloadByKind = {
|
|
53
51
|
readonly mesh: MeshAsset;
|
|
54
52
|
readonly material: MaterialPackPayload;
|
|
@@ -86,6 +84,9 @@ export type AssetOutputPayloadByKind = {
|
|
|
86
84
|
readonly 'particle-effect': Extract<Asset, {
|
|
87
85
|
readonly kind: 'particle-effect';
|
|
88
86
|
}>;
|
|
87
|
+
readonly 'ies-profile': Extract<Asset, {
|
|
88
|
+
readonly kind: 'ies-profile';
|
|
89
|
+
}>;
|
|
89
90
|
};
|
|
90
91
|
export type AssetOutputPayload = AssetOutputPayloadByKind[ScriptablePackAssetKind];
|
|
91
92
|
export type AssetOutputProduct = ImportAssetProduct<AssetOutputPayload>;
|
|
@@ -109,33 +110,19 @@ export interface ScriptablePackExternalEvidence {
|
|
|
109
110
|
}
|
|
110
111
|
export interface ScriptablePackBuildProduct {
|
|
111
112
|
readonly product: TerminalImportProduct<unknown>;
|
|
112
|
-
/** Raw private outputs for the current staged build generation, never a runtime publication path. */
|
|
113
113
|
readonly stagedOutputs: readonly ScriptablePackStagedOutput[];
|
|
114
114
|
readonly externalEvidence: readonly ScriptablePackExternalEvidence[];
|
|
115
115
|
readonly inputFingerprint: string;
|
|
116
|
-
/** Engine publication fields projected after ordinary producers run. */
|
|
117
116
|
readonly publication?: AssetPublicationEnvelope;
|
|
118
117
|
}
|
|
119
|
-
/** Domain-owned structured failure transported without flattening its recovery fields. */
|
|
120
118
|
export interface ScriptablePackDomainError {
|
|
121
119
|
readonly code: string;
|
|
122
120
|
readonly expected: string;
|
|
123
121
|
readonly hint: string;
|
|
124
122
|
readonly detail?: unknown;
|
|
125
123
|
}
|
|
126
|
-
|
|
127
|
-
export
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
readonly assetSource?: ScriptablePackAssetSnapshotSource;
|
|
131
|
-
readonly outputs: AssetOutputProducerRegistry;
|
|
132
|
-
readonly sourceClosure: readonly ScriptablePackSourceClosureEntry[];
|
|
133
|
-
readonly authoringContractVersion: string;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Build one external ScriptablePack through the producer-owned Pack bridge.
|
|
137
|
-
* Success preserves payloads, GUID refs, and local artifacts; failure retains
|
|
138
|
-
* `code`, `expected`, `hint`, and `detail` for recovery by the caller.
|
|
139
|
-
*/
|
|
140
|
-
export declare function buildScriptablePack(options: BuildScriptablePackOptions): Promise<ScriptablePackBuildBridgeResult>;
|
|
124
|
+
/** The source authoring contract is owned by Pack; this alias keeps reader typing local. */
|
|
125
|
+
export type ScriptablePackAssetReader = AssetReader;
|
|
126
|
+
export type ScriptablePackAuthoringError = PackAuthoringError;
|
|
127
|
+
export type ScriptablePackImportedAsset = ImportedAsset<unknown>;
|
|
141
128
|
//# sourceMappingURL=scriptable-pack.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scriptable-pack.d.ts","sourceRoot":"","sources":["../src/scriptable-pack.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"scriptable-pack.d.ts","sourceRoot":"","sources":["../src/scriptable-pack.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,KAAK,EACV,WAAW,EACX,kBAAkB,EAClB,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EACV,cAAc,EACd,KAAK,EACL,SAAS,IAAI,aAAa,EAC1B,wBAAwB,EACxB,SAAS,EACT,WAAW,EACX,aAAa,EACb,aAAa,EACb,SAAS,EACT,MAAM,EACN,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAErF,YAAY,EAAE,gCAAgC,EAAE,MAAM,6BAA6B,CAAC;AAEpF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,iCAAiC;IAChD,UAAU,CACR,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,MAAM,CAAC,2BAA2B,EAAE,uBAAuB,CAAC,CAAC,CAAC;CAC1E;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED,KAAK,mBAAmB,GAAG,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,QAAQ,CAAC,GAAG;IACpE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACrD,CAAC;AAEF,KAAK,gBAAgB,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,CAAC;AAEpF,KAAK,eAAe,GAAG,IAAI,CAAC,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC,GAAG;IAC5D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,KAAK,kBAAkB,GAAG,IAAI,CAAC,YAAY,EAAE,SAAS,CAAC,GAAG;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC;AAElG,KAAK,yBAAyB,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,GAAG;IAC/D,QAAQ,CAAC,KAAK,EAAE,SAAS,CACrB,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,GACnE,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,MAAM,CAAC,GAAG;QACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;KACvB,CAAC,CACL,EAAE,CAAC;CACL,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,wBAAwB,GAAG;IACrC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC/D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IACjE,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAC,CAAC;IAC/D,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAAC;IACjF,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC3D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IACjE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAA;KAAE,CAAC,CAAC;IAC/E,QAAQ,CAAC,iBAAiB,EAAE,yBAAyB,CAAC;IACtD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC3D,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAA;KAAE,CAAC,CAAC;IACjF,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;CAC1E,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAC,uBAAuB,CAAC,CAAC;AACnF,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,kBAAkB,CAAC,CAAC;AAExE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,OAAO,CACL,KAAK,EAAE,gBAAgB,GACtB,MAAM,CAAC,kBAAkB,EAAE,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC;CAC/F;AAED,qBAAa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0C;IAEpE,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI;IAU7C,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS;IAIlD,QAAQ,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAO7C;AAED,MAAM,MAAM,2BAA2B,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3E,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,2BAA2B,CAAC;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,SAAS,0BAA0B,EAAE,CAAC;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,SAAS,8BAA8B,EAAE,CAAC;IACrE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,WAAW,CAAC,EAAE,wBAAwB,CAAC;CACjD;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,4FAA4F;AAC5F,MAAM,MAAM,yBAAyB,GAAG,WAAW,CAAC;AACpD,MAAM,MAAM,4BAA4B,GAAG,kBAAkB,CAAC;AAC9D,MAAM,MAAM,2BAA2B,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-package-errors.d.ts","sourceRoot":"","sources":["../src/source-package-errors.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;CAyBvB,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,2BAA2B,CAAC;AAE9E,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GACN,UAAU,GACV,YAAY,GACZ,SAAS,GACT,KAAK,GACL,iBAAiB,CAAC;AAEtB,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAyB,SAAQ,yBAAyB;IACzE,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;CAC3C;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,sBAAsB,EAC5B,OAAO,EAAE,yBAAyB,EAClC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,MAAM,yBAAyB,CAAC,GACtE,kBAAkB,CAQpB;
|
|
1
|
+
{"version":3,"file":"source-package-errors.d.ts","sourceRoot":"","sources":["../src/source-package-errors.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;CAyBvB,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,2BAA2B,CAAC;AAE9E,MAAM,MAAM,uBAAuB,GAC/B,MAAM,GACN,UAAU,GACV,YAAY,GACZ,SAAS,GACT,KAAK,GACL,iBAAiB,CAAC;AAEtB,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAyB,SAAQ,yBAAyB;IACzE,QAAQ,CAAC,KAAK,EAAE,uBAAuB,CAAC;IACxC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAClD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAC;CAC3C;AAED,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,sBAAsB,EAC5B,OAAO,EAAE,yBAAyB,EAClC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,MAAM,yBAAyB,CAAC,GACtE,kBAAkB,CAQpB;AA4ED,qFAAqF;AACrF,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,eAAqB,GAAG,OAAO,CAM7F;AAED,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,yBAAyB,GACjC,kBAAkB,CAyBpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source-package-publication.d.ts","sourceRoot":"","sources":["../src/source-package-publication.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"source-package-publication.d.ts","sourceRoot":"","sources":["../src/source-package-publication.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forgeax/engine-import",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.23",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,12 +27,13 @@
|
|
|
27
27
|
"LICENSE"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@forgeax/engine-ddc": "0.1.
|
|
31
|
-
"@forgeax/engine-ecs": "0.1.
|
|
32
|
-
"@forgeax/engine-geometry": "0.1.
|
|
33
|
-
"@forgeax/engine-pack": "0.1.
|
|
34
|
-
"@forgeax/engine-scene": "0.1.
|
|
35
|
-
"@forgeax/engine-
|
|
30
|
+
"@forgeax/engine-ddc": "0.1.23",
|
|
31
|
+
"@forgeax/engine-ecs": "0.1.23",
|
|
32
|
+
"@forgeax/engine-geometry": "0.1.23",
|
|
33
|
+
"@forgeax/engine-pack": "0.1.23",
|
|
34
|
+
"@forgeax/engine-scene": "0.1.23",
|
|
35
|
+
"@forgeax/engine-shader": "0.1.23",
|
|
36
|
+
"@forgeax/engine-types": "0.1.23",
|
|
36
37
|
"@noble/hashes": "^2.2.0"
|
|
37
38
|
},
|
|
38
39
|
"devDependencies": {
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { IesProfileAsset } from '@forgeax/engine-types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { validateIesProfilePayload } from '../ies/ies-importer';
|
|
4
|
+
|
|
5
|
+
describe('IES asset contract', () => {
|
|
6
|
+
it('accepts exactly one cooked Type C payload shape', () => {
|
|
7
|
+
const payload: IesProfileAsset = {
|
|
8
|
+
kind: 'ies-profile',
|
|
9
|
+
data: new Uint8Array(256 * 128 * 2),
|
|
10
|
+
};
|
|
11
|
+
expect(validateIesProfilePayload(payload)).toEqual({ ok: true, value: payload });
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('rejects wrong kind, byte length, and non-finite decoded values', () => {
|
|
15
|
+
expect(
|
|
16
|
+
validateIesProfilePayload({ kind: 'texture', data: new Uint8Array(256 * 128 * 2) }),
|
|
17
|
+
).toMatchObject({
|
|
18
|
+
ok: false,
|
|
19
|
+
});
|
|
20
|
+
expect(
|
|
21
|
+
validateIesProfilePayload({ kind: 'ies-profile', data: new Uint8Array(4) }),
|
|
22
|
+
).toMatchObject({
|
|
23
|
+
ok: false,
|
|
24
|
+
});
|
|
25
|
+
const nonFinite = new Uint8Array(256 * 128 * 2);
|
|
26
|
+
nonFinite[1] = 0x7c;
|
|
27
|
+
expect(validateIesProfilePayload({ kind: 'ies-profile', data: nonFinite })).toMatchObject({
|
|
28
|
+
ok: false,
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { ImportContext } from '@forgeax/engine-types';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { iesImporter } from '../ies/ies-importer.js';
|
|
4
|
+
import { parseLm63TypeC } from '../ies/parse-lm63.js';
|
|
5
|
+
import { readFloat16LE, resampleTypeC } from '../ies/resample-type-c.js';
|
|
6
|
+
|
|
7
|
+
const GUID = '019f0000-0000-7000-8000-000000000081';
|
|
8
|
+
const SOURCE = `IESNA:LM-63-2002
|
|
9
|
+
TILT=NONE
|
|
10
|
+
1 1000 1 3 3 1 1 1 1 1 1 1
|
|
11
|
+
0 90 180
|
|
12
|
+
0 90 180
|
|
13
|
+
1 2 3
|
|
14
|
+
4 5 6
|
|
15
|
+
1 2 3
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
function context(source: string): ImportContext {
|
|
19
|
+
return {
|
|
20
|
+
source: 'fixtures/asymmetric.ies',
|
|
21
|
+
readSource: async () => ({ ok: true as const, value: new TextEncoder().encode(source) }),
|
|
22
|
+
readSibling: async () => ({ ok: false as const, error: new Error('not used') as never }),
|
|
23
|
+
decodeImage: async () => {
|
|
24
|
+
throw new Error('not used');
|
|
25
|
+
},
|
|
26
|
+
subAssets: [{ guid: GUID, sourceIndex: 0, sourceKey: 'ies/main', kind: 'ies-profile' }],
|
|
27
|
+
importSettings: {},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function fixture(): string {
|
|
32
|
+
return `IESNA:LM-63-2002
|
|
33
|
+
[TEST] ForgeaX Type C fixture
|
|
34
|
+
TILT=NONE
|
|
35
|
+
1 1000 1 3 3 1 1 1 1 1 1 1
|
|
36
|
+
0 90 180
|
|
37
|
+
0 90 180
|
|
38
|
+
1 2 3
|
|
39
|
+
4 5 6
|
|
40
|
+
1 2 3
|
|
41
|
+
`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe('LM-63 Type C producer primitives', () => {
|
|
45
|
+
it('parses TILT=NONE and preserves Type C angle tables', () => {
|
|
46
|
+
const parsed = parseLm63TypeC(fixture());
|
|
47
|
+
expect(parsed.ok).toBe(true);
|
|
48
|
+
if (parsed.ok) {
|
|
49
|
+
expect(parsed.value.horizontalAnglesDeg).toEqual([0, 90, 180]);
|
|
50
|
+
expect(parsed.value.candela).toHaveLength(9);
|
|
51
|
+
expect(parsed.value.tilt).toBe('NONE');
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('rejects tilted or non-Type-C sources with source diagnostics', () => {
|
|
56
|
+
const tilted = parseLm63TypeC(fixture().replace('TILT=NONE', 'TILT=INCLUDE'));
|
|
57
|
+
const nonTypeC = parseLm63TypeC(fixture().replace('1 1000 1 3 3 1 1', '1 1000 1 3 3 2 1'));
|
|
58
|
+
expect(tilted.ok).toBe(false);
|
|
59
|
+
expect(nonTypeC.ok).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('resamples to deterministic finite peak-normalized little-endian f16 bytes', () => {
|
|
63
|
+
const parsed = parseLm63TypeC(fixture());
|
|
64
|
+
expect(parsed.ok).toBe(true);
|
|
65
|
+
if (!parsed.ok) return;
|
|
66
|
+
const first = resampleTypeC(parsed.value);
|
|
67
|
+
const second = resampleTypeC(parsed.value);
|
|
68
|
+
expect(first).toEqual(second);
|
|
69
|
+
expect(first).toHaveLength(256 * 128 * 2);
|
|
70
|
+
const samples = Array.from({ length: 256 * 128 }, (_, index) =>
|
|
71
|
+
readFloat16LE(first, index * 2),
|
|
72
|
+
);
|
|
73
|
+
expect(samples.every(Number.isFinite)).toBe(true);
|
|
74
|
+
expect(Math.max(...samples)).toBeCloseTo(1, 6);
|
|
75
|
+
const lastSample = samples.at(-1) ?? 0;
|
|
76
|
+
expect(samples[255]).toBeCloseTo(lastSample, 3);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('IES Pack and publication boundary', () => {
|
|
81
|
+
it('publishes the authored GUID and cooked artifact without source text', async () => {
|
|
82
|
+
const result = await iesImporter.import(context(SOURCE));
|
|
83
|
+
expect(result.ok).toBe(true);
|
|
84
|
+
if (!result.ok) return;
|
|
85
|
+
expect(result.value.assets).toHaveLength(1);
|
|
86
|
+
expect(result.value.assets[0]).toMatchObject({ guid: GUID, kind: 'ies-profile' });
|
|
87
|
+
expect(result.value.assets[0]?.payload).toMatchObject({ kind: 'ies-profile' });
|
|
88
|
+
expect(result.value.assets[0]?.artifacts.body?.bytes).toHaveLength(256 * 128 * 2);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('is byte deterministic and rejects invalid sources before publication', async () => {
|
|
92
|
+
const first = await iesImporter.import(context(SOURCE));
|
|
93
|
+
const second = await iesImporter.import(context(SOURCE));
|
|
94
|
+
expect(first).toEqual(second);
|
|
95
|
+
|
|
96
|
+
const failed = await iesImporter.import(context(SOURCE.replace('TILT=NONE', 'TILT=INCLUDE')));
|
|
97
|
+
expect(failed.ok).toBe(false);
|
|
98
|
+
if (!failed.ok) {
|
|
99
|
+
expect(failed.error).toMatchObject({ code: 'source-validation-failed' });
|
|
100
|
+
expect(failed.error.expected).toContain('TILT=NONE');
|
|
101
|
+
expect(failed.error.detail).toMatchObject({ diagnostics: expect.any(Array) });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -91,6 +91,75 @@ describe('mesh-bin v4 roundtrip contract', () => {
|
|
|
91
91
|
);
|
|
92
92
|
});
|
|
93
93
|
|
|
94
|
+
it('stores lower-detail mesh refs and screen coverage in v4 metadata', () => {
|
|
95
|
+
const lodGuid = '019d0000-0000-7000-8000-000000000006';
|
|
96
|
+
const lod = AssetGuid.parse(lodGuid);
|
|
97
|
+
if (!lod.ok) throw new Error('fixture guid must parse');
|
|
98
|
+
const payload = {
|
|
99
|
+
...buildPayload(4, 0, false),
|
|
100
|
+
lods: [{ mesh: lod.value, screenCoverage: 0.5 }],
|
|
101
|
+
lodHysteresis: 0.08,
|
|
102
|
+
};
|
|
103
|
+
const result = packMeshBinV4(payload, 'gltf://lod-root', [lodGuid]);
|
|
104
|
+
expect(result.ok).toBe(true);
|
|
105
|
+
if (!result.ok) return;
|
|
106
|
+
const header = decodeMeshBinHeader(result.value, 'gltf://lod-root');
|
|
107
|
+
expect(header.ok).toBe(true);
|
|
108
|
+
if (!header.ok) return;
|
|
109
|
+
const jsonOffset = 80 + header.value.vertexBytes + header.value.indexBytes;
|
|
110
|
+
const meta = JSON.parse(
|
|
111
|
+
new TextDecoder().decode(
|
|
112
|
+
result.value.subarray(jsonOffset, jsonOffset + header.value.jsonBytes),
|
|
113
|
+
),
|
|
114
|
+
) as { lods?: unknown; lodHysteresis?: unknown };
|
|
115
|
+
expect(meta.lods).toEqual([{ meshRef: 0, screenCoverage: 0.5 }]);
|
|
116
|
+
expect(meta.lodHysteresis).toBe(0.08);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('fails closed when a lower-detail mesh ref is not enclosed by refs', () => {
|
|
120
|
+
const lod = AssetGuid.parse('019d0000-0000-7000-8000-000000000007');
|
|
121
|
+
if (!lod.ok) throw new Error('fixture guid must parse');
|
|
122
|
+
const result = packMeshBinV4(
|
|
123
|
+
{ ...buildPayload(4, 0, false), lods: [{ mesh: lod.value, screenCoverage: 0.5 }] },
|
|
124
|
+
'gltf://lod-missing-ref',
|
|
125
|
+
);
|
|
126
|
+
expect(result.ok).toBe(false);
|
|
127
|
+
if (result.ok) return;
|
|
128
|
+
expect(result.error.actual).toContain('absent from refs');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('rejects non-decreasing coverage and invalid hysteresis before cooking', () => {
|
|
132
|
+
const first = AssetGuid.parse('019d0000-0000-7000-8000-000000000008');
|
|
133
|
+
const second = AssetGuid.parse('019d0000-0000-7000-8000-000000000009');
|
|
134
|
+
if (!first.ok || !second.ok) throw new Error('fixture guids must parse');
|
|
135
|
+
const result = packMeshBinV4(
|
|
136
|
+
{
|
|
137
|
+
...buildPayload(4, 0, false),
|
|
138
|
+
lods: [
|
|
139
|
+
{ mesh: first.value, screenCoverage: 0.5 },
|
|
140
|
+
{ mesh: second.value, screenCoverage: 0.5 },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
'gltf://lod-invalid-coverage',
|
|
144
|
+
[AssetGuid.format(first.value), AssetGuid.format(second.value)],
|
|
145
|
+
);
|
|
146
|
+
expect(result.ok).toBe(false);
|
|
147
|
+
if (result.ok) return;
|
|
148
|
+
expect(result.error.actual).toContain('strictly decreasing');
|
|
149
|
+
|
|
150
|
+
const hysteresis = packMeshBinV4(
|
|
151
|
+
{
|
|
152
|
+
...buildPayload(4, 0, false),
|
|
153
|
+
lods: [{ mesh: first.value, screenCoverage: 0.5 }],
|
|
154
|
+
lodHysteresis: 1,
|
|
155
|
+
},
|
|
156
|
+
'gltf://lod-invalid-hysteresis',
|
|
157
|
+
[AssetGuid.format(first.value)],
|
|
158
|
+
);
|
|
159
|
+
expect(hysteresis.ok).toBe(false);
|
|
160
|
+
if (!hysteresis.ok) expect(hysteresis.error.actual).toContain('lodHysteresis');
|
|
161
|
+
});
|
|
162
|
+
|
|
94
163
|
it('returns a closed error without bytes for invalid stride cardinality', () => {
|
|
95
164
|
const payload = buildPayload(2, 0, false);
|
|
96
165
|
const result = packMeshBinV4({ ...payload, vertexCount: 3 }, 'gltf://invalid');
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
deriveDefaultLodScreenCoverages,
|
|
4
|
+
reconcileMeshLodMeta,
|
|
5
|
+
validateMeshLodContract,
|
|
6
|
+
} from '../mesh-lod.js';
|
|
7
|
+
|
|
8
|
+
describe('mesh LOD contract', () => {
|
|
9
|
+
it.each([
|
|
10
|
+
[1, []],
|
|
11
|
+
[2, [0.5]],
|
|
12
|
+
[3, [0.5, 0.2]],
|
|
13
|
+
[4, [0.5, 0.2, 0.08]],
|
|
14
|
+
[5, [0.5, 0.2, 0.08, 0.032]],
|
|
15
|
+
[8, [0.5, 0.2, 0.08, 0.032, 0.0128, 0.00512, 0.002048]],
|
|
16
|
+
])('derives stable defaults for %i levels', (levelCount, expected) => {
|
|
17
|
+
expect(deriveDefaultLodScreenCoverages(levelCount)).toEqual(expected);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('rejects zero, non-finite, and non-decreasing coverage', () => {
|
|
21
|
+
expect(validateMeshLodContract({ lods: [{ meshGuid: 'a', screenCoverage: 0 }] })).toMatchObject(
|
|
22
|
+
{
|
|
23
|
+
ok: false,
|
|
24
|
+
error: { code: 'mesh-lod-contract-invalid' },
|
|
25
|
+
},
|
|
26
|
+
);
|
|
27
|
+
expect(
|
|
28
|
+
validateMeshLodContract({
|
|
29
|
+
lods: [
|
|
30
|
+
{ meshGuid: 'a', screenCoverage: 0.5 },
|
|
31
|
+
{ meshGuid: 'b', screenCoverage: 0.6 },
|
|
32
|
+
],
|
|
33
|
+
}),
|
|
34
|
+
).toMatchObject({
|
|
35
|
+
ok: false,
|
|
36
|
+
error: { code: 'mesh-lod-contract-invalid' },
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('preserves existing author facts and only appends levels', () => {
|
|
41
|
+
const previous = [
|
|
42
|
+
{ sourceKey: 'mesh/lod1', meshGuid: 'guid-1', screenCoverage: 0.5 },
|
|
43
|
+
{ sourceKey: 'mesh/lod2', meshGuid: 'guid-2', screenCoverage: 0.2 },
|
|
44
|
+
];
|
|
45
|
+
expect(
|
|
46
|
+
reconcileMeshLodMeta(previous, [...previous, { sourceKey: 'mesh/lod3', meshGuid: 'guid-3' }]),
|
|
47
|
+
).toMatchObject({
|
|
48
|
+
ok: true,
|
|
49
|
+
value: {
|
|
50
|
+
lods: [...previous, { sourceKey: 'mesh/lod3', meshGuid: 'guid-3', screenCoverage: 0.08 }],
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
expect(reconcileMeshLodMeta(previous, previous.slice().reverse())).toMatchObject({
|
|
54
|
+
ok: false,
|
|
55
|
+
error: { code: 'mesh-lod-topology-change' },
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('rejects incomplete refs, non-enclosing bounds, slot drift, and cycles', () => {
|
|
60
|
+
const base = {
|
|
61
|
+
lods: [{ meshGuid: 'lod-1', screenCoverage: 0.5 }],
|
|
62
|
+
rootMeshGuid: 'root',
|
|
63
|
+
refs: ['root'],
|
|
64
|
+
rootBounds: { min: [-1, -1, -1] as const, max: [1, 1, 1] as const },
|
|
65
|
+
lodBounds: [{ min: [-2, -1, -1] as const, max: [1, 1, 1] as const }],
|
|
66
|
+
rootMaterialSlots: [{ sourceKey: 'body' }],
|
|
67
|
+
lodMaterialSlots: [[{ sourceKey: 'body' }]],
|
|
68
|
+
relations: [{ from: 'root', to: 'lod-1' }],
|
|
69
|
+
};
|
|
70
|
+
expect(validateMeshLodContract(base).ok).toBe(false);
|
|
71
|
+
const cycle = validateMeshLodContract({
|
|
72
|
+
...base,
|
|
73
|
+
refs: ['root', 'lod-1'],
|
|
74
|
+
lodBounds: [{ min: [-1, -1, -1], max: [1, 1, 1] }],
|
|
75
|
+
relations: [
|
|
76
|
+
{ from: 'root', to: 'lod-1' },
|
|
77
|
+
{ from: 'lod-1', to: 'root' },
|
|
78
|
+
],
|
|
79
|
+
});
|
|
80
|
+
expect(cycle.ok).toBe(false);
|
|
81
|
+
if (!cycle.ok) expect(cycle.error.reason).toContain('acyclic');
|
|
82
|
+
const slotDrift = validateMeshLodContract({
|
|
83
|
+
...base,
|
|
84
|
+
refs: ['root', 'lod-1'],
|
|
85
|
+
lodBounds: [{ min: [-1, -1, -1], max: [1, 1, 1] }],
|
|
86
|
+
relations: [{ from: 'root', to: 'lod-1' }],
|
|
87
|
+
lodMaterialSlots: [[{ sourceKey: 'head' }]],
|
|
88
|
+
});
|
|
89
|
+
expect(slotDrift.ok).toBe(false);
|
|
90
|
+
if (!slotDrift.ok) expect(slotDrift.error.reason).toContain('material slots');
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { reconcileMeshLodMeta } from '../mesh-lod.js';
|
|
3
|
+
|
|
4
|
+
describe('mesh LOD reimport identity', () => {
|
|
5
|
+
it('keeps coverage attached to sourceKey instead of array position', () => {
|
|
6
|
+
const result = reconcileMeshLodMeta(
|
|
7
|
+
[{ sourceKey: 'root/lod1', meshGuid: 'guid-1', screenCoverage: 0.5 }],
|
|
8
|
+
[{ sourceKey: 'root/lod1', meshGuid: 'guid-1', screenCoverage: 0.5 }],
|
|
9
|
+
);
|
|
10
|
+
expect(result).toMatchObject({
|
|
11
|
+
ok: true,
|
|
12
|
+
value: { lods: [{ meshGuid: 'guid-1', screenCoverage: 0.5 }] },
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|