@forgeax/engine-gltf 0.1.6 → 0.1.19

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 (39) hide show
  1. package/README.md +9 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/__tests__/transmission-pack-carrier.integration.test.d.ts +2 -0
  4. package/dist/__tests__/transmission-pack-carrier.integration.test.d.ts.map +1 -0
  5. package/dist/bridge.d.ts.map +1 -1
  6. package/dist/check-extensions.d.ts +3 -3
  7. package/dist/check-extensions.d.ts.map +1 -1
  8. package/dist/cli-gltf.mjs +161 -69
  9. package/dist/cli-gltf.mjs.map +1 -1
  10. package/dist/errors.d.ts +7 -0
  11. package/dist/errors.d.ts.map +1 -1
  12. package/dist/gltf-importer.d.ts.map +1 -1
  13. package/dist/importer-entry.mjs +177 -72
  14. package/dist/importer-entry.mjs.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.mjs +177 -72
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/material/parse-material.d.ts +118 -0
  20. package/dist/material/parse-material.d.ts.map +1 -0
  21. package/dist/node-file-entry.mjs +161 -69
  22. package/dist/node-file-entry.mjs.map +1 -1
  23. package/dist/parse-gltf.d.ts +17 -103
  24. package/dist/parse-gltf.d.ts.map +1 -1
  25. package/package.json +12 -12
  26. package/src/__tests__/bridge-material-values.unit.test.ts +46 -0
  27. package/src/__tests__/gltf-error-derived-views.test-d.ts +4 -0
  28. package/src/__tests__/gltf-error-policy-owner.unit.test.ts +26 -178
  29. package/src/__tests__/gltf.unit.test.ts +28 -4
  30. package/src/__tests__/material-pack-refs.integration.test.ts +12 -0
  31. package/src/__tests__/parse-gltf.unit.test.ts +121 -0
  32. package/src/__tests__/transmission-pack-carrier.integration.test.ts +82 -0
  33. package/src/bridge.ts +12 -1
  34. package/src/check-extensions.ts +14 -9
  35. package/src/errors.ts +12 -0
  36. package/src/gltf-importer.ts +6 -0
  37. package/src/index.ts +1 -0
  38. package/src/material/parse-material.ts +342 -0
  39. package/src/parse-gltf.ts +50 -277
@@ -1,12 +1,14 @@
1
1
  import { ImportError } from '@forgeax/engine-types';
2
2
  import { COMPONENT_TYPE } from './accessor/decode-accessor.js';
3
3
  import { type GltfError, type Result } from './errors.js';
4
+ import { type GltfImageIr, type GltfMaterialIr, type GltfSamplerIr, type GltfTextureIr } from './material/parse-material.js';
4
5
  import { type GltfBufferViewDecodeCapability } from './meshopt-decode.js';
5
6
  import { type GltfAnimationClipRecord } from './parse-animation.js';
6
7
  import { type GltfSkeletonRecord } from './parse-skin.js';
7
8
  import { type GltfMetaJson, type GltfSubAssetEntry } from './reimport-reuse-meta.js';
8
9
  import type { GltfSourceKeyError } from './source-key.js';
9
10
  import { type DecomposedTransform } from './transform.js';
11
+ export type { GltfImageIr, GltfMaterialIr, GltfMaterialJson, GltfNormalTextureInfoIr, GltfOcclusionTextureInfoIr, GltfSamplerIr, GltfTextureInfoIr, GltfTextureIr, GltfTextureTransformIr, NormalTextureInfoJson, OcclusionTextureInfoJson, TextureInfoJson, } from './material/parse-material.js';
10
12
  export interface MeshPrimitiveJson {
11
13
  readonly attributes?: Record<string, number>;
12
14
  readonly indices?: number;
@@ -24,26 +26,26 @@ export interface GltfMeshIr {
24
26
  readonly positions: Float32Array;
25
27
  readonly normals?: Float32Array;
26
28
  readonly texcoord0?: Float32Array;
27
- /** TEXCOORD_1 per-vertex UV set 1 (Float32Array, 2 per vertex). feat-20260629-multi-uv-set-support m1-w2. */
29
+ /** TEXCOORD_1 per-vertex UV set 1. */
28
30
  readonly texcoord1?: Float32Array;
29
- /** TEXCOORD_2 per-vertex UV set 2 (Float32Array, 2 per vertex). */
31
+ /** TEXCOORD_2 per-vertex UV set 2. */
30
32
  readonly texcoord2?: Float32Array;
31
- /** TEXCOORD_3 per-vertex UV set 3 (Float32Array, 2 per vertex). */
33
+ /** TEXCOORD_3 per-vertex UV set 3. */
32
34
  readonly texcoord3?: Float32Array;
33
- /** TEXCOORD_4 per-vertex UV set 4 (Float32Array, 2 per vertex). */
35
+ /** TEXCOORD_4 per-vertex UV set 4. */
34
36
  readonly texcoord4?: Float32Array;
35
- /** TEXCOORD_5 per-vertex UV set 5 (Float32Array, 2 per vertex). */
37
+ /** TEXCOORD_5 per-vertex UV set 5. */
36
38
  readonly texcoord5?: Float32Array;
37
- /** TEXCOORD_6 per-vertex UV set 6 (Float32Array, 2 per vertex). */
39
+ /** TEXCOORD_6 per-vertex UV set 6. */
38
40
  readonly texcoord6?: Float32Array;
39
- /** TEXCOORD_7 per-vertex UV set 7 (Float32Array, 2 per vertex). */
41
+ /** TEXCOORD_7 per-vertex UV set 7. */
40
42
  readonly texcoord7?: Float32Array;
41
43
  readonly tangents?: Float32Array;
42
- /** COLOR_0 importer carrier; bridge projects it to the canonical color attribute. */
44
+ /** COLOR_0 importer carrier. */
43
45
  readonly colors0?: Float32Array;
44
- /** JOINTS_0 per-vertex joint indices (Uint16Array, 4 per vertex). UBYTE source is width-converted to U16 at parse time (D-3). */
46
+ /** JOINTS_0 per-vertex joint indices. */
45
47
  readonly joints0?: Uint16Array;
46
- /** WEIGHTS_0 per-vertex skin weights (Float32Array, 4 per vertex). */
48
+ /** WEIGHTS_0 per-vertex skin weights. */
47
49
  readonly weights0?: Float32Array;
48
50
  readonly morphTargets?: readonly {
49
51
  readonly position?: Float32Array;
@@ -51,100 +53,16 @@ export interface GltfMeshIr {
51
53
  readonly tangent?: Float32Array;
52
54
  }[];
53
55
  readonly morphWeights?: Float32Array;
54
- /**
55
- * Optional per-glTF-spec: when omitted, primitive declares non-indexed
56
- * geometry (vertex buffer is consumed in vertex order, every 3 verts =
57
- * 1 triangle for triangle-list). bridge.ts handles undefined by routing
58
- * MeshAsset.indices to undefined and submesh.indexCount=0 (vertexCount
59
- * carries the draw count for `pass.draw(vertexCount)`).
60
- * bug-20260612 hello-skin visual layered gate: prior shape coerced
61
- * undefined into Uint16Array(0) and tripped MeshAsset.indices !==
62
- * undefined branches downstream into drawIndexed(0).
63
- * U16 (incl. widened U8) or U32 — width preserved from the source accessor;
64
- * bridge.ts narrows U32 to U16 when the merged maxIndex fits.
65
- */
56
+ /** Undefined means non-indexed; otherwise source width is preserved. */
66
57
  readonly indices?: Uint16Array | Uint32Array;
67
58
  readonly materialIndex: number | null;
68
- /**
69
- * Owning glTF mesh index in the original document (`gltf.meshes[meshIndex]`).
70
- * After OOS-7 flattening, multiple GltfMeshIr entries may share the same
71
- * meshIndex (one per primitive). Bridge layer uses this to filter material
72
- * collection per node, fixing the verify-r1 charter-defect where multi
73
- * glTF-mesh documents would silently misalign materials across nodes.
74
- */
59
+ /** Owning glTF mesh index; multiple IR rows may share it after flattening. */
75
60
  readonly meshIndex: number;
76
61
  }
77
- export interface GltfTextureIr {
78
- readonly sampler?: number;
79
- readonly source: number;
80
- readonly name?: string;
81
- }
82
- export interface GltfTextureTransformIr {
83
- readonly offset?: readonly [number, number];
84
- readonly rotation?: number;
85
- readonly scale?: readonly [number, number];
86
- }
87
- export interface GltfTextureInfoIr {
88
- readonly texture: number;
89
- readonly sampler?: number;
90
- readonly texCoord?: number;
91
- readonly transform?: GltfTextureTransformIr;
92
- }
93
- export interface GltfNormalTextureInfoIr extends GltfTextureInfoIr {
94
- readonly scale?: number;
95
- }
96
- export interface GltfOcclusionTextureInfoIr extends GltfTextureInfoIr {
97
- readonly strength?: number;
98
- }
99
- export interface GltfImageIr {
100
- readonly uri?: string;
101
- readonly mimeType?: string;
102
- readonly bufferView?: number;
103
- readonly name?: string;
104
- }
105
- export interface GltfSamplerIr {
106
- readonly magFilter?: number;
107
- readonly minFilter?: number;
108
- readonly wrapS: number;
109
- readonly wrapT: number;
110
- readonly name?: string;
111
- }
112
- export interface GltfMaterialIr {
113
- readonly name?: string;
114
- readonly baseColorFactor: readonly [number, number, number, number];
115
- /** glTF emissiveFactor; omitted means the glTF default [0, 0, 0]. */
116
- readonly emissiveFactor?: readonly [number, number, number];
117
- readonly baseColorTexture?: GltfTextureInfoIr | number;
118
- /** Texture binding for the emissive map. */
119
- readonly emissiveTexture?: GltfTextureInfoIr | number;
120
- readonly metallicFactor: number;
121
- readonly roughnessFactor: number;
122
- readonly metallicRoughnessTexture?: GltfTextureInfoIr | number;
123
- readonly normalTexture?: GltfNormalTextureInfoIr | number;
124
- readonly occlusionTexture?: GltfOcclusionTextureInfoIr | number;
125
- /**
126
- * glTF `alphaMode` (`'OPAQUE'` | `'MASK'` | `'BLEND'`). Absent -> `'OPAQUE'`
127
- * (glTF spec default). Drives the bridge's transparent / alpha-test routing.
128
- */
129
- readonly alphaMode?: 'OPAQUE' | 'MASK' | 'BLEND';
130
- /** glTF `alphaCutoff` (MASK-mode threshold; glTF spec default 0.5). */
131
- readonly alphaCutoff?: number;
132
- /**
133
- * glTF `doubleSided`. Absent -> false (the glTF spec default). The bridge
134
- * maps this to a no-cull material pass so reverse-facing glass and cards
135
- * remain visible without changing their authored winding.
136
- */
137
- readonly doubleSided?: boolean;
138
- /**
139
- * baseColorTexture UV-set index (glTF `baseColorTexture.texCoord`). Absent
140
- * -> 0. Selects which interleaved UV set the base-color sampler reads.
141
- */
142
- readonly baseColorTexCoord?: number;
143
- }
144
62
  export interface NodeInstancingIr {
145
- /** Number of instances. All TRS attribute accessors share this count. */
63
+ /** Number of instances. */
146
64
  readonly count: number;
147
- /** N column-major mat4 transforms packed into one Float32Array (length = N*16). */
65
+ /** Column-major transforms packed into one Float32Array. */
148
66
  readonly transforms: Float32Array;
149
67
  }
150
68
  export type GltfPunctualLightType = 'directional' | 'point' | 'spot';
@@ -162,16 +80,12 @@ export interface GltfNodeIr {
162
80
  readonly name?: string;
163
81
  readonly transform: DecomposedTransform;
164
82
  readonly meshIndex: number | null;
165
- /** Node-authored morph weights override mesh defaults at instantiation. */
83
+ /** Node-authored morph weights override mesh defaults. */
166
84
  readonly morphWeights?: Float32Array;
167
- /** Valid when node carries `skin` reference. Null when no skin. */
168
85
  readonly skinIndex: number | null;
169
86
  readonly children: readonly number[];
170
- /** Present when node carries EXT_mesh_gpu_instancing (feat-20260518). */
171
87
  readonly instancing?: NodeInstancingIr;
172
- /** glTF camera index. Null when the node does not reference a camera. */
173
88
  readonly camera: number | null;
174
- /** KHR_lights_punctual light index. Null when the node has no light. */
175
89
  readonly lightIndex?: number | null;
176
90
  }
177
91
  export interface GltfSceneIr {
@@ -1 +1 @@
1
- {"version":3,"file":"parse-gltf.d.ts","sourceRoot":"","sources":["../src/parse-gltf.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"parse-gltf.d.ts","sourceRoot":"","sources":["../src/parse-gltf.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgeax/engine-gltf",
3
- "version": "0.1.6",
3
+ "version": "0.1.19",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -38,21 +38,21 @@
38
38
  "LICENSE"
39
39
  ],
40
40
  "dependencies": {
41
- "@forgeax/engine-animation": "0.1.6",
42
- "@forgeax/engine-geometry": "0.1.6",
43
- "@forgeax/engine-import": "0.1.6",
44
- "@forgeax/engine-math": "0.1.6",
45
- "@forgeax/engine-pack": "0.1.6",
46
- "@forgeax/engine-scene": "0.1.6",
47
- "@forgeax/engine-types": "0.1.6",
41
+ "@forgeax/engine-animation": "0.1.19",
42
+ "@forgeax/engine-geometry": "0.1.19",
43
+ "@forgeax/engine-import": "0.1.19",
44
+ "@forgeax/engine-math": "0.1.19",
45
+ "@forgeax/engine-pack": "0.1.19",
46
+ "@forgeax/engine-scene": "0.1.19",
47
+ "@forgeax/engine-types": "0.1.19",
48
48
  "@webgpu/types": "^0.1.71",
49
49
  "meshoptimizer": "^0.20.0"
50
50
  },
51
51
  "devDependencies": {
52
- "@forgeax/engine-assets-runtime": "0.1.6",
53
- "@forgeax/engine-picking": "0.1.6",
54
- "@forgeax/engine-render": "0.1.6",
55
- "@forgeax/engine-runtime": "0.1.6",
52
+ "@forgeax/engine-assets-runtime": "0.1.19",
53
+ "@forgeax/engine-picking": "0.1.19",
54
+ "@forgeax/engine-render": "0.1.19",
55
+ "@forgeax/engine-runtime": "0.1.19",
56
56
  "@types/node": "^20.14.0"
57
57
  },
58
58
  "forgeax": {
@@ -103,4 +103,50 @@ describe('glTF material bridge values', () => {
103
103
  expect(material.values?.baseColorTexture).toEqual({ texture: 100 });
104
104
  expect(material.values?.baseColorTexture).not.toHaveProperty('coordinates');
105
105
  });
106
+
107
+ it('projects transmission and volume texture references without flattening coordinates', () => {
108
+ const material = toMaterialAsset(
109
+ {
110
+ baseColorFactor: [1, 1, 1, 1],
111
+ metallicFactor: 0,
112
+ roughnessFactor: 0.5,
113
+ transmissionFactor: 0.8,
114
+ transmissionTexture: { texture: 5, sampler: 15, texCoord: 2 },
115
+ ior: 1.45,
116
+ thicknessFactor: 0.2,
117
+ thicknessTexture: {
118
+ texture: 6,
119
+ sampler: 16,
120
+ texCoord: 3,
121
+ transform: { offset: [0.1, 0.2] },
122
+ },
123
+ attenuationColor: [0.5, 0.6, 0.7],
124
+ attenuationDistance: 2,
125
+ } as unknown as GltfMaterialIr,
126
+ {
127
+ textureHandles: new Map([
128
+ [5, 105],
129
+ [6, 106],
130
+ ]) as unknown as ReadonlyMap<number, Handle<'TextureAsset', 'shared'>>,
131
+ samplerHandles: new Map([
132
+ [15, 205],
133
+ [16, 206],
134
+ ]) as unknown as ReadonlyMap<number, Handle<'SamplerAsset', 'shared'>>,
135
+ },
136
+ );
137
+
138
+ expect(material.values).toMatchObject({
139
+ transmission: 0.8,
140
+ ior: 1.45,
141
+ thickness: 0.2,
142
+ attenuationColor: [0.5, 0.6, 0.7],
143
+ attenuationDistance: 2,
144
+ transmissionTexture: { texture: 105, sampler: 205, coordinates: { set: 2 } },
145
+ thicknessTexture: {
146
+ texture: 106,
147
+ sampler: 206,
148
+ coordinates: { set: 3, transform: { offset: [0.1, 0.2] } },
149
+ },
150
+ });
151
+ });
106
152
  });
@@ -14,6 +14,7 @@ import {
14
14
  type GltfImageMimeUnsupportedDetail,
15
15
  type GltfInstancingCountMismatchDetail,
16
16
  type GltfMalformedHeaderDetail,
17
+ type GltfMaterialTransmissionInvalidDetail,
17
18
  type GltfMeshBridgeInvalidDetail,
18
19
  type GltfMeshoptDecodeFailedDetail,
19
20
  type GltfMeshoptDecoderRequiredDetail,
@@ -51,6 +52,7 @@ type ExpectedDetails = {
51
52
  readonly 'gltf-color-accessor-unsupported': GltfColorAccessorUnsupportedDetail;
52
53
  readonly 'gltf-color-accessor-malformed': GltfColorAccessorMalformedDetail;
53
54
  readonly 'gltf-mesh-bridge-invalid': GltfMeshBridgeInvalidDetail;
55
+ readonly 'gltf-material-transmission-invalid': GltfMaterialTransmissionInvalidDetail;
54
56
  };
55
57
 
56
58
  type ExpectedCodes = keyof ExpectedDetails;
@@ -109,6 +111,8 @@ function exhaustive(error: GltfError): string {
109
111
  return `${error.detail.semantic}:${error.detail.accessorIndex}:${error.detail.reason}`;
110
112
  case 'gltf-mesh-bridge-invalid':
111
113
  return error.detail.reason;
114
+ case 'gltf-material-transmission-invalid':
115
+ return `${error.detail.extension}:${error.detail.field}:${error.detail.reason}`;
112
116
  }
113
117
  return error;
114
118
  }
@@ -1,185 +1,33 @@
1
- import { describe, expect, expectTypeOf, it } from 'vitest';
2
- import {
3
- GLTF_ERROR_HINTS,
4
- type GltfError,
5
- type GltfErrorCode,
6
- type GltfSkinAttrAsymmetricDetail,
7
- type GltfVersionUnsupportedDetail,
8
- gltfErr,
9
- } from '../errors.js';
10
-
11
- const EXPECTED_IN_POLICY_ORDER = [
12
- 'GLB 12-byte header (magic 0x46546C67 + version=2 + length) plus mandatory JSON chunk',
13
- 'asset.version === "2.0"',
14
- 'accessor byte range within bufferView.byteLength',
15
- 'extension listed in v1 allowlist (see EXTENSION_ALLOWLIST in @forgeax/engine-gltf)',
16
- 'dense fixed-stride accessor with supported componentType',
17
- 'externalLoader resolved the URI into an ArrayBuffer without throwing',
18
- "sidecar <source>.meta.json (importer: 'gltf') present in same directory",
19
- 'all instance attribute accessors share the same count',
20
- 'image/mimeType is image/jpeg or image/png',
21
- 'skin.joints.length <= MAX_JOINTS (256)',
22
- 'animation sampler interpolation is LINEAR or STEP',
23
- 'animation channel target path is one of translation, rotation, scale, or weights',
24
- 'every joint node has a non-empty name and belongs to an acyclic hierarchy',
25
- 'image bytes extractable from bufferView / data-URI / external URI without corruption',
26
- 'mesh primitive declares JOINTS_0 and WEIGHTS_0 symmetrically (both present or both absent)',
27
- 'every animation channel resolves to one uniquely named scene node and stable target ID',
28
- 'a required or compressed-only EXT_meshopt_compression bufferView has a ready decoder capability',
29
- 'the EXT_meshopt_compression declaration and decoder output are structurally valid',
30
- 'morph target and default-weight arrays are dense, bounded, and match the base vertex count',
31
- 'COLOR_0 dense accessor uses VEC3/VEC4 FLOAT or normalized UBYTE/USHORT',
32
- 'COLOR_0 accessor is non-empty, finite, in range, and fully addressable',
33
- 'a non-empty merged mesh with consistent morph and COLOR_0 cardinality',
34
- ] as const;
35
-
36
- const HINTS_IN_POLICY_ORDER = [
37
- 'verify .glb is not truncated; rerun: forgeax-engine-remote-gltf import <path>',
38
- 'asset.version must be "2.0"; v1 or v3 not supported',
39
- 'rebuild .gltf with valid bufferViews; check accessor index; ensure accessor.byteOffset + EFFECTIVE_STRIDE * (count - 1) + element_size <= bufferView.byteLength',
40
- 'see feat-future-gltf-extensions-allowlist; remove this extension or wait for the allowlist to expand',
41
- 'sparse: see feat-future-gltf-sparse-accessor; morph: see feat-future-gltf-morph; interleaved: see feat-future-gltf-mesh-multi-section',
42
- 'check sidecar meta.json + textures/ directory + vite-plugin-pack /__pack/lookup route',
43
- 'run: forgeax-engine-remote-gltf import <path>',
44
- 'EXT_mesh_gpu_instancing requires TRANSLATION/ROTATION/SCALE accessors to share count; see https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/EXT_mesh_gpu_instancing/README.md#extending-nodes-with-instance-attributes',
45
- 'convert to JPG/PNG via external tool; only image/jpeg and image/png are supported',
46
- 'reduce joint count below MAX_JOINTS (256) or see OOS-skin-max-joints',
47
- 'see OOS-skin-cubicspline; convert CUBICSPLINE to LINEAR/STEP in DCC tool',
48
- 'animation target path must be translation, rotation, scale, or weights',
49
- 'ensure every joint node has a non-empty name and the node hierarchy is acyclic',
50
- 'verify the bufferView byte range / data: URI base64 / external URI sibling file is intact next to the .gltf source; rerun: forgeax-engine-remote-gltf import <path>',
51
- 'glTF spec requires JOINTS_0 and WEIGHTS_0 to appear together for each skinned primitive; add the missing attribute or remove the present one in the DCC tool',
52
- 'name every node in the animated hierarchy and ensure each animated full path is unique',
53
- 'provide the build-only EXT_meshopt_compression decoder or author a valid core fallback bufferView',
54
- 'the meshopt decoder accepts the declared compressed range and produces the declared byte count',
55
- 're-export dense morph targets with at most eight targets/attributes and matching vertex/default-weight lengths',
56
- 're-export COLOR_0 with a supported type/component/normalized combination; morph and sparse COLOR_0 remain deferred',
57
- 'repair the COLOR_0 accessor count, reference, range, or buffer bounds, then re-import the glTF source',
58
- 'repair the source primitive and re-import; inspect detail.reason and its typed facts',
59
- ] as const;
60
-
61
- const policyErrors: readonly GltfError[] = [
62
- gltfErr('gltf-malformed-header', { filePath: 'model.glb', byteOffset: 0 }),
63
- gltfErr('gltf-version-unsupported', { filePath: 'model.gltf', actualVersion: '1.0' }),
64
- gltfErr('gltf-buffer-out-of-bounds', {
65
- accessor: 0,
66
- byteOffset: 0,
67
- byteLength: 4,
68
- bufferIndex: 0,
69
- }),
70
- gltfErr('gltf-extension-unsupported', {
71
- extension: 'KHR_x',
72
- source: 'extensionsRequired',
73
- }),
74
- gltfErr('gltf-accessor-type-mismatch', { accessorIndex: 0, reason: 'sparse' }),
75
- gltfErr('gltf-texture-load-failed', { uri: 'textures/test.png' }),
76
- gltfErr('gltf-meta-missing', {
77
- filePath: 'model.gltf',
78
- expectedMetaPath: 'model.gltf.meta.json',
79
- }),
80
- gltfErr('gltf-instancing-count-mismatch', {
81
- nodeIndex: 0,
82
- accessor: 'TRANSLATION',
83
- expectedCount: 2,
84
- actualCount: 3,
85
- }),
86
- gltfErr('gltf-image-mime-unsupported', { mimeType: 'image/bmp' }),
87
- gltfErr('gltf-skin-joint-count-exceeded', { skinIndex: 0, jointCount: 300, maxJoints: 256 }),
88
- gltfErr('gltf-animation-cubicspline-unsupported', { animationIndex: 0, samplerIndex: 1 }),
89
- gltfErr('gltf-morph-unsupported', { animationIndex: 0, channelIndex: 2, nodeIndex: 3 }),
90
- gltfErr('gltf-skin-joint-name-missing', {
91
- reason: 'name-missing',
92
- skinIndex: 0,
93
- jointPathIndex: 4,
94
- nodeIndex: 5,
95
- }),
96
- gltfErr('gltf-image-extract-failed', { imageIndex: 0, source: 'bufferView', reason: 'sample' }),
97
- gltfErr('gltf-skin-attr-asymmetric', {
98
- meshIndex: 0,
99
- primitiveIndex: 0,
100
- hasJoints: true,
101
- hasWeights: false,
102
- }),
103
- gltfErr('gltf-animation-target-invalid', {
104
- reason: 'name-missing',
105
- animationIndex: 0,
106
- channelIndex: 0,
107
- nodeIndex: 0,
108
- }),
109
- gltfErr('gltf-meshopt-decoder-required', {
110
- bufferView: 0,
111
- actual: 'required',
112
- hasCoreFallback: false,
113
- }),
114
- gltfErr('gltf-meshopt-decode-failed', {
115
- bufferView: 1,
116
- actual: 'decoded byte count mismatch',
117
- mode: 'ATTRIBUTES',
118
- filter: 'NONE',
119
- }),
120
- gltfErr('gltf-morph-invalid', {
121
- meshIndex: 0,
122
- primitiveIndex: 0,
123
- reason: 'target-count-exceeded',
124
- targetCount: 9,
125
- attributeCount: 1,
126
- vertexCount: 3,
127
- }),
128
- gltfErr('gltf-color-accessor-unsupported', {
129
- semantic: 'COLOR_0',
130
- accessorIndex: 0,
131
- reason: 'component',
132
- }),
133
- gltfErr('gltf-color-accessor-malformed', {
134
- semantic: 'COLOR_0',
135
- accessorIndex: 0,
136
- reason: 'bounds',
137
- }),
138
- gltfErr('gltf-mesh-bridge-invalid', { reason: 'empty-input', primitiveCount: 0 }),
139
- ];
140
-
141
- describe('glTF error policy owner', () => {
142
- it('projects one exact twenty-two-code policy surface with stable own-key order', () => {
143
- const codes = policyErrors.map(({ code }) => code);
144
-
145
- expect(codes).toHaveLength(22);
146
- expect(new Set(codes).size).toBe(22);
147
- expect(Object.keys(GLTF_ERROR_HINTS)).toEqual(codes);
148
- expect(Object.getOwnPropertyNames(GLTF_ERROR_HINTS)).toEqual(codes);
149
- expect(Object.values(GLTF_ERROR_HINTS)).toEqual(HINTS_IN_POLICY_ORDER);
150
-
151
- for (const code of codes) {
152
- expect(Object.prototype.propertyIsEnumerable.call(GLTF_ERROR_HINTS, code)).toBe(true);
153
- }
1
+ import { describe, expect, it } from 'vitest';
2
+ import { checkExtensions } from '../check-extensions.js';
3
+ import { gltfErr } from '../errors.js';
4
+
5
+ describe('glTF transmission error policy', () => {
6
+ it('keeps invalid material facts in a structured closed detail', () => {
7
+ const error = gltfErr('gltf-material-transmission-invalid', {
8
+ extension: 'KHR_materials_ior',
9
+ field: 'ior',
10
+ reason: 'range',
11
+ actual: 0,
12
+ });
13
+ expect(error).toMatchObject({
14
+ code: 'gltf-material-transmission-invalid',
15
+ detail: { extension: 'KHR_materials_ior', field: 'ior', reason: 'range', actual: 0 },
16
+ expected: expect.any(String),
17
+ hint: expect.any(String),
18
+ });
154
19
  });
155
20
 
156
- it('keeps every expected and hint string byte-identical through gltfErr', () => {
157
- for (const [index, error] of policyErrors.entries()) {
158
- expect(error.expected).toBe(EXPECTED_IN_POLICY_ORDER[index]);
159
- expect(error.hint).toBe(HINTS_IN_POLICY_ORDER[index]);
160
- expect(GLTF_ERROR_HINTS[error.code]).toBe(HINTS_IN_POLICY_ORDER[index]);
161
- expect(Object.keys(error)).toEqual(['code', 'expected', 'hint', 'detail']);
162
- }
21
+ it('admits supported KHR transmission extensionsRequired declarations', () => {
22
+ const result = checkExtensions({ extensionsRequired: ['KHR_materials_transmission'] });
23
+ expect(result).toEqual({ ok: true, value: { unsupportedUsed: [] } });
163
24
  });
164
25
 
165
- it('preserves the public hint type and representative detail narrowing', () => {
166
- expectTypeOf(GLTF_ERROR_HINTS).toEqualTypeOf<Readonly<Record<GltfErrorCode, string>>>();
167
-
168
- const versionError = gltfErr('gltf-version-unsupported', {
169
- filePath: 'model.gltf',
170
- actualVersion: '1.0',
171
- });
172
- expectTypeOf(versionError.detail).toEqualTypeOf<GltfVersionUnsupportedDetail>();
173
- expect(versionError.detail.actualVersion).toBe('1.0');
174
-
175
- const skinError = gltfErr('gltf-skin-attr-asymmetric', {
176
- meshIndex: 2,
177
- primitiveIndex: 1,
178
- hasJoints: true,
179
- hasWeights: false,
26
+ it('keeps unknown extensionsRequired declarations rejected', () => {
27
+ const result = checkExtensions({ extensionsRequired: ['KHR_materials_unlit'] });
28
+ expect(result).toMatchObject({
29
+ ok: false,
30
+ error: { code: 'gltf-extension-unsupported' },
180
31
  });
181
- expectTypeOf(skinError.detail).toEqualTypeOf<GltfSkinAttrAsymmetricDetail>();
182
- expect(skinError.detail.meshIndex).toBe(2);
183
- expect(skinError.detail.hasWeights).toBe(false);
184
32
  });
185
33
  });
@@ -278,6 +278,7 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
278
278
  'gltf-version-unsupported',
279
279
  'gltf-buffer-out-of-bounds',
280
280
  'gltf-extension-unsupported',
281
+ 'gltf-material-transmission-invalid',
281
282
  'gltf-accessor-type-mismatch',
282
283
  'gltf-texture-load-failed',
283
284
  'gltf-meta-missing',
@@ -308,6 +309,8 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
308
309
  return 'oob';
309
310
  case 'gltf-extension-unsupported':
310
311
  return 'ext';
312
+ case 'gltf-material-transmission-invalid':
313
+ return 'material-transmission-invalid';
311
314
  case 'gltf-accessor-type-mismatch':
312
315
  return 'accessor';
313
316
  case 'gltf-texture-load-failed':
@@ -357,6 +360,13 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
357
360
  return gltfErr(code, { accessor: 0, byteOffset: 0, byteLength: 0, bufferIndex: 0 });
358
361
  case 'gltf-extension-unsupported':
359
362
  return gltfErr(code, { extension: 'KHR_x', source: 'extensionsRequired' });
363
+ case 'gltf-material-transmission-invalid':
364
+ return gltfErr(code, {
365
+ extension: 'KHR_materials_transmission',
366
+ field: 'transmissionFactor',
367
+ reason: 'range',
368
+ actual: 2,
369
+ });
360
370
  case 'gltf-accessor-type-mismatch':
361
371
  return gltfErr(code, { accessorIndex: 0, reason: 'sparse' });
362
372
  case 'gltf-texture-load-failed':
@@ -446,8 +456,8 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
446
456
  });
447
457
 
448
458
  describe('GltfErrorCode roster', () => {
449
- it('GLTF_ERROR_HINTS exposes exactly 22 keys', () => {
450
- expect(Object.keys(GLTF_ERROR_HINTS).length).toBe(22);
459
+ it('GLTF_ERROR_HINTS exposes exactly 23 keys', () => {
460
+ expect(Object.keys(GLTF_ERROR_HINTS).length).toBe(23);
451
461
  });
452
462
 
453
463
  it.each(ALL_CODES)('hint for %s is a non-empty string', (code) => {
@@ -2016,7 +2026,7 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
2016
2026
  expect(EXTENSION_ALLOWLIST).toEqual(['EXT_mesh_gpu_instancing', 'EXT_meshopt_compression']);
2017
2027
  });
2018
2028
 
2019
- it('(a) rejects extensionsRequired entries outside the allowlist', () => {
2029
+ it('(a) rejects unsupported extensionsRequired entries', () => {
2020
2030
  const result = checkExtensions({
2021
2031
  extensionsRequired: ['KHR_materials_pbrSpecularGlossiness'],
2022
2032
  });
@@ -2029,7 +2039,9 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
2029
2039
  });
2030
2040
 
2031
2041
  it('(b) accepts extensionsUsed (not required) into diagnostics list with no stderr', () => {
2032
- const result = checkExtensions({ extensionsUsed: ['KHR_materials_pbrSpecularGlossiness'] });
2042
+ const result = checkExtensions({
2043
+ extensionsUsed: ['KHR_materials_pbrSpecularGlossiness', 'KHR_materials_transmission'],
2044
+ });
2033
2045
  expect(result.ok).toBe(true);
2034
2046
  if (!result.ok) return;
2035
2047
  expect(result.value.unsupportedUsed).toEqual(['KHR_materials_pbrSpecularGlossiness']);
@@ -2073,6 +2085,18 @@ function unwrapReimport(result: ReturnType<typeof reimportReuseMeta>) {
2073
2085
  expect(stderrSpy).not.toHaveBeenCalled();
2074
2086
  });
2075
2087
 
2088
+ it.each([
2089
+ 'KHR_materials_transmission',
2090
+ 'KHR_materials_ior',
2091
+ 'KHR_materials_volume',
2092
+ ])('%s in extensionsRequired routes ok (supported)', (extension) => {
2093
+ const result = checkExtensions({ extensionsRequired: [extension] });
2094
+ expect(result.ok).toBe(true);
2095
+ if (!result.ok) return;
2096
+ expect(result.value.unsupportedUsed).toEqual([]);
2097
+ expect(stderrSpy).not.toHaveBeenCalled();
2098
+ });
2099
+
2076
2100
  it('EXT_mesh_gpu_instancing in extensionsUsed (not required) routes ok with no warn', () => {
2077
2101
  const result = checkExtensions({ extensionsUsed: ['EXT_mesh_gpu_instancing'] });
2078
2102
  expect(result.ok).toBe(true);