@forgeax/engine-fbx 0.0.0-dev.8d955ade1c79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +188 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/__tests__/blendshape-import.integration.test.d.ts +2 -0
- package/dist/__tests__/blendshape-import.integration.test.d.ts.map +1 -0
- package/dist/__tests__/blendshape-import.unit.test.d.ts +2 -0
- package/dist/__tests__/blendshape-import.unit.test.d.ts.map +1 -0
- package/dist/__tests__/fbx-importer.test.d.ts +2 -0
- package/dist/__tests__/fbx-importer.test.d.ts.map +1 -0
- package/dist/__tests__/fbx-local-artifacts.test.d.ts +2 -0
- package/dist/__tests__/fbx-local-artifacts.test.d.ts.map +1 -0
- package/dist/__tests__/index.test.d.ts +2 -0
- package/dist/__tests__/index.test.d.ts.map +1 -0
- package/dist/__tests__/mesh-material-slots.unit.test.d.ts +2 -0
- package/dist/__tests__/mesh-material-slots.unit.test.d.ts.map +1 -0
- package/dist/__tests__/parse-mesh-multi-uv.test.d.ts +2 -0
- package/dist/__tests__/parse-mesh-multi-uv.test.d.ts.map +1 -0
- package/dist/__tests__/pick-e2e.integration.test.d.ts +2 -0
- package/dist/__tests__/pick-e2e.integration.test.d.ts.map +1 -0
- package/dist/__tests__/resolve-texture-path.unit.test.d.ts +2 -0
- package/dist/__tests__/resolve-texture-path.unit.test.d.ts.map +1 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/fbx-importer.d.ts +17 -0
- package/dist/fbx-importer.d.ts.map +1 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1499 -0
- package/dist/index.mjs.map +1 -0
- package/dist/parse-animation-clip.d.ts +35 -0
- package/dist/parse-animation-clip.d.ts.map +1 -0
- package/dist/parse-material.d.ts +24 -0
- package/dist/parse-material.d.ts.map +1 -0
- package/dist/parse-mesh.d.ts +21 -0
- package/dist/parse-mesh.d.ts.map +1 -0
- package/dist/parse-scene.d.ts +28 -0
- package/dist/parse-scene.d.ts.map +1 -0
- package/dist/parse-skeleton.d.ts +15 -0
- package/dist/parse-skeleton.d.ts.map +1 -0
- package/dist/parse-skin.d.ts +20 -0
- package/dist/parse-skin.d.ts.map +1 -0
- package/dist/parse-texture.d.ts +11 -0
- package/dist/parse-texture.d.ts.map +1 -0
- package/dist/resolve-texture-path.d.ts +25 -0
- package/dist/resolve-texture-path.d.ts.map +1 -0
- package/dist/to-asset-pack.d.ts +31 -0
- package/dist/to-asset-pack.d.ts.map +1 -0
- package/package.json +74 -0
- package/pkg/fbx-wasm.mjs +2 -0
- package/pkg/fbx-wasm.wasm +0 -0
- package/scripts/build-wasm.mjs +85 -0
- package/scripts/content-key.mjs +88 -0
- package/scripts/ensure-wasm.mjs +28 -0
- package/scripts/fetch-ufbx.mjs +42 -0
- package/scripts/fetch-wasm.mjs +91 -0
- package/scripts/parity-diff.mjs +127 -0
- package/scripts/test-wasm.mjs +91 -0
- package/src/__tests__/blendshape-import.integration.test.ts +90 -0
- package/src/__tests__/blendshape-import.unit.test.ts +83 -0
- package/src/__tests__/fbx-importer.test.ts +36 -0
- package/src/__tests__/fbx-local-artifacts.test.ts +39 -0
- package/src/__tests__/index.test.ts +168 -0
- package/src/__tests__/mesh-material-slots.unit.test.ts +125 -0
- package/src/__tests__/parse-mesh-multi-uv.test.ts +187 -0
- package/src/__tests__/pick-e2e.integration.test.ts +247 -0
- package/src/__tests__/resolve-texture-path.unit.test.ts +50 -0
- package/src/errors.ts +112 -0
- package/src/fbx-importer.ts +146 -0
- package/src/index.ts +215 -0
- package/src/native/bridge.c +942 -0
- package/src/parse-animation-clip.ts +271 -0
- package/src/parse-material.ts +92 -0
- package/src/parse-mesh.ts +223 -0
- package/src/parse-scene.ts +75 -0
- package/src/parse-skeleton.ts +46 -0
- package/src/parse-skin.ts +71 -0
- package/src/parse-texture.ts +22 -0
- package/src/resolve-texture-path.ts +152 -0
- package/src/to-asset-pack.ts +742 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/parse-scene.ts","../src/parse-animation-clip.ts","../src/parse-material.ts","../src/parse-mesh.ts","../src/parse-skeleton.ts","../src/parse-skin.ts","../src/parse-texture.ts","../../geometry/src/vertex-attribute-layout.ts","../../import/src/mesh-bin.ts","../src/to-asset-pack.ts","../src/fbx-importer.ts","../src/resolve-texture-path.ts","../src/index.ts"],"names":["err","MESH_BIN_HEADER_V4_BYTES","ok","n","AssetGuid","box3","deriveAnimationTargetId","guid"],"mappings":"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","file":"index.mjs","sourcesContent":["// errors.ts — FbxError definitions SSOT + factory.\n//\n// Per requirements AC-09 + plan-strategy D-5 (DIP), FbxErrorCode +\n// FbxErrorDetail + FbxError + the private error policy owner are the FBX\n// importer's own error SSOT, local to this package. Subsequent milestones\n// append per-section members as needed.\n//\n// Producers MUST go through `fbxErr` so any FbxErrorCode addition that\n// lacks a matching detail variant fails at the call site (TS exhaustive\n// per-arm).\n\nexport { err, ok, type Result } from '@forgeax/engine-types';\n\n// === FbxErrorCode — closed union SSOT ===\n\n/**\n * Closed `FbxErrorCode` union derived from the private `DetailFor` map below.\n * That map is the single code/detail authority for parser diagnostics; the\n * ufbx WASM parser needs no native-addon build step.\n *\n * Domain-separated from `ImportErrorCode` (importer dispatch surface in\n * @forgeax/engine-types) and `AssetErrorCode` (runtime registry surface).\n */\nexport type FbxErrorCode = keyof DetailFor;\n\n// === Per-code detail shapes ===\n\n/** `fbx-mesh-type-unsupported` payload: surface type + mesh name. */\nexport interface FbxMeshTypeUnsupportedDetail {\n readonly meshType: 'nurbs' | 'patch';\n readonly meshName: string;\n}\n\nexport type FbxAnimationTargetInvalidDetail =\n | {\n readonly reason: 'hierarchy-cycle';\n readonly nodeIndex: number;\n }\n | {\n readonly reason:\n | 'name-missing'\n | 'path-invalid'\n | 'path-duplicate'\n | 'path-not-found'\n | 'id-collision';\n readonly clipIndex: number;\n readonly channelIndex: number;\n readonly targetNode: string;\n };\n\n/** Discriminated detail family unifying all FbxError variants. */\nexport type FbxErrorDetail = DetailFor[FbxErrorCode];\n\n// === FbxError discriminated union ===\n\nexport type FbxError = {\n readonly [C in FbxErrorCode]: {\n readonly code: C;\n readonly expected: string;\n readonly hint: string;\n readonly detail: DetailFor[C];\n };\n}[FbxErrorCode];\n\n// === Private expected/hint policy owner + public hint projection ===\n\nconst fbxErrorPolicy = {\n 'fbx-mesh-type-unsupported': {\n expected: 'all meshes in the file are polygon (triangles/quads), not NURBS or patch surfaces',\n hint: 'NURBS and patch surfaces are not supported; convert to polygon mesh in a DCC tool before import',\n },\n 'fbx-animation-target-invalid': {\n expected:\n 'an acyclic hierarchy where every animation channel uniquely matches one named Scene node and stable target ID',\n hint: 'name every node, keep the hierarchy acyclic, and export unique full animation target paths',\n },\n} satisfies {\n readonly [Code in FbxErrorCode]: {\n readonly expected: string;\n readonly hint: string;\n };\n};\n\nexport const FBX_ERROR_HINTS: Readonly<Record<FbxErrorCode, string>> = Object.fromEntries(\n Object.entries(fbxErrorPolicy).map(([code, policy]) => [code, policy.hint]),\n) as Readonly<Record<FbxErrorCode, string>>;\n\n// === DetailFor map + fbxErr factory ===\n\ninterface DetailFor {\n readonly 'fbx-mesh-type-unsupported': FbxMeshTypeUnsupportedDetail;\n readonly 'fbx-animation-target-invalid': FbxAnimationTargetInvalidDetail;\n}\n\n/**\n * Build a fully-typed FbxError. The discriminated-union return type lets\n * call sites narrow with `switch (e.code)` on the result.\n *\n * Charter P3 explicit-failure: `expected` + `hint` fields are sourced from\n * the private policy owner — no producer can omit them.\n */\nexport function fbxErr<C extends FbxErrorCode>(\n code: C,\n detail: DetailFor[C],\n): Extract<FbxError, { readonly code: C }> {\n return {\n code,\n expected: fbxErrorPolicy[code].expected,\n hint: fbxErrorPolicy[code].hint,\n detail,\n } as Extract<FbxError, { readonly code: C }>;\n}\n","// parse-scene.ts — FBX JSON POD to ScenePod bridge (t29).\n\nimport type { SceneEntityPod, ScenePod } from '@forgeax/engine-types';\n\nexport interface FbxRawNode {\n readonly name: string;\n readonly transform: {\n readonly translation: [number, number, number];\n readonly rotation: [number, number, number, number];\n readonly scale: [number, number, number];\n };\n readonly meshIndex: number;\n readonly children: readonly number[];\n}\n\nexport interface FbxRawNodes {\n readonly nodes?: readonly FbxRawNode[];\n}\n\nexport type FbxNodePathResult =\n | { readonly ok: true; readonly value: readonly string[] }\n | {\n readonly ok: false;\n readonly reason: 'name-missing' | 'path-invalid' | 'hierarchy-cycle';\n readonly nodeIndex: number;\n };\n\nexport function buildFbxNodePaths(\n nodes: readonly { readonly name?: string; readonly children?: readonly number[] }[],\n): readonly FbxNodePathResult[] {\n const parents = new Map<number, number>();\n for (let index = 0; index < nodes.length; index++) {\n for (const child of nodes[index]?.children ?? []) parents.set(child, index);\n }\n return nodes.map((_, index) => {\n const reversed: string[] = [];\n const visited = new Set<number>();\n let current: number | undefined = index;\n while (current !== undefined) {\n if (visited.has(current)) {\n return { ok: false, reason: 'hierarchy-cycle', nodeIndex: current };\n }\n visited.add(current);\n const name = nodes[current]?.name;\n if (name === undefined || name.length === 0) {\n return { ok: false, reason: 'name-missing', nodeIndex: current };\n }\n if (name.includes('/')) {\n return { ok: false, reason: 'path-invalid', nodeIndex: current };\n }\n reversed.push(name);\n current = parents.get(current);\n }\n return { ok: true, value: reversed.reverse() };\n });\n}\n\nexport function parseScene(rawNodes: FbxRawNodes): ScenePod {\n const nodes = rawNodes.nodes ?? [];\n const entities: SceneEntityPod[] = nodes.map((n) => ({\n name: n.name,\n transform: {\n translation: n.transform.translation,\n rotation: n.transform.rotation,\n scale: n.transform.scale,\n },\n meshIndex: n.meshIndex >= 0 ? n.meshIndex : null,\n children: n.children,\n }));\n\n return {\n entities,\n rootEntityIndex: 0,\n };\n}\n","// parse-animation-clip.ts — M5 t50: TS bridge for animation clip POD data.\n//\n// Consumes the C++ JSON POD clips section emitted by binding.cc\n// (WriteAnimationData), linear-resamples each channel to a fixed fps,\n// produces AnimationClipPod (types SSOT per requirements AC-07).\n//\n// Input schema (from JSON.parse of binding output) — flat per-channel timeline:\n// clips?: [{\n// name?: string,\n// duration: number,\n// channels: [{\n// targetNode: string,\n// property: 'translation'|'rotation'|'scale'|'weights',\n// keyTimes: number[], // ascending, seconds\n// keyValues: number[], // interleaved, stride 3/4 or weightCount\n// weightCount?: number, // required for 'weights'\n// }],\n// }]\n//\n// The binding emits rotation as a real unit quaternion sampled from\n// node->EvaluateLocalTransform(t).GetQ() (NOT raw euler-degree curves), so the\n// bridge only resamples + re-normalizes; it never euler-converts.\n//\n// Processing:\n// linear resample: evaluate the strided keyValues at each framestep (1/fps)\n// rotation: per-component lerp then normalize (nlerp); runtime slerps further\n// output: AnimationClipPod.channels[].sampler.{input,output,interpolation:LINEAR}\n\nimport { deriveAnimationTargetId } from '@forgeax/engine-animation/target-id';\nimport type {\n AnimationChannelPod,\n AnimationClipPod,\n AnimationSamplerPod,\n} from '@forgeax/engine-types';\nimport { err, type FbxError, fbxErr, ok, type Result } from './errors.js';\nimport { buildFbxNodePaths } from './parse-scene.js';\n\nexport interface FbxRawAnimChannel {\n readonly targetNode: string;\n readonly property: 'translation' | 'rotation' | 'scale' | 'weights';\n /** Ascending key timestamps in seconds. */\n readonly keyTimes?: number[];\n /** Interleaved key values, stride 3/4 or weightCount for morph weights. */\n readonly keyValues?: number[];\n /** Number of morph weight elements in each sampled key. */\n readonly weightCount?: number;\n}\n\nexport interface FbxRawClip {\n readonly name?: string;\n readonly duration: number;\n readonly channels: readonly FbxRawAnimChannel[];\n}\n\nexport interface FbxRawAnimDoc {\n readonly clips?: readonly FbxRawClip[];\n}\n\nconst DEFAULT_FPS = 30;\n\n/**\n * Linear-interpolate a strided keyValues stream at time t into `out`.\n *\n * keyTimes is ascending; keyValues holds `stride` floats per key. Clamps to\n * the first/last key outside the range. For rotation (stride 4) the result is\n * a per-component lerp; the caller normalizes it (nlerp) — runtime playback\n * slerps further, so import-time nlerp is sufficient to keep unit length.\n */\nfunction sampleStrided(\n keyTimes: readonly number[],\n keyValues: readonly number[],\n stride: number,\n t: number,\n out: number[],\n rotation: boolean,\n): void {\n const n = keyTimes.length;\n if (n === 0) {\n for (let c = 0; c < stride; c++) out[c] = rotation && c === 3 ? 1 : 0;\n return;\n }\n const first = keyTimes[0] as number;\n const lastIdx = n - 1;\n const last = keyTimes[lastIdx] as number;\n if (t <= first) {\n for (let c = 0; c < stride; c++) out[c] = keyValues[c] ?? 0;\n return;\n }\n if (t >= last) {\n for (let c = 0; c < stride; c++) out[c] = keyValues[lastIdx * stride + c] ?? 0;\n return;\n }\n // Find bracket [i-1, i].\n let i = 1;\n while (i < n && (keyTimes[i] as number) < t) i++;\n const t0 = keyTimes[i - 1] as number;\n const t1 = keyTimes[i] as number;\n const frac = t1 > t0 ? (t - t0) / (t1 - t0) : 0;\n const b0 = (i - 1) * stride;\n const b1 = i * stride;\n for (let c = 0; c < stride; c++) {\n const v0 = keyValues[b0 + c] ?? 0;\n const v1 = keyValues[b1 + c] ?? 0;\n out[c] = v0 + (v1 - v0) * frac;\n }\n}\n\n/**\n * Build a per-frame sampler for one channel: resample the flat strided\n * keyValues onto a uniform timeline at the given fps. Rotation channels are\n * re-normalized per frame so the lerp output stays a unit quaternion.\n */\nfunction buildSampler(ch: FbxRawAnimChannel, duration: number, fps: number): AnimationSamplerPod {\n const frameInterval = 1 / fps;\n const frameCount = Math.floor(duration * fps) + 1;\n\n const input = new Float32Array(frameCount);\n for (let f = 0; f < frameCount; f++) {\n input[f] = f * frameInterval;\n }\n\n const stride =\n ch.property === 'rotation' ? 4 : ch.property === 'weights' ? (ch.weightCount ?? 0) : 3;\n if (ch.property === 'weights' && (!Number.isInteger(stride) || stride < 1 || stride > 8)) {\n throw new Error('fbx-morph-invalid: weight channel count must be an integer in [1, 8]');\n }\n const output = new Float32Array(frameCount * stride);\n\n const keyTimes = ch.keyTimes ?? [];\n const keyValues = ch.keyValues ?? [];\n if (keyTimes.length > 0 && keyValues.length !== keyTimes.length * stride) {\n throw new Error('fbx-morph-invalid: animation key value width does not match key times');\n }\n const tmp = new Array<number>(stride);\n\n for (let f = 0; f < frameCount; f++) {\n const t = input[f] as number;\n sampleStrided(keyTimes, keyValues, stride, t, tmp, ch.property === 'rotation');\n const base = f * stride;\n if (ch.property === 'rotation') {\n const len = Math.hypot(tmp[0] ?? 0, tmp[1] ?? 0, tmp[2] ?? 0, tmp[3] ?? 0);\n const inv = len > 0 ? 1 / len : 0;\n output[base + 0] = (tmp[0] ?? 0) * inv;\n output[base + 1] = (tmp[1] ?? 0) * inv;\n output[base + 2] = (tmp[2] ?? 0) * inv;\n output[base + 3] = len > 0 ? (tmp[3] ?? 0) * inv : 1;\n } else {\n for (let c = 0; c < stride; c++) output[base + c] = tmp[c] ?? 0;\n }\n }\n\n return { input, output, interpolation: 'LINEAR' };\n}\n\nfunction buildChannel(ch: FbxRawAnimChannel, duration: number, fps: number): AnimationChannelPod {\n return {\n targetId: deriveAnimationTargetId(ch.targetNode.split('/')),\n property: ch.property,\n sampler: buildSampler(ch, duration, fps),\n };\n}\n\ninterface FbxAnimationNode {\n readonly name: string;\n readonly children: readonly number[];\n}\n\nexport function resolveAnimationTargetIds(\n nodes: readonly FbxAnimationNode[],\n clips: readonly FbxRawClip[],\n): Result<void, FbxError> {\n const nodesByPath = new Map<string, number[]>();\n const nodePaths = buildFbxNodePaths(nodes);\n const cycle = nodePaths.find((path) => !path.ok && path.reason === 'hierarchy-cycle');\n if (cycle && !cycle.ok) {\n return err(\n fbxErr('fbx-animation-target-invalid', {\n reason: 'hierarchy-cycle',\n nodeIndex: cycle.nodeIndex,\n }),\n );\n }\n const hasAmbiguousName = nodePaths.some((path) => !path.ok);\n for (let index = 0; index < nodePaths.length; index++) {\n const result = nodePaths[index];\n if (result === undefined || !result.ok) continue;\n const path = result.value.join('/');\n const matches = nodesByPath.get(path) ?? [];\n matches.push(index);\n nodesByPath.set(path, matches);\n }\n\n const pathById = new Map<string, string>();\n for (let clipIndex = 0; clipIndex < clips.length; clipIndex++) {\n const clip = clips[clipIndex];\n if (clip === undefined) continue;\n for (let channelIndex = 0; channelIndex < clip.channels.length; channelIndex++) {\n const channel = clip.channels[channelIndex];\n if (channel === undefined) continue;\n const segments = channel.targetNode.split('/');\n if (segments.some((segment) => segment.length === 0)) {\n return err(\n fbxErr('fbx-animation-target-invalid', {\n reason: 'path-invalid',\n clipIndex,\n channelIndex,\n targetNode: channel.targetNode,\n }),\n );\n }\n const matches = nodesByPath.get(channel.targetNode);\n if (matches === undefined) {\n return err(\n fbxErr('fbx-animation-target-invalid', {\n reason: hasAmbiguousName ? 'name-missing' : 'path-not-found',\n clipIndex,\n channelIndex,\n targetNode: channel.targetNode,\n }),\n );\n }\n if (matches.length !== 1) {\n return err(\n fbxErr('fbx-animation-target-invalid', {\n reason: 'path-duplicate',\n clipIndex,\n channelIndex,\n targetNode: channel.targetNode,\n }),\n );\n }\n const id = deriveAnimationTargetId(segments);\n const previous = pathById.get(id);\n if (previous !== undefined && previous !== channel.targetNode) {\n return err(\n fbxErr('fbx-animation-target-invalid', {\n reason: 'id-collision',\n clipIndex,\n channelIndex,\n targetNode: channel.targetNode,\n }),\n );\n }\n pathById.set(id, channel.targetNode);\n }\n }\n return ok(undefined);\n}\n\n/**\n * Parse animation clips from a C++ JSON POD document.\n * Performs merge-keys + linear resample at the requested fps\n * (default 30). OOS-9: Hermite tangent data is discarded.\n *\n * Returns an empty array when the document has no clip data.\n */\nexport function parseAnimationClips(\n doc: FbxRawAnimDoc,\n fps: number = DEFAULT_FPS,\n): AnimationClipPod[] {\n const clips = doc.clips;\n if (!clips || clips.length === 0) return [];\n\n return clips.map((clip): AnimationClipPod => {\n return {\n ...(clip.name !== undefined && { name: clip.name }),\n duration: clip.duration,\n channels: clip.channels.map((ch) => buildChannel(ch, clip.duration, fps)),\n };\n });\n}\n","// parse-material.ts — FBX JSON POD to MaterialPod bridge (t40).\n//\n// Material mapping priority (plan-strategy §D-3):\n// 1. StingrayPBS → channels mapped directly (baseColor/metallic/roughness)\n// 2. Phong → Family A formula: roughness = 1 - sqrt(shininess/100)\n// baseColor = diffuse, metallic = 0\n// 3. Lambert → same formula as Phong (max_gloss=100 default)\n// 4. Fallback → default grey PBR: baseColor=[0.5,0.5,0.5], metal=0, rough=0.5\n\nimport type { MaterialPod } from '@forgeax/engine-types';\n\n/** JSON shape emitted by binding.cc WriteMaterials for a single material. */\nexport interface FbxRawMaterial {\n readonly name?: string;\n readonly kind: 'stingray-pbs' | 'phong' | 'lambert' | 'fallback';\n readonly baseColor?: readonly [number, number, number];\n readonly diffuse?: readonly [number, number, number];\n readonly shininess?: number;\n readonly specular?: readonly [number, number, number];\n readonly stingrayProps?: {\n readonly baseColor?: readonly [number, number, number];\n readonly metallic?: number;\n readonly roughness?: number;\n readonly emissive?: readonly [number, number, number];\n };\n}\n\nfunction clamp(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v;\n}\n\n/** Family A formula: roughness = 1 - sqrt(shininess / maxGloss), clamped [0, 1]. */\nfunction phongRoughness(shininess: number, maxGloss = 100): number {\n return clamp(1 - Math.sqrt(shininess / maxGloss), 0, 1);\n}\n\n/**\n * Parse a single FBX raw material JSON node into a MaterialPod.\n *\n * The caller (fbx-importer.ts) iterates the top-level `materials` array\n * from the C++ binding JSON output.\n */\nexport function parseMaterial(raw: FbxRawMaterial, sourceIndex: number): MaterialPod {\n void sourceIndex; // reserved for future cross-referencing\n\n switch (raw.kind) {\n case 'stingray-pbs': {\n const sp = raw.stingrayProps ?? {};\n return {\n ...(raw.name !== undefined && { name: raw.name }),\n baseColorFactor: [\n sp.baseColor?.[0] ?? 0.5,\n sp.baseColor?.[1] ?? 0.5,\n sp.baseColor?.[2] ?? 0.5,\n 1,\n ],\n metallicFactor: sp.metallic ?? 0,\n roughnessFactor: sp.roughness ?? 0.5,\n };\n }\n\n case 'phong': {\n const d = raw.diffuse ?? raw.baseColor ?? [0.5, 0.5, 0.5];\n const gloss = raw.shininess ?? 100;\n return {\n ...(raw.name !== undefined && { name: raw.name }),\n baseColorFactor: [d[0] ?? 0.5, d[1] ?? 0.5, d[2] ?? 0.5, 1],\n metallicFactor: 0,\n roughnessFactor: phongRoughness(gloss),\n };\n }\n\n case 'lambert': {\n const d = raw.diffuse ?? raw.baseColor ?? [0.5, 0.5, 0.5];\n return {\n ...(raw.name !== undefined && { name: raw.name }),\n baseColorFactor: [d[0] ?? 0.5, d[1] ?? 0.5, d[2] ?? 0.5, 1],\n metallicFactor: 0,\n roughnessFactor: 0.5, // lambert has no specular → default roughness\n };\n }\n\n default: {\n // fallback: no recognized material type\n return {\n baseColorFactor: [0.5, 0.5, 0.5, 1],\n metallicFactor: 0,\n roughnessFactor: 0.5,\n };\n }\n }\n}\n","// parse-mesh.ts — FBX JSON POD to MeshPod bridge (t28).\n\nimport type { MeshPod, MorphTarget } from '@forgeax/engine-types';\n\nconst MORPH_MAX_TARGETS = 8;\nconst MORPH_MAX_ATTRIBUTES = 8;\n\nexport interface FbxRawMesh {\n readonly name?: string;\n readonly vertices: number[];\n readonly indices?: number[];\n readonly attributes: Record<string, number[]>;\n readonly polygonCount: number;\n readonly sourceIndex: number;\n readonly materialIndex: number;\n readonly morphTargets?: readonly {\n readonly position?: number[];\n readonly normal?: number[];\n readonly tangent?: number[];\n }[];\n readonly morphWeights?: number[];\n}\n\nexport interface FbxRawDocument {\n readonly meshes?: readonly FbxRawMesh[];\n}\n\n// feat-20260629-multi-uv-set-support m1-w6: TEXCOORD key prefix for attribute\n// naming. Used by both parse-mesh (de-index path) and to-asset-pack (consumer).\nconst TEXCOORD_PREFIX = 'TEXCOORD_';\n\n// FBX maps positions per control-point but normals / UVs per polygon-vertex\n// (per index corner). When an attribute's element count equals the index count\n// (and not the position count), it is corner-mapped and must be de-indexed:\n// expand to one vertex per corner so positions / normals / uvs stay parallel\n// (the layout buildMeshAsset and the engine vertex buffer assume). A glTF-style\n// mesh (attributes already per-vertex) skips this path untouched.\nfunction isCornerMapped(\n attrLen: number,\n components: number,\n posCount: number,\n idxCount: number,\n): boolean {\n const elems = attrLen / components;\n return idxCount > 0 && elems === idxCount && elems !== posCount;\n}\n\nexport function parseMesh(raw: FbxRawMesh, sourceIndex: number): MeshPod {\n const rawIndices = raw.indices && raw.indices.length > 0 ? raw.indices : undefined;\n const posCount = raw.vertices.length / 3;\n const idxCount = rawIndices?.length ?? 0;\n const normal = raw.attributes.NORMAL;\n const rawMorphTargets = raw.morphTargets ?? [];\n const morphAttributeCount = rawMorphTargets.reduce(\n (count, target) =>\n count + (target.position ? 1 : 0) + (target.normal ? 1 : 0) + (target.tangent ? 1 : 0),\n 0,\n );\n if (rawMorphTargets.length > MORPH_MAX_TARGETS || morphAttributeCount > MORPH_MAX_ATTRIBUTES) {\n throw new Error('fbx-morph-invalid: morph target or attribute limit exceeded');\n }\n if (\n rawMorphTargets.some(\n (target) =>\n target.position === undefined &&\n target.normal === undefined &&\n target.tangent === undefined,\n )\n ) {\n throw new Error('fbx-morph-invalid: every target must contain POSITION, NORMAL, or TANGENT');\n }\n const morphTargets = rawMorphTargets.map((target): MorphTarget => {\n const out: {\n position?: Float32Array;\n normal?: Float32Array;\n tangent?: Float32Array;\n } = {};\n for (const [key, values, components] of [\n ['position', target.position, 3],\n ['normal', target.normal, 3],\n ['tangent', target.tangent, 4],\n ] as const) {\n if (values === undefined) continue;\n if (values.length !== posCount * components) {\n throw new Error(`fbx-morph-invalid: ${key} length does not match vertex count`);\n }\n out[key] = new Float32Array(values);\n }\n return out;\n });\n if (raw.morphWeights !== undefined && raw.morphWeights.length !== morphTargets.length) {\n throw new Error('fbx-morph-invalid: default weight count does not match target count');\n }\n\n // Determine if any attribute is corner-mapped (NORMAL or any TEXCOORD_n).\n const normalCorner = normal !== undefined && isCornerMapped(normal.length, 3, posCount, idxCount);\n const uvCornerMap = new Map<string, boolean>();\n for (const key of Object.keys(raw.attributes)) {\n if (key.startsWith(TEXCOORD_PREFIX)) {\n const arr = raw.attributes[key];\n if (arr !== undefined && isCornerMapped(arr.length, 2, posCount, idxCount)) {\n uvCornerMap.set(key, true);\n }\n }\n }\n const hasAnyCorner = normalCorner || uvCornerMap.size > 0;\n\n if (rawIndices !== undefined && hasAnyCorner) {\n // De-index: one expanded vertex per corner. Position pulled through the\n // index; corner-mapped attributes copied straight; per-vertex attributes\n // gathered through the index. New index buffer is the identity sequence.\n const expandedPos = new Float32Array(idxCount * 3);\n const expandedNormal = normal !== undefined ? new Float32Array(idxCount * 3) : undefined;\n // feat-20260629-multi-uv-set-support m1-w6: expand all TEXCOORD_n sets.\n const expandedUvs = new Map<string, Float32Array>();\n for (const key of Object.keys(raw.attributes)) {\n if (key.startsWith(TEXCOORD_PREFIX)) {\n expandedUvs.set(key, new Float32Array(idxCount * 2));\n }\n }\n const expandedMorphTargets = morphTargets.map((target) => {\n const expanded: {\n position?: Float32Array;\n normal?: Float32Array;\n tangent?: Float32Array;\n } = {};\n for (const [key, values, components] of [\n ['position', target.position, 3],\n ['normal', target.normal, 3],\n ['tangent', target.tangent, 4],\n ] as const) {\n if (values === undefined) continue;\n const output = new Float32Array(idxCount * components);\n for (let corner = 0; corner < idxCount; corner++) {\n const vi = rawIndices[corner] ?? 0;\n for (let component = 0; component < components; component++) {\n output[corner * components + component] = values[vi * components + component] ?? 0;\n }\n }\n expanded[key] = output;\n }\n return expanded;\n });\n for (let corner = 0; corner < idxCount; corner++) {\n const vi = rawIndices[corner] ?? 0;\n expandedPos[corner * 3 + 0] = raw.vertices[vi * 3 + 0] ?? 0;\n expandedPos[corner * 3 + 1] = raw.vertices[vi * 3 + 1] ?? 0;\n expandedPos[corner * 3 + 2] = raw.vertices[vi * 3 + 2] ?? 0;\n if (normal !== undefined && expandedNormal !== undefined) {\n const src = normalCorner ? corner : vi;\n expandedNormal[corner * 3 + 0] = normal[src * 3 + 0] ?? 0;\n expandedNormal[corner * 3 + 1] = normal[src * 3 + 1] ?? 0;\n expandedNormal[corner * 3 + 2] = normal[src * 3 + 2] ?? 0;\n }\n for (const [key, expanded] of expandedUvs) {\n const srcArr = raw.attributes[key];\n if (srcArr !== undefined) {\n const src = uvCornerMap.get(key) ? corner : vi;\n expanded[corner * 2 + 0] = srcArr[src * 2 + 0] ?? 0;\n expanded[corner * 2 + 1] = srcArr[src * 2 + 1] ?? 0;\n }\n }\n }\n const identity = new Uint32Array(idxCount);\n for (let i = 0; i < idxCount; i++) identity[i] = i;\n const expandedAttrs: Record<string, Float32Array> = {};\n if (expandedNormal !== undefined) expandedAttrs.NORMAL = expandedNormal;\n for (const [key, val] of expandedUvs) {\n expandedAttrs[key] = val;\n }\n return {\n ...(raw.name !== undefined ? { name: raw.name } : {}),\n vertices: expandedPos,\n indices: identity,\n attributes: expandedAttrs,\n submeshes: [\n {\n topology: 'triangle-list' as const,\n indexOffset: 0,\n indexCount: idxCount,\n vertexCount: idxCount,\n materialIndex: raw.materialIndex >= 0 ? raw.materialIndex : null,\n },\n ],\n sourceIndex,\n ...(expandedMorphTargets.length === 0 ? {} : { morphTargets: expandedMorphTargets }),\n ...(raw.morphWeights === undefined\n ? {}\n : { morphWeights: new Float32Array(raw.morphWeights) }),\n };\n }\n\n const vertices = new Float32Array(raw.vertices);\n const indices = rawIndices ? new Uint16Array(rawIndices) : undefined;\n\n const attributes: Record<string, Float32Array | Uint16Array | Uint32Array> = {};\n for (const [key, arr] of Object.entries(raw.attributes)) {\n attributes[key] = new Float32Array(arr);\n }\n\n const indexCount = indices?.length ?? 0;\n\n const submeshes = [\n {\n topology: 'triangle-list' as const,\n indexOffset: 0,\n indexCount,\n vertexCount: vertices.length / 3,\n materialIndex: raw.materialIndex >= 0 ? raw.materialIndex : null,\n },\n ];\n\n return {\n ...(raw.name !== undefined ? { name: raw.name } : {}),\n vertices,\n ...(indices ? { indices } : {}),\n attributes,\n submeshes,\n sourceIndex,\n ...(morphTargets.length === 0 ? {} : { morphTargets }),\n ...(raw.morphWeights === undefined ? {} : { morphWeights: new Float32Array(raw.morphWeights) }),\n };\n}\n","// parse-skeleton.ts — M5 t48: TS bridge for skeleton POD data.\n//\n// Consumes the C++ JSON POD skeleton section emitted by t45 binding.cc\n// (WriteSkeletonData), produces SkeletonPod (types SSOT per requirements AC-05).\n//\n// Input schema (from JSON.parse of binding output):\n// skeletons?: [{\n// jointCount: number,\n// inverseBindMatrices: number[], // jointCount * 16 packed doubles\n// jointPaths: string[],\n// }]\n//\n// Output: SkeletonPod { jointCount, inverseBindMatrices: Float32Array, jointPaths }\n\nimport type { SkeletonPod } from '@forgeax/engine-types';\n\nexport interface FbxRawSkeleton {\n readonly jointCount: number;\n readonly inverseBindMatrices: number[];\n readonly jointPaths: string[];\n}\n\nexport interface FbxRawSkeletonDoc {\n readonly skeletons?: readonly FbxRawSkeleton[];\n}\n\n/**\n * Parse the first skeleton from a C++ JSON POD document.\n * Returns an empty skeleton when the document has no skeleton data.\n */\nexport function parseSkeleton(doc: FbxRawSkeletonDoc): SkeletonPod {\n const skeletons = doc.skeletons;\n if (!skeletons || skeletons.length === 0) {\n return { jointCount: 0, inverseBindMatrices: new Float32Array(0), jointPaths: [] };\n }\n\n const skel = skeletons[0];\n if (!skel) {\n return { jointCount: 0, inverseBindMatrices: new Float32Array(0), jointPaths: [] };\n }\n return {\n jointCount: skel.jointCount,\n inverseBindMatrices: new Float32Array(skel.inverseBindMatrices),\n jointPaths: [...skel.jointPaths],\n };\n}\n","// parse-skin.ts — M5 t49: TS bridge for skin POD data.\n//\n// Consumes the C++ JSON POD skin section emitted by t45 binding.cc\n// (WriteSkinData), produces SkinPod (types SSOT per requirements AC-06).\n//\n// Input schema (from JSON.parse of binding output):\n// skins?: [{\n// meshSourceIndex: number,\n// jointPaths: string[],\n// vertexCount: number,\n// influences: [{ jointIndices: number[], jointWeights: number[] }],\n// }]\n//\n// Output: SkinPod { skeletonGuid, jointPaths, vertexCount, influences }\n\nimport type { SkinPod, SkinVertexInfluencePod } from '@forgeax/engine-types';\n\nexport interface FbxRawSkinInfluence {\n readonly jointIndices: number[];\n readonly jointWeights: number[];\n}\n\nexport interface FbxRawSkin {\n readonly meshSourceIndex: number;\n readonly jointPaths: string[];\n readonly vertexCount: number;\n readonly influences: readonly FbxRawSkinInfluence[];\n}\n\nexport interface FbxRawSkinDoc {\n readonly skins?: readonly FbxRawSkin[];\n}\n\nfunction bridgeSkeletonGuid(_jointPaths: readonly string[]): string {\n // Deterministic GUID from joint paths. Real GUID assignment happens\n // at import-runner time; this is a placeholder bridge identifier.\n return 'fbx-skeleton-000000000000';\n}\n\nfunction toInfluence(raw: FbxRawSkinInfluence): SkinVertexInfluencePod {\n // Pad to exactly 4 entries\n const ji = new Uint16Array(4);\n const jw = new Float32Array(4);\n for (let i = 0; i < 4; i++) {\n ji[i] = raw.jointIndices[i] ?? 0;\n jw[i] = raw.jointWeights[i] ?? 0;\n }\n return { jointIndices: ji, jointWeights: jw };\n}\n\n/**\n * Parse the first skin from a C++ JSON POD document.\n * Returns an empty skin when the document has no skin data.\n */\nexport function parseSkin(doc: FbxRawSkinDoc): SkinPod {\n const skins = doc.skins;\n if (!skins || skins.length === 0) {\n return { skeletonGuid: '', jointPaths: [], vertexCount: 0, influences: [] };\n }\n\n const skin = skins[0];\n if (!skin) {\n return { skeletonGuid: '', jointPaths: [], vertexCount: 0, influences: [] };\n }\n return {\n skeletonGuid: bridgeSkeletonGuid(skin.jointPaths),\n jointPaths: [...skin.jointPaths],\n vertexCount: skin.vertexCount,\n influences: skin.influences.map(toInfluence),\n };\n}\n","// parse-texture.ts — FBX JSON POD to TexturePod bridge (t30).\n\nimport type { TexturePod } from '@forgeax/engine-types';\n\nexport interface FbxRawTexture {\n readonly name?: string;\n readonly filePath: string;\n readonly sourceIndex: number;\n}\n\nexport interface FbxRawTextures {\n readonly textures?: readonly FbxRawTexture[];\n}\n\nexport function parseTextures(raw: FbxRawTextures): TexturePod[] {\n const textures = raw.textures ?? [];\n return textures.map((t) => ({\n name: t.name ?? t.filePath,\n filePath: t.filePath,\n sourceIndex: t.sourceIndex,\n }));\n}\n","// @forgeax/engine-runtime - Vertex attribute layout SSOT (14-key closed set\n// to GPUVertexBufferLayout derived function).\n//\n// deriveVertexBufferLayout(map, opts?) consumes a partial VertexAttributeMap and produces\n// a fixed-order array of GPUVertexBufferLayout entries — the single source of\n// truth for @location(N) assignment + GPUVertexFormat for every attribute the\n// engine pipeline can consume. Shader WGSL @location(N) declarations and\n// geometry factories are consumers of this SSOT; naga reflection deep-equal\n// tests (T-33 dawn-only) keep them in sync (AC-26 / plan-strategy D-7).\n//\n// Canonical interleaved order (plan-strategy F-1, must match bridge + import layers):\n// position / normal / uv / tangent / skinIndex / skinWeight / uv1..uv7 / color\n//\n// Key index (plan-strategy D-4 / D-7):\n// 0: position -> @location(0) float32x3\n// 1: normal -> @location(1) float32x3\n// 2: uv -> @location(2) float32x2 (set 0)\n// 3: tangent -> @location(3) float32x4\n// 4: skinIndex -> @location(4) uint16x4\n// 5: skinWeight -> @location(5) float32x4\n// 6: uv1 -> @location(6) float32x2 (set 1, fea-20260629 D-4)\n// 7: uv2 -> @location(7) float32x2 (set 2)\n// 8: uv3 -> @location(8) float32x2 (set 3)\n// 9: uv4 -> @location(9) float32x2 (set 4)\n// 10: uv5 -> @location(10) float32x2 (set 5)\n// 11: uv6 -> @location(11) float32x2 (set 6)\n// 12: uv7 -> @location(12) float32x2 (set 7)\n//\n// feat-20260523-skin-skeleton-animation M2 / T-22.\n// feat-20260629-multi-uv-set-support m3-w4: uv1..uv7 + clamp-to-last alias (D-1).\n\nimport {\n ASSET_ERROR_HINTS,\n AssetError,\n countUvSets,\n err,\n ok,\n type Result,\n type VertexAttributeMap,\n type VertexAttributePackDetail,\n type VertexAttributeStorage,\n} from '@forgeax/engine-types';\n\nconst ATTRIBUTE_FORMAT_MAP = {\n position: 'float32x3' as const,\n normal: 'float32x3' as const,\n uv: 'float32x2' as const,\n tangent: 'float32x4' as const,\n skinIndex: 'uint16x4' as const,\n skinWeight: 'float32x4' as const,\n uv1: 'float32x2' as const,\n uv2: 'float32x2' as const,\n uv3: 'float32x2' as const,\n uv4: 'float32x2' as const,\n uv5: 'float32x2' as const,\n uv6: 'float32x2' as const,\n uv7: 'float32x2' as const,\n color: 'float32x4' as const,\n} as const;\n\ntype AttributeKey = keyof typeof ATTRIBUTE_FORMAT_MAP;\n\nconst ATTRIBUTE_BYTE_STRIDE: Record<AttributeKey, number> = {\n position: 12,\n normal: 12,\n uv: 8,\n tangent: 16,\n skinIndex: 8,\n skinWeight: 16,\n uv1: 8,\n uv2: 8,\n uv3: 8,\n uv4: 8,\n uv5: 8,\n uv6: 8,\n uv7: 8,\n color: 16,\n};\n\nexport interface GpuVertexBufferLayoutEntry {\n readonly arrayStride: number;\n readonly attributes: ReadonlyArray<{\n readonly shaderLocation: number;\n readonly offset: number;\n readonly format: string;\n }>;\n readonly stepMode?: 'vertex' | 'instance' | undefined;\n}\n\nconst isAttributeKey = (key: string): key is AttributeKey => key in ATTRIBUTE_FORMAT_MAP;\n\nconst CANONICAL_KEYS: readonly AttributeKey[] =\n Object.keys(ATTRIBUTE_FORMAT_MAP).filter(isAttributeKey);\nconst UV_KEYS: readonly AttributeKey[] = CANONICAL_KEYS.filter(\n (key) => key === 'uv' || key.startsWith('uv'),\n);\n\ntype Entry = {\n readonly key: AttributeKey;\n readonly shaderLocation: number;\n readonly offset: number;\n readonly format: string;\n};\n\nfunction emitAliasEntries(\n entries: Entry[],\n fromIndex: number,\n toIndex: number,\n aliasOffset: number,\n currentStride: number,\n): number {\n for (let k = fromIndex; k < toIndex && k < UV_KEYS.length; k++) {\n // biome-ignore lint/style/noNonNullAssertion: bounded index on const array\n const uvKey = UV_KEYS[k]!;\n entries.push({\n key: uvKey,\n shaderLocation: CANONICAL_KEYS.indexOf(uvKey),\n offset: aliasOffset,\n format: ATTRIBUTE_FORMAT_MAP[uvKey],\n });\n }\n // When meshUvSetCount===0, allocate 8 bytes for the zero UV area.\n // Otherwise no stride increase (aliased to existing offset).\n return fromIndex === 0 ? currentStride + ATTRIBUTE_BYTE_STRIDE.uv : currentStride;\n}\n\n/**\n * Build a non-skin `VertexAttributeMap` carrying exactly `uvSetCount` UV sets\n * (set 0 = `uv`, then `uv1..uv{uvSetCount-1}`). `deriveVertexBufferLayout`\n * reads only key presence, so the zero-length typed-array values are sentinels.\n *\n * feat-20260629-multi-uv-set-support: the forward record stage owns only the\n * mesh's `uvSetCount` (a scalar threaded through MeshGpuHandles), not the\n * original `MeshAsset.attributes` map. It synthesizes the map here so the\n * material PSO's vertex layout includes the real @location(6+) attributes and\n * its stride matches the interleaved buffer (a mesh with 2 real UV sets has a\n * 56 B stride; a 48 B PSO layout against it puts every vertex after the first\n * off-screen). uvSetCount <= 1 yields the canonical 4-attribute single-UV map.\n */\nexport function buildMeshAttributeMapForUvSets(uvSetCount: number): VertexAttributeMap {\n const map: Record<string, Float32Array> = {\n position: new Float32Array(0),\n normal: new Float32Array(0),\n uv: new Float32Array(0),\n tangent: new Float32Array(0),\n };\n for (let set = 1; set < uvSetCount && set < UV_KEYS.length; set++) {\n // biome-ignore lint/style/noNonNullAssertion: bounded index on const array\n map[UV_KEYS[set]!] = new Float32Array(0);\n }\n return map as unknown as VertexAttributeMap;\n}\n\nexport function deriveVertexBufferLayout(\n map: VertexAttributeMap,\n opts?: { shaderUvSetCount?: number },\n): GpuVertexBufferLayoutEntry[] {\n const shaderUvSetCount = opts?.shaderUvSetCount ?? 0;\n\n // Process present keys in canonical order; absent keys reserve no space.\n const entries: Entry[] = [];\n let offset = 0;\n\n for (const key of CANONICAL_KEYS) {\n if (map[key] === undefined) continue;\n entries.push({\n key,\n shaderLocation: CANONICAL_KEYS.indexOf(key),\n offset,\n format: ATTRIBUTE_FORMAT_MAP[key],\n });\n offset += ATTRIBUTE_BYTE_STRIDE[key];\n }\n\n const present = entries.length;\n\n // ── clamp-to-last alias (plan-strategy D-1) ──\n if (shaderUvSetCount > 0) {\n const meshUvSetCount = countUvSets(map);\n\n if (shaderUvSetCount > meshUvSetCount) {\n const lastUvIndex = meshUvSetCount - 1;\n const lastUvKey =\n lastUvIndex >= 0 && lastUvIndex < UV_KEYS.length ? UV_KEYS[lastUvIndex] : undefined;\n const aliasOffset = lastUvKey !== undefined ? CANONICAL_KEYS.indexOf(lastUvKey) : -1;\n\n const aliasByteOffset =\n aliasOffset >= 0\n ? (entries.find((e) => e.shaderLocation === aliasOffset)?.offset ?? 0)\n : offset;\n\n offset = emitAliasEntries(entries, meshUvSetCount, shaderUvSetCount, aliasByteOffset, offset);\n }\n }\n\n if (present === 0 && shaderUvSetCount === 0) return [];\n\n // Sort by shaderLocation for deterministic vertex buffer descriptor\n entries.sort((a, b) => a.shaderLocation - b.shaderLocation);\n\n return [\n {\n arrayStride: offset,\n attributes: entries.map(({ shaderLocation, offset: entryOffset, format }) => ({\n shaderLocation,\n offset: entryOffset,\n format,\n })),\n },\n ];\n}\n\n/** Build the GPU descriptor from an immutable projection, adding only shader UV aliases. */\nexport function deriveVertexBufferLayoutFromProjection(\n projection: VertexLayoutProjection,\n opts?: { shaderUvSetCount?: number },\n): GpuVertexBufferLayoutEntry[] {\n const entries = projection.attributes.map(({ key, shaderLocation, offset, format }) => ({\n key,\n shaderLocation,\n offset,\n format,\n }));\n let arrayStride = projection.arrayStride;\n const shaderUvSetCount = opts?.shaderUvSetCount ?? 0;\n if (shaderUvSetCount > 0) {\n const meshUvSetCount = entries.filter(\n (entry) => entry.key === 'uv' || entry.key.startsWith('uv'),\n ).length;\n if (shaderUvSetCount > meshUvSetCount) {\n const lastUv = entries\n .filter((entry) => entry.key === 'uv' || entry.key.startsWith('uv'))\n .at(-1);\n const aliasOffset = lastUv?.offset ?? arrayStride;\n for (\n let index = meshUvSetCount;\n index < shaderUvSetCount && index < UV_KEYS.length;\n index += 1\n ) {\n const key = UV_KEYS[index];\n if (key === undefined) continue;\n entries.push({\n key,\n shaderLocation: CANONICAL_KEYS.indexOf(key),\n offset: aliasOffset,\n format: ATTRIBUTE_FORMAT_MAP[key],\n });\n }\n if (meshUvSetCount === 0) arrayStride += ATTRIBUTE_BYTE_STRIDE.uv;\n }\n }\n entries.sort((a, b) => a.shaderLocation - b.shaderLocation);\n return projection.attributes.length === 0\n ? []\n : [\n {\n arrayStride,\n attributes: entries.map(({ shaderLocation, offset, format }) => ({\n shaderLocation,\n offset,\n format,\n })),\n },\n ];\n}\n\nexport interface VertexLayoutProjectionAttribute {\n readonly key: AttributeKey;\n readonly shaderLocation: number;\n readonly offset: number;\n readonly format: (typeof ATTRIBUTE_FORMAT_MAP)[AttributeKey];\n readonly byteLength: number;\n}\n\n/** Immutable geometry-owned projection consumed by packers and GPU consumers. */\nexport interface VertexLayoutProjection {\n readonly schemaVersion: 1;\n readonly attributes: readonly VertexLayoutProjectionAttribute[];\n readonly mask: number;\n readonly arrayStride: number;\n readonly digest: string;\n}\n\nfunction bytesForFormat(format: string): number {\n if (format === 'uint16x4' || format === 'float32x2') return 8;\n if (format === 'float32x3') return 12;\n return 16;\n}\n\nfunction storageOf(value: unknown): VertexAttributeStorage {\n if (value instanceof ArrayBuffer) return 'array-buffer';\n if (value instanceof Float32Array) return 'float32';\n if (value instanceof Uint16Array) return 'uint16';\n return 'other';\n}\n\nfunction elementView(\n value: VertexAttributeMap[AttributeKey],\n format: string,\n): Float32Array | Uint16Array | undefined {\n if (value instanceof Float32Array || value instanceof Uint16Array) return value;\n if (value instanceof ArrayBuffer) {\n return format === 'uint16x4' ? new Uint16Array(value) : new Float32Array(value);\n }\n return undefined;\n}\n\nfunction fnv1a(input: string): string {\n let hash = 0x811c9dc5;\n for (let i = 0; i < input.length; i++) {\n hash ^= input.charCodeAt(i);\n hash = Math.imul(hash, 0x01000193);\n }\n return `vlp-v1-${(hash >>> 0).toString(16).padStart(8, '0')}`;\n}\n\n/** Derive the one canonical immutable layout projection for a vertex map. */\nexport function deriveVertexLayoutProjection(map: VertexAttributeMap): VertexLayoutProjection {\n const attributes: VertexLayoutProjectionAttribute[] = [];\n let offset = 0;\n let mask = 0;\n for (const key of CANONICAL_KEYS) {\n const value = map[key];\n if (value === undefined) continue;\n const format = ATTRIBUTE_FORMAT_MAP[key];\n const byteLength = bytesForFormat(format);\n attributes.push({\n key,\n shaderLocation: CANONICAL_KEYS.indexOf(key),\n offset,\n format,\n byteLength,\n });\n mask |= 1 << CANONICAL_KEYS.indexOf(key);\n offset += byteLength;\n }\n const digestInput = [\n '1',\n String(mask),\n String(offset),\n ...attributes.map(\n (entry) => `${entry.key},${entry.shaderLocation},${entry.offset},${entry.format}`,\n ),\n ].join('|');\n return Object.freeze({\n schemaVersion: 1,\n attributes: Object.freeze(attributes),\n mask,\n arrayStride: offset,\n digest: fnv1a(digestInput),\n });\n}\n\nexport interface PackedVertexAttributes {\n readonly projection: VertexLayoutProjection;\n readonly vertices: Float32Array;\n}\n\nexport class VertexAttributePackError extends AssetError {\n declare readonly detail: VertexAttributePackDetail;\n\n constructor(detail: VertexAttributePackDetail) {\n super({\n code: 'asset-invalid-value',\n expected: 'canonical vertex attributes with matching storage and cardinality',\n hint: ASSET_ERROR_HINTS['asset-invalid-value'],\n detail,\n });\n }\n}\n\nexport interface VertexLayoutProjectionMaskError {\n readonly code: 'vertex-layout-mask-invalid';\n readonly expected: string;\n readonly hint: string;\n readonly detail: {\n readonly mask: number;\n readonly knownMask: number;\n readonly unknownMask: number;\n readonly reason: 'empty' | 'unknown-bits';\n };\n}\n\n/** Rebuild the canonical projection from a packed wire mask without a second schema. */\nexport function deriveVertexLayoutProjectionFromMask(\n mask: number,\n): Result<VertexLayoutProjection, VertexLayoutProjectionMaskError> {\n const knownMask = (1 << CANONICAL_KEYS.length) - 1;\n const unsignedMask = Number.isInteger(mask) && mask >= 0 ? mask >>> 0 : 0xffffffff;\n const unknownMask = unsignedMask & ~knownMask;\n if (mask === 0) {\n return err({\n code: 'vertex-layout-mask-invalid',\n expected: 'a non-empty canonical vertex attribute mask',\n hint: 're-cook the mesh-bin payload from MeshAsset.attributes',\n detail: { mask, knownMask, unknownMask, reason: 'empty' },\n });\n }\n if (!Number.isInteger(mask) || mask < 0 || unknownMask !== 0) {\n return err({\n code: 'vertex-layout-mask-invalid',\n expected: `a mask using only canonical bits 0..${CANONICAL_KEYS.length - 1}`,\n hint: 're-cook the mesh-bin payload from MeshAsset.attributes',\n detail: { mask, knownMask, unknownMask, reason: 'unknown-bits' },\n });\n }\n const map: Record<string, Float32Array | Uint16Array> = {};\n for (let index = 0; index < CANONICAL_KEYS.length; index += 1) {\n if ((mask & (1 << index)) === 0) continue;\n const key = CANONICAL_KEYS[index];\n if (key !== undefined)\n map[key] = key === 'skinIndex' ? new Uint16Array(0) : new Float32Array(0);\n }\n return ok(deriveVertexLayoutProjection(map as VertexAttributeMap));\n}\n\n/** Pack tightly-owned attributes into the projection's canonical interleaved bytes. */\nexport function packInterleavedVertexAttributes(\n map: VertexAttributeMap,\n vertexCount: number,\n): Result<PackedVertexAttributes, VertexAttributePackError> {\n const invalid = (detail: VertexAttributePackDetail): Result<never, VertexAttributePackError> =>\n err(new VertexAttributePackError(detail));\n if (!Number.isInteger(vertexCount) || vertexCount < 0) {\n return invalid({ field: 'vertexCount', reason: 'vertex-count-invalid', actual: vertexCount });\n }\n const projection = deriveVertexLayoutProjection(map);\n if (projection.attributes.length === 0) {\n return invalid({ field: 'attributes', reason: 'attributes-empty', actualCount: 0 });\n }\n const output = new ArrayBuffer(projection.arrayStride * vertexCount);\n const outputFloats = new Float32Array(output);\n const outputU16 = new Uint16Array(output);\n for (const entry of projection.attributes) {\n const sourceValue = map[entry.key];\n if (sourceValue === undefined) continue;\n const uint16 = entry.format === 'uint16x4';\n const components = entry.byteLength / (uint16 ? 2 : 4);\n const bytesPerComponent = uint16 ? 2 : 4;\n if (sourceValue instanceof ArrayBuffer && sourceValue.byteLength % bytesPerComponent !== 0) {\n return invalid({\n field: entry.key,\n reason: 'attribute-cardinality-mismatch',\n vertexCount,\n componentsPerVertex: components,\n expectedLength: vertexCount * components,\n actualLength: sourceValue.byteLength / bytesPerComponent,\n });\n }\n const source = elementView(sourceValue, entry.format);\n if (\n source === undefined ||\n (uint16\n ? storageOf(sourceValue) !== 'uint16' && storageOf(sourceValue) !== 'array-buffer'\n : storageOf(sourceValue) !== 'float32' && storageOf(sourceValue) !== 'array-buffer')\n ) {\n return invalid({\n field: entry.key,\n reason: 'attribute-storage-invalid',\n expectedStorage: uint16 ? 'uint16' : 'float32',\n actualStorage: storageOf(sourceValue),\n });\n }\n const expectedLength = vertexCount * components;\n if (source.length !== expectedLength) {\n return invalid({\n field: entry.key,\n reason: 'attribute-cardinality-mismatch',\n vertexCount,\n componentsPerVertex: components,\n expectedLength,\n actualLength: source.length,\n });\n }\n if (entry.key === 'color') {\n for (let elementIndex = 0; elementIndex < source.length; elementIndex += 1) {\n const component = source[elementIndex] as number;\n if (!Number.isFinite(component)) {\n return invalid({\n field: 'color',\n reason: 'attribute-non-finite',\n elementIndex,\n actual: Number.isNaN(component)\n ? 'nan'\n : component === Number.POSITIVE_INFINITY\n ? 'positive-infinity'\n : 'negative-infinity',\n });\n }\n }\n }\n for (let vertex = 0; vertex < vertexCount; vertex += 1) {\n for (let component = 0; component < components; component += 1) {\n const sourceIndex = vertex * components + component;\n const byteOffset =\n vertex * projection.arrayStride + entry.offset + component * (uint16 ? 2 : 4);\n if (uint16) outputU16[byteOffset / 2] = Number(source[sourceIndex] ?? 0);\n else outputFloats[byteOffset / 4] = Number(source[sourceIndex] ?? 0);\n }\n }\n }\n return ok(Object.freeze({ projection, vertices: outputFloats }));\n}\n","import { deriveVertexLayoutProjection } from '@forgeax/engine-geometry';\nimport { AssetGuid } from '@forgeax/engine-pack/guid';\nimport {\n MESH_BIN_HEADER_V4_BYTES,\n type MeshBinContractError,\n type MeshBinHeaderV4,\n writeMeshBinHeader,\n} from '@forgeax/engine-pack/mesh-bin-contract';\nimport {\n err,\n type MeshAsset,\n ok,\n type Result,\n type VertexAttributeMap,\n} from '@forgeax/engine-types';\n\ntype MeshPayloadIn = { readonly [Key in keyof MeshAsset]?: MeshAsset[Key] | undefined } & {\n readonly vertexCount?: number;\n};\n\nexport type MeshBinEncodeError =\n | MeshBinContractError\n | {\n readonly code: 'mesh-bin-payload-invalid';\n readonly subject: 'mesh-bin';\n readonly sourceKey: string;\n readonly expected: string;\n readonly actual: string;\n readonly recovery: string;\n };\n\nfunction failure(sourceKey: string, expected: string, actual: string): MeshBinEncodeError {\n return {\n code: 'mesh-bin-payload-invalid',\n subject: 'mesh-bin',\n sourceKey,\n expected,\n actual,\n recovery: 're-cook the source with its Meta sidecar through the build-time importer',\n };\n}\n\nfunction asAttributeMap(value: unknown): VertexAttributeMap {\n return (value ?? {}) as VertexAttributeMap;\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Float32Array || value instanceof Uint16Array) return Array.from(value);\n if (Array.isArray(value)) return value.map(jsonValue);\n if (value !== null && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value).map(([key, nested]) => [key, jsonValue(nested)]),\n );\n }\n return value;\n}\n\nfunction refsMeta(payload: MeshPayloadIn, refs: readonly string[]): Record<string, unknown> {\n const materialSlots = (payload.materialSlots ?? [{ slotName: 'Default' }]).map(\n (slot, slotIndex) => {\n const defaultMaterial = slot.defaultMaterial;\n let defaultMaterialRef: number | undefined;\n if (defaultMaterial !== undefined) {\n const guid = AssetGuid.format(defaultMaterial);\n defaultMaterialRef = refs.findIndex((candidate) => candidate.toLowerCase() === guid);\n if (defaultMaterialRef < 0) {\n throw new Error(\n `material slot ${slotIndex} default material ${guid} is absent from refs`,\n );\n }\n }\n return {\n slotName: slot.slotName,\n ...(slot.sourceKey === undefined ? {} : { sourceKey: slot.sourceKey }),\n ...(defaultMaterialRef === undefined ? {} : { defaultMaterialRef }),\n };\n },\n );\n return {\n submeshes:\n payload.submeshes === undefined || payload.submeshes.length === 0\n ? [{ indexOffset: 0, indexCount: payload.indices?.length ?? 0, materialSlot: 0 }]\n : payload.submeshes,\n materialSlots,\n ...(payload.aabb === undefined ? {} : { aabb: jsonValue(payload.aabb) }),\n ...(payload.morphTargets === undefined\n ? {}\n : { morphTargets: jsonValue(payload.morphTargets) }),\n ...(payload.morphWeights === undefined\n ? {}\n : { morphWeights: jsonValue(payload.morphWeights) }),\n };\n}\n\n/** Encode one canonical v4 mesh binary. No legacy version is accepted or emitted. */\nexport function packMeshBinV4(\n payload: MeshPayloadIn,\n sourceKey: string,\n refs: readonly string[] = [],\n): Result<Uint8Array, MeshBinEncodeError> {\n try {\n const vertices = payload.vertices;\n const indices = payload.indices;\n if (!(vertices instanceof Float32Array)) {\n return err(\n failure(sourceKey, 'Float32Array interleaved vertices', 'vertices is not Float32Array'),\n );\n }\n if (\n indices !== undefined &&\n !(indices instanceof Uint16Array || indices instanceof Uint32Array)\n ) {\n return err(\n failure(sourceKey, 'Uint16Array or Uint32Array indices', 'indices has an unsupported type'),\n );\n }\n const attributes = asAttributeMap(payload.attributes);\n const projection = deriveVertexLayoutProjection(attributes);\n if (projection.attributes.length === 0 || projection.arrayStride === 0) {\n return err(\n failure(\n sourceKey,\n 'a non-empty canonical geometry projection',\n 'projection has no attributes',\n ),\n );\n }\n const vertexCount = payload.vertexCount ?? vertices.byteLength / projection.arrayStride;\n if (!Number.isSafeInteger(vertexCount) || vertexCount < 0) {\n return err(\n failure(sourceKey, 'a non-negative safe vertex cardinality', `vertexCount=${vertexCount}`),\n );\n }\n if (vertices.byteLength !== vertexCount * projection.arrayStride) {\n return err(\n failure(\n sourceKey,\n `vertices.byteLength=${vertexCount * projection.arrayStride}`,\n `vertices.byteLength=${vertices.byteLength}; stride=${projection.arrayStride}`,\n ),\n );\n }\n for (const attribute of projection.attributes) {\n const value = attributes[attribute.key];\n const components = attribute.byteLength / (attribute.format === 'uint16x4' ? 2 : 4);\n if (\n value === undefined ||\n (!(value instanceof Float32Array) && !(value instanceof Uint16Array)) ||\n value.length !== vertexCount * components\n ) {\n return err(\n failure(\n sourceKey,\n `${attribute.key} cardinality=${vertexCount * components}`,\n `${attribute.key} cardinality=${value?.byteLength ?? 'missing'}`,\n ),\n );\n }\n }\n const interleaved = new Uint8Array(vertexCount * projection.arrayStride);\n const interleavedView = new DataView(interleaved.buffer);\n for (const attribute of projection.attributes) {\n const value = attributes[attribute.key];\n if (value === undefined) continue;\n const components = attribute.byteLength / (attribute.format === 'uint16x4' ? 2 : 4);\n for (let vertex = 0; vertex < vertexCount; vertex++) {\n for (let component = 0; component < components; component++) {\n const sourceIndex = vertex * components + component;\n const targetOffset =\n vertex * projection.arrayStride +\n attribute.offset +\n component * (attribute.format === 'uint16x4' ? 2 : 4);\n if (attribute.format === 'uint16x4') {\n interleavedView.setUint16(targetOffset, (value as Uint16Array)[sourceIndex] ?? 0, true);\n } else {\n interleavedView.setFloat32(\n targetOffset,\n (value as Float32Array)[sourceIndex] ?? 0,\n true,\n );\n }\n }\n }\n }\n const indexCount = indices?.length ?? 0;\n const indexWidth = indices === undefined || indexCount === 0 ? 0 : indices.BYTES_PER_ELEMENT;\n const indexBytes = indexCount * indexWidth;\n if (!Number.isSafeInteger(indexBytes) || indexBytes > 0xffffffff) {\n return err(failure(sourceKey, 'safe index payload byte length', `indexBytes=${indexBytes}`));\n }\n const meta = new TextEncoder().encode(JSON.stringify(refsMeta(payload, refs)));\n const header: MeshBinHeaderV4 = {\n version: 4,\n projectionVersion: projection.schemaVersion,\n mask: projection.mask,\n digest: projection.digest,\n stride: projection.arrayStride,\n vertexCount,\n vertexBytes: interleaved.byteLength,\n indexCount,\n indexWidth: indexWidth as 0 | 2 | 4,\n indexBytes,\n jsonBytes: meta.byteLength,\n };\n const total = MESH_BIN_HEADER_V4_BYTES + interleaved.byteLength + indexBytes + meta.byteLength;\n if (!Number.isSafeInteger(total) || total > 0xffffffff) {\n return err(failure(sourceKey, 'safe mesh binary byte length', `total=${total}`));\n }\n const out = new Uint8Array(total);\n writeMeshBinHeader(header, out);\n let offset = MESH_BIN_HEADER_V4_BYTES;\n out.set(interleaved, offset);\n offset += interleaved.byteLength;\n if (indices !== undefined && indexBytes > 0) {\n out.set(new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength), offset);\n offset += indexBytes;\n }\n out.set(meta, offset);\n return ok(out);\n } catch (error) {\n return err(\n failure(\n sourceKey,\n 'valid canonical mesh payload',\n error instanceof Error ? error.message : String(error),\n ),\n );\n }\n}\n","// to-asset-pack.ts — aggregate parsed sub-assets into ImportedAsset[] (t31).\n//\n// GUID import-stable iron law: GUIDs come from `ctx.subAssets[]` (the external\n// meta), never minted here. Each parsed POD is matched to its declared GUID by\n// (kind, sourceIndex); a parsed asset that no sub-asset declares is dropped so\n// the produced set stays a subset of the declared set (mirrors gltfImporter).\n// The import-runner then validates produced == declared and rejects mismatches.\n\nimport { deriveAnimationTargetId } from '@forgeax/engine-animation/target-id';\nimport { packMeshBinV4 } from '@forgeax/engine-import/mesh-bin';\nimport { box3 } from '@forgeax/engine-math';\nimport { AssetGuid } from '@forgeax/engine-pack/guid';\nimport type {\n AnimationClipPod,\n AssetRef,\n ImportedAsset,\n MaterialAsset,\n MaterialPod,\n MeshAsset,\n MeshMaterialSlot,\n MeshMaterialSlotTopologyEntry,\n MeshPod,\n SceneAsset,\n ScenePod,\n SkeletonPod,\n SkinPod,\n SourceOverrideMap,\n TexturePod,\n} from '@forgeax/engine-types';\nimport {\n IMPORT_ERROR_HINTS,\n ImportError,\n reconcileMeshMaterialSlotTopology,\n resolveMeshMaterialSlotDefaultGuid,\n} from '@forgeax/engine-types';\nimport { buildFbxNodePaths } from './parse-scene.js';\n\ntype SubAsset = {\n readonly guid: string;\n readonly sourceIndex: number;\n readonly kind: string;\n readonly sourceKey?: string;\n};\n\n/** Resolve the meta-declared GUID for a parsed (kind, sourceIndex) pair. */\nfunction makeGuidResolver(\n subAssets: readonly SubAsset[],\n): (kind: string, sourceIndex: number) => string | undefined {\n const byKey = new Map<string, string>();\n for (const sub of subAssets) byKey.set(`${sub.kind}:${sub.sourceIndex}`, sub.guid);\n return (kind, sourceIndex) => byKey.get(`${kind}:${sourceIndex}`);\n}\n\nexport function buildMeshAsset(\n pod: MeshPod,\n guid: string,\n influences?: readonly { jointIndices: Uint16Array; jointWeights: Float32Array }[],\n materialContext: {\n readonly guidByIndex?: ReadonlyMap<number, string>;\n readonly nameByIndex?: ReadonlyMap<number, string>;\n readonly sourceKeyByIndex?: ReadonlyMap<number, string>;\n readonly previousMaterialSlots?: readonly MeshMaterialSlotTopologyEntry[];\n readonly materialSlotDefaultOverrides?: Readonly<Record<string, string | null>>;\n readonly meshSourceKey?: string;\n } = {},\n): ImportedAsset {\n const vc = pod.vertices.length / 3;\n const n = pod.attributes.NORMAL as Float32Array | undefined;\n // feat-20260629-multi-uv-set-support m1-w6: scan all TEXCOORD_n sets\n // (n in [0,7]) from MeshPod.attributes. TEXCOORD_0 -> uv (set 0),\n // TEXCOORD_n for n>=1 -> uvN attribute. >8 sets truncated per D-6.\n // uvSetCount = max(n) + 1 (not count of keys) so sparse sets (TEXCOORD_0+TEXCOORD_2\n // without TEXCOORD_1) still get correct interleaved stride with zero-filled gap.\n let uvSetCount = 1; // always at least 1 (uv slot in interleaved)\n for (const key of Object.keys(pod.attributes)) {\n if (key.startsWith('TEXCOORD_')) {\n const n = Number(key.slice('TEXCOORD_'.length));\n if (Number.isFinite(n) && n >= 0 && n <= 7) {\n uvSetCount = Math.max(uvSetCount, n + 1);\n }\n }\n }\n\n const u = pod.attributes.TEXCOORD_0 as Float32Array | undefined;\n\n // Skinned meshes use the 18-float interleaved stride (mirror of gltfImporter):\n // 12 floats (position/normal/uv/tangent) + uint16x4 joints (2 float slots, via\n // an aliased Uint16 view) + float32x4 weights = 18 floats / 72 bytes. The\n // runtime deriveVertexBufferLayout expects skinIndex at byte 48, skinWeight at\n // byte 56. Unskinned meshes keep the 12-float layout.\n const skinned = influences !== undefined && influences.length === vc && vc > 0;\n // feat-20260629-multi-uv-set-support m1-w6: dynamic stride.\n // Canonical interleaved order = position/normal/uv/tangent/skinIndex/skinWeight/uv1..uv7.\n // Base stride: 12 (unskinned) / 18 (skinned). Extra UV sets add 2F each.\n // UV1 offset: 12 (unskinned) / 18 (skinned) -- same as glTF bridge m1-w3.\n const BASE_FLOATS = skinned ? 18 : 12;\n const UV1_OFFSET = skinned ? 18 : 12;\n const FLOATS_PER_VERT = BASE_FLOATS + (uvSetCount - 1) * 2;\n const ib = new Float32Array(vc * FLOATS_PER_VERT);\n const ibU16 = skinned ? new Uint16Array(ib.buffer) : undefined;\n const skinIndexAttr = skinned ? new Uint16Array(vc * 4) : undefined;\n const skinWeightAttr = skinned ? new Float32Array(vc * 4) : undefined;\n\n for (let i = 0; i < vc; i++) {\n const d = i * FLOATS_PER_VERT;\n const p = i * 3;\n const t = i * 2;\n ib[d + 0] = pod.vertices[p + 0] ?? 0;\n ib[d + 1] = pod.vertices[p + 1] ?? 0;\n ib[d + 2] = pod.vertices[p + 2] ?? 0;\n ib[d + 3] = n?.[p + 0] ?? 0;\n ib[d + 4] = n?.[p + 1] ?? 0;\n ib[d + 5] = n?.[p + 2] ?? 0;\n ib[d + 6] = u?.[t + 0] ?? 0;\n ib[d + 7] = u?.[t + 1] ?? 0;\n ib[d + 8] = 1;\n ib[d + 9] = 0;\n ib[d + 10] = 0;\n ib[d + 11] = 1;\n if (skinned && ibU16 && skinIndexAttr && skinWeightAttr) {\n const inf = influences[i];\n const u16Base = (d + 12) * 2; // float slot 12 -> uint16 index (d+12)*2\n const sd = i * 4;\n for (let k = 0; k < 4; k++) {\n const ji = inf?.jointIndices[k] ?? 0;\n const jw = inf?.jointWeights[k] ?? 0;\n ibU16[u16Base + k] = ji;\n ib[d + 14 + k] = jw;\n skinIndexAttr[sd + k] = ji;\n skinWeightAttr[sd + k] = jw;\n }\n }\n // feat-20260629-multi-uv-set-support m1-w6: write uv1..uvK after skin data.\n // Canonical interleaved order matches glTF bridge m1-w3:\n // position/normal/uv/tangent/skinIndex/skinWeight/uv1..uv7.\n // UV1 starts at UV1_OFFSET (12 for unskinned, 18 for skinned) in float slots.\n // Each additional UV set 2F. Missing texcoordK -> zero-fill (implicit).\n for (let k = 1; k < uvSetCount; k++) {\n const srcKey = `TEXCOORD_${k}`;\n const srcArr = pod.attributes[srcKey] as Float32Array | undefined;\n const interleavedOffset = UV1_OFFSET + (k - 1) * 2;\n if (srcArr !== undefined) {\n ib[d + interleavedOffset + 0] = srcArr[t + 0] ?? 0;\n ib[d + interleavedOffset + 1] = srcArr[t + 1] ?? 0;\n }\n // else: zero-fill (implicit -- Float32Array defaults to 0)\n }\n }\n\n // feat-20260629-multi-uv-set-support m1-w6: per-UV-set standalone typed arrays\n // for MeshAsset.attributes (uv1..uvK). TEXCOORD_n -> attributes.uvN.\n // Preserve sparse source-set semantics in the importer-facing mesh.\n const extraUvAttrs: Record<string, Float32Array> = {};\n for (let k = 1; k < uvSetCount; k++) {\n const srcKey = `TEXCOORD_${k}`;\n const srcArr = pod.attributes[srcKey] as Float32Array | undefined;\n if (srcArr !== undefined) {\n const cat = new Float32Array(vc * 2);\n for (let i = 0; i < vc; i++) {\n const t2 = i * 2;\n cat[t2 + 0] = srcArr[t2 + 0] ?? 0;\n cat[t2 + 1] = srcArr[t2 + 1] ?? 0;\n }\n extraUvAttrs[`uv${k}`] = cat;\n }\n }\n\n const attributes: MeshAsset['attributes'] = {\n position: pod.vertices,\n normal: n ?? new Float32Array(vc * 3).fill(0),\n uv: u ?? new Float32Array(vc * 2).fill(0),\n tangent: new Float32Array(vc * 4).fill(0).map((_, i) => (i % 4 === 0 || i % 4 === 3 ? 1 : 0)),\n ...(skinIndexAttr ? { skinIndex: skinIndexAttr } : {}),\n ...(skinWeightAttr ? { skinWeight: skinWeightAttr } : {}),\n ...extraUvAttrs,\n };\n\n const materialSlots: MeshMaterialSlot[] = [];\n const slotByMaterial = new Map<number | null, number>();\n const usedNames = new Set<string>();\n const uniqueName = (raw: string): string => {\n const base = raw.trim() || 'Material';\n let candidate = base;\n let suffix = 2;\n while (usedNames.has(candidate)) candidate = `${base}_${suffix++}`;\n usedNames.add(candidate);\n return candidate;\n };\n const materialSlotFor = (materialIndex: number | null): number => {\n const existing = slotByMaterial.get(materialIndex);\n if (existing !== undefined) return existing;\n const guidString =\n materialIndex === null ? undefined : materialContext.guidByIndex?.get(materialIndex);\n const parsed = guidString === undefined ? undefined : AssetGuid.parse(guidString);\n const slotIndex = materialSlots.length;\n materialSlots.push({\n slotName: uniqueName(\n materialIndex === null\n ? 'Default'\n : (materialContext.nameByIndex?.get(materialIndex) ?? `Material_${materialIndex}`),\n ),\n sourceKey:\n materialIndex === null\n ? 'fbx:default'\n : (materialContext.sourceKeyByIndex?.get(materialIndex) ??\n `fbx:material:${materialIndex}`),\n ...(parsed?.ok ? { defaultMaterial: parsed.value } : {}),\n });\n slotByMaterial.set(materialIndex, slotIndex);\n return slotIndex;\n };\n const currentMesh: MeshAsset = {\n kind: 'mesh',\n vertices: ib,\n ...(pod.indices ? { indices: pod.indices } : {}),\n aabb: box3.fromPositions(box3.create(), pod.vertices),\n attributes,\n ...(pod.morphTargets === undefined\n ? {}\n : {\n morphTargets: pod.morphTargets.map((target) => ({\n ...(target.position === undefined\n ? {}\n : { position: new Float32Array(target.position) }),\n ...(target.normal === undefined ? {} : { normal: new Float32Array(target.normal) }),\n ...(target.tangent === undefined ? {} : { tangent: new Float32Array(target.tangent) }),\n })),\n }),\n ...(pod.morphWeights === undefined ? {} : { morphWeights: new Float32Array(pod.morphWeights) }),\n submeshes: pod.submeshes.map((sm) => ({\n indexOffset: sm.indexOffset,\n indexCount: sm.indexCount,\n vertexCount: vc,\n topology: sm.topology,\n materialSlot: materialSlotFor(sm.materialIndex),\n })),\n materialSlots,\n };\n\n const reconciled = reconcileMeshMaterialSlotTopology(\n currentMesh.materialSlots.map((slot) => ({\n slotName: slot.slotName,\n ...(slot.sourceKey === undefined ? {} : { sourceKey: slot.sourceKey }),\n ...(slot.defaultMaterial === undefined\n ? {}\n : { defaultMaterialGuid: AssetGuid.format(slot.defaultMaterial) }),\n })),\n materialContext.previousMaterialSlots,\n );\n if (!reconciled.ok) {\n throw new ImportError({\n code: 'mesh-material-slot-topology-change',\n expected: `unambiguous material slot identity for mesh ${guid}`,\n hint: IMPORT_ERROR_HINTS['mesh-material-slot-topology-change'],\n detail: {\n meshGuid: guid,\n ...(materialContext.meshSourceKey === undefined\n ? {}\n : { meshSourceKey: materialContext.meshSourceKey }),\n previousIndices: reconciled.error.previousIndices,\n nextIndices: reconciled.error.nextIndices,\n },\n });\n }\n const mesh: MeshAsset = {\n ...currentMesh,\n submeshes: currentMesh.submeshes.map((submesh) => ({\n ...submesh,\n materialSlot: reconciled.currentToStableSlot[submesh.materialSlot] as number,\n })),\n materialSlots: reconciled.slots.map((slot, stableIndex) => {\n const active = reconciled.currentToStableSlot.includes(stableIndex);\n const effectiveDefault = resolveMeshMaterialSlotDefaultGuid(\n slot,\n active\n ? materialContext.materialSlotDefaultOverrides?.[slot.sourceKey ?? slot.slotName]\n : undefined,\n );\n const parsed = effectiveDefault === undefined ? undefined : AssetGuid.parse(effectiveDefault);\n return {\n slotName: slot.slotName,\n ...(slot.sourceKey === undefined ? {} : { sourceKey: slot.sourceKey }),\n ...(active && parsed?.ok ? { defaultMaterial: parsed.value } : {}),\n };\n }),\n };\n\n // The wire projection is dense even when the source mesh intentionally\n // preserves sparse UV-set presence. Missing intermediate slots are zeroed\n // only for the canonical v4 payload.\n const wireAttributes = { ...mesh.attributes } as Record<string, Float32Array | Uint16Array>;\n for (let k = 1; k < uvSetCount; k++) {\n if (wireAttributes[`uv${k}`] === undefined) {\n wireAttributes[`uv${k}`] = new Float32Array(vc * 2);\n }\n }\n const wireMesh: MeshAsset = { ...mesh, attributes: wireAttributes };\n\n const refs: AssetRef[] = [];\n const seenRefs = new Set<string>();\n for (let slotIndex = 0; slotIndex < mesh.materialSlots.length; slotIndex++) {\n const defaultMaterial = mesh.materialSlots[slotIndex]?.defaultMaterial;\n const materialGuid =\n defaultMaterial === undefined ? undefined : AssetGuid.format(defaultMaterial);\n if (materialGuid !== undefined && !seenRefs.has(materialGuid.toLowerCase())) {\n seenRefs.add(materialGuid.toLowerCase());\n refs.push({\n guid: materialGuid,\n sourceField: { fieldName: 'materialSlots', arrayIndex: slotIndex },\n });\n }\n }\n\n return {\n guid,\n kind: 'mesh',\n ...(pod.name !== undefined ? { name: pod.name } : {}),\n payload: mesh,\n refs,\n artifacts: {\n body: {\n mediaType: 'application/x-forgeax-mesh',\n assetCodec: { name: 'mesh-binary', version: '4' },\n bytes: (() => {\n const packed = packMeshBinV4(\n wireMesh as never,\n materialContext.meshSourceKey ?? 'fbx://mesh',\n refs.map((ref) => ref.guid),\n );\n if (!packed.ok) {\n throw new ImportError({\n code: 'import-internal-error',\n expected: 'mesh-bin v4 producer to accept the canonical FBX mesh projection',\n hint: 're-cook the FBX source with its Meta sidecar after fixing the mesh payload',\n detail: { reason: `${packed.error.code}: ${packed.error.actual}` },\n });\n }\n return packed.value;\n })(),\n },\n },\n };\n}\n\nfunction buildMaterialAsset(pod: MaterialPod, guid: string, skinned = false): ImportedAsset {\n // A material consumed by a skinned mesh must select the pbr-skin shader so the\n // runtime PSO chain (LayoutKind 'pbr-skin' + 18-float vertex layout + joint\n // palette) is exercised; the render-system fail-fasts otherwise (mirror of\n // gltfImporter's `skinned` routing).\n const mat: MaterialAsset = {\n kind: 'material',\n colorSpace: 'linear',\n passes: [\n {\n name: 'Forward',\n program: { module: skinned ? 'forgeax::pbr-skin' : 'forgeax::default-standard-pbr' },\n renderState: { tags: { LightMode: 'Forward' }, queue: 2000 },\n },\n ],\n values: {\n baseColor: pod.baseColorFactor as readonly [number, number, number, number],\n metallic: pod.metallicFactor,\n roughness: pod.roughnessFactor,\n },\n };\n return {\n guid,\n kind: 'material',\n ...(pod.name !== undefined ? { name: pod.name } : {}),\n payload: mat,\n refs: [],\n artifacts: {},\n };\n}\n\ninterface SceneBuildContext {\n /** mesh sourceIndex -> MeshFilter.assetHandle (a scene refs[] index). */\n readonly meshHandleByIndex: ReadonlyMap<number, number>;\n /** mesh sourceIndex carrying the skin deformer; null when the scene has no skin. */\n readonly skinnedMeshIndex: number | null;\n /** Skin.skeleton handle (a scene refs[] index); undefined when no skeleton. */\n readonly skeletonHandle: number | undefined;\n /** Scene refs[]: [mesh..., skeleton..., skin...] GUIDs. */\n readonly refs: readonly string[];\n /**\n * Skin GUIDs (inline strings) injected into the SceneAsset payload and the\n * scene envelope's refs[] so the runtime recursive loadByGuid walk pulls each\n * SkinAsset on the browser-async pack-fetch path. Mirrors gltf-importer:\n * stored as GUID strings (the on-disk round-trip + parseScenePayload's\n * resolveSkinGuids accept both shapes).\n */\n readonly skinGuids: readonly string[];\n readonly animationTargetIds: ReadonlySet<string>;\n readonly morphWeightsByMeshIndex: ReadonlyMap<\n number,\n { readonly targetCount: number; readonly weights?: Float32Array }\n >;\n}\n\nfunction buildSceneAsset(pod: ScenePod, guid: string, ctx: SceneBuildContext): ImportedAsset {\n // ChildOf wiring: ScenePod.children[] holds flattened-array indices; invert to\n // a parent map so each entity emits ChildOf { parent } (localId === array idx).\n const parentOf = new Map<number, number>();\n for (let i = 0; i < pod.entities.length; i++) {\n const e = pod.entities[i];\n if (!e) continue;\n for (const childIdx of e.children ?? []) parentOf.set(childIdx, i);\n }\n const targetIdByEntity = new Map<number, string>();\n const nodePaths = buildFbxNodePaths(pod.entities);\n for (let index = 0; index < nodePaths.length; index++) {\n const path = nodePaths[index];\n if (path === undefined || !path.ok) continue;\n const targetId = deriveAnimationTargetId(path.value);\n if (ctx.animationTargetIds.has(targetId)) targetIdByEntity.set(index, targetId);\n }\n\n const entities = pod.entities.map((e, idx) => {\n const components: Record<string, Record<string, unknown>> = {\n Transform: {\n pos: [e.transform.translation[0], e.transform.translation[1], e.transform.translation[2]],\n // Quaternion component order [x, y, z, w] (E6).\n quat: [\n e.transform.rotation[0],\n e.transform.rotation[1],\n e.transform.rotation[2],\n e.transform.rotation[3],\n ],\n scale: [e.transform.scale[0], e.transform.scale[1], e.transform.scale[2]],\n },\n };\n\n // Name is required for postSpawnResolveJoints to match SkinAsset.jointPaths\n // against the spawned subtree (the skeleton joint resolution path).\n if (e.name) components.Name = { value: e.name };\n const targetId = targetIdByEntity.get(idx);\n if (targetId !== undefined) components.AnimationTargetId = { value: targetId };\n\n const parent = parentOf.get(idx);\n if (parent !== undefined) components.ChildOf = { parent };\n\n if (e.meshIndex !== null) {\n const meshHandle = ctx.meshHandleByIndex.get(e.meshIndex);\n if (meshHandle !== undefined) components.MeshFilter = { assetHandle: meshHandle };\n\n components.MeshRenderer = { materials: [] };\n const morph = ctx.morphWeightsByMeshIndex.get(e.meshIndex);\n if (morph !== undefined && morph.targetCount > 0) {\n const weights = morph.weights ?? new Float32Array(morph.targetCount);\n if (weights.length !== morph.targetCount) {\n throw new Error('fbxScene: MorphWeights length does not match morph targets');\n }\n components.MorphWeights = { weights: Array.from(weights) };\n }\n // Skinned mesh node carries Skin { skeleton: <handle> }; instantiate\n // resolves the handle and postSpawnResolveJoints fills Skin.joints[].\n if (ctx.skinnedMeshIndex === e.meshIndex && ctx.skeletonHandle !== undefined) {\n components.Skin = { skeleton: ctx.skeletonHandle };\n }\n }\n\n return { localId: idx as never, components };\n });\n\n const scene: SceneAsset = {\n kind: 'scene',\n entities,\n ...(ctx.skinGuids.length > 0 ? { skinGuids: ctx.skinGuids } : {}),\n } as SceneAsset;\n\n return {\n guid,\n kind: 'scene',\n ...(pod.name !== undefined ? { name: pod.name } : {}),\n payload: scene,\n refs: ctx.refs.map((guid) => ({ guid })),\n artifacts: {},\n };\n}\n\n// M3: TextureAsset requires decoded pixel data — deferred to M4.\n// TexturePod.filePath is preserved for diagnostics during M3.\nfunction buildTextureNote(_pod: TexturePod, _guid: string): ImportedAsset {\n // Produce a minimal placeholder; real texture import (decode + upload)\n // lands with M4 material parsing.\n return {\n guid: _guid,\n kind: 'texture',\n ...(_pod.name !== undefined ? { name: _pod.name } : {}),\n payload: {} as never,\n refs: [],\n artifacts: {},\n };\n}\n\nexport function toAssetPack(params: {\n readonly meshes: readonly MeshPod[];\n readonly scene: ScenePod;\n readonly materials: readonly MaterialPod[];\n readonly textures: readonly TexturePod[];\n readonly skeleton: SkeletonPod;\n readonly skin: SkinPod;\n readonly animationClips: readonly AnimationClipPod[];\n readonly subAssets: readonly SubAsset[];\n readonly sourceOverrides?: SourceOverrideMap;\n}): readonly ImportedAsset[] {\n const assets: ImportedAsset[] = [];\n const guidOf = makeGuidResolver(params.subAssets);\n const materialGuidByIndex = new Map<number, string>();\n const materialNameByIndex = new Map<number, string>();\n const materialSourceKeyByIndex = new Map<number, string>();\n for (let materialIndex = 0; materialIndex < params.materials.length; materialIndex++) {\n const materialGuid = guidOf('material', materialIndex);\n if (materialGuid !== undefined) materialGuidByIndex.set(materialIndex, materialGuid);\n const materialSourceKey = params.subAssets.find(\n (entry) => entry.kind === 'material' && entry.sourceIndex === materialIndex,\n )?.sourceKey;\n if (materialSourceKey !== undefined) {\n materialSourceKeyByIndex.set(materialIndex, materialSourceKey);\n }\n const materialName = params.materials[materialIndex]?.name;\n if (materialName !== undefined) materialNameByIndex.set(materialIndex, materialName);\n }\n\n // The skin deforms the (single) first mesh; its per-vertex influences promote\n // both the mesh (18-float skinned layout) and its material (pbr-skin shader).\n const hasSkin = params.skin.vertexCount > 0;\n const skinnedMeshSourceIndex = hasSkin ? (params.meshes[0]?.sourceIndex ?? null) : null;\n\n for (const mesh of params.meshes) {\n const meshDeclaration = params.subAssets.find(\n (entry) => entry.kind === 'mesh' && entry.sourceIndex === mesh.sourceIndex,\n );\n const guid = meshDeclaration?.guid;\n if (guid === undefined) continue;\n const previousRaw =\n meshDeclaration?.sourceKey === undefined\n ? undefined\n : params.sourceOverrides?.[meshDeclaration.sourceKey]?.materialSlots;\n const previousMaterialSlots = Array.isArray(previousRaw)\n ? previousRaw.filter(\n (slot): slot is MeshMaterialSlotTopologyEntry =>\n slot !== null &&\n typeof slot === 'object' &&\n !Array.isArray(slot) &&\n typeof (slot as { slotName?: unknown }).slotName === 'string',\n )\n : undefined;\n const authoredRaw =\n meshDeclaration?.sourceKey === undefined\n ? undefined\n : params.sourceOverrides?.[meshDeclaration.sourceKey]?.materialSlotDefaultOverrides;\n const materialSlotDefaultOverrides =\n authoredRaw !== null && typeof authoredRaw === 'object' && !Array.isArray(authoredRaw)\n ? Object.fromEntries(\n Object.entries(authoredRaw).filter(\n (entry): entry is [string, string | null] =>\n typeof entry[1] === 'string' || entry[1] === null,\n ),\n )\n : undefined;\n const inf = mesh.sourceIndex === skinnedMeshSourceIndex ? params.skin.influences : undefined;\n assets.push(\n buildMeshAsset(mesh, guid, inf, {\n guidByIndex: materialGuidByIndex,\n nameByIndex: materialNameByIndex,\n sourceKeyByIndex: materialSourceKeyByIndex,\n ...(previousMaterialSlots === undefined ? {} : { previousMaterialSlots }),\n ...(materialSlotDefaultOverrides === undefined ? {} : { materialSlotDefaultOverrides }),\n ...(meshDeclaration?.sourceKey === undefined\n ? {}\n : { meshSourceKey: meshDeclaration.sourceKey }),\n }),\n );\n }\n\n for (let i = 0; i < params.materials.length; i++) {\n const mat = params.materials[i];\n if (!mat) continue;\n const guid = guidOf('material', i);\n // Single-mesh fixtures: any material is consumed by the skinned mesh.\n if (guid !== undefined) assets.push(buildMaterialAsset(mat, guid, hasSkin));\n }\n\n for (const tex of params.textures) {\n const guid = guidOf('texture', tex.sourceIndex);\n if (guid !== undefined) assets.push(buildTextureNote(tex, guid));\n }\n\n // Scene refs[] ordering (mirror of gltfImporter): only direct scene\n // dependencies live here. Mesh defaults belong to MeshAsset refs and\n // textures belong to MaterialAsset refs, so the scene concatenates\n // [mesh GUIDs..., skeleton GUIDs..., skin GUIDs...]\n // each section in declared sourceIndex order. Build the section -> refs-index\n // maps here so buildSceneAsset can stamp the right indices.\n const declaredByKind = (kind: string): string[] =>\n params.subAssets\n .filter((s) => s.kind === kind)\n .slice()\n .sort((a, b) => a.sourceIndex - b.sourceIndex)\n .map((s) => s.guid);\n\n const meshGuids = declaredByKind('mesh');\n const skeletonGuids = declaredByKind('skeleton');\n const skinGuids = declaredByKind('skin');\n const sceneRefs = [...meshGuids, ...skeletonGuids, ...skinGuids];\n\n // mesh sourceIndex -> scene refs[] index (mesh section starts at 0).\n const meshHandleByIndex = new Map<number, number>();\n params.subAssets\n .filter((s) => s.kind === 'mesh')\n .forEach((s) => {\n const idx = meshGuids.indexOf(s.guid);\n if (idx >= 0) meshHandleByIndex.set(s.sourceIndex, idx);\n });\n // skeleton handle = first skeleton's scene refs[] index.\n const skeletonRefBase = meshGuids.length;\n const skeletonHandle = skeletonGuids.length > 0 ? skeletonRefBase : undefined;\n // Single-mesh fixtures: the skin deforms the (only) mesh node.\n const skinnedMeshIndex =\n params.skin.vertexCount > 0 ? (params.meshes[0]?.sourceIndex ?? null) : null;\n\n // Skeleton asset (t48). refs[] empty (skeleton is leaf data). The runtime\n // SkeletonAsset POD is { inverseBindMatrices, jointCount } — joint paths live\n // on the parallel SkinAsset (mirror of gltfImporter's emit policy). The native\n // binding derives the skeleton from the skin's clusters, so jointCount /\n // inverseBindMatrices already align 1:1 with the skin's jointPaths and the\n // per-vertex skinIndex influences (runtime requires\n // SkeletonAsset.jointCount === Skin.joints.length).\n const skeletonGuid = guidOf('skeleton', 0);\n if (params.skeleton.jointCount > 0 && skeletonGuid !== undefined) {\n assets.push({\n guid: skeletonGuid,\n kind: 'skeleton',\n payload: {\n kind: 'skeleton',\n inverseBindMatrices: params.skeleton.inverseBindMatrices,\n jointCount: params.skeleton.jointCount,\n } as never,\n refs: [],\n artifacts: {},\n });\n }\n\n // Skin asset (t49). The runtime SkinAsset POD is { skeletonGuid, jointPaths };\n // per-vertex influences live in the mesh vertex buffer, not the SkinAsset.\n // refs[] carries the skeleton GUID cross-edge (mirror of gltfImporter) so the\n // runner / runtime asset graph sees the skin->skeleton link.\n const skinGuid = guidOf('skin', 0);\n if (params.skin.vertexCount > 0 && skinGuid !== undefined) {\n assets.push({\n guid: skinGuid,\n kind: 'skin',\n payload: {\n kind: 'skin',\n skeletonGuid: skeletonGuid ?? '',\n jointPaths: params.skin.jointPaths,\n } as never,\n refs:\n skeletonGuid !== undefined\n ? [{ guid: skeletonGuid, sourceField: { fieldName: 'skeleton' } }]\n : [],\n artifacts: {},\n });\n }\n\n // Animation clip assets (t50)\n for (let i = 0; i < params.animationClips.length; i++) {\n const clip = params.animationClips[i];\n if (!clip) continue;\n const guid = guidOf('animation-clip', i);\n if (guid === undefined) continue;\n assets.push({\n guid,\n kind: 'animation-clip',\n payload: {\n kind: 'animation-clip',\n name: clip.name ?? `Clip${i}`,\n duration: clip.duration,\n channels: clip.channels.map((ch) => ({\n targetId: ch.targetId,\n property: ch.property,\n sampler: {\n input: Array.from(ch.sampler.input),\n output: Array.from(ch.sampler.output),\n interpolation: ch.sampler.interpolation,\n },\n })),\n } as never,\n refs: [],\n artifacts: {},\n });\n }\n\n const sceneGuid = guidOf('scene', 0);\n const animationTargetIds = new Set(\n params.animationClips.flatMap((clip) => clip.channels.map((channel) => channel.targetId)),\n );\n const morphWeightsByMeshIndex = new Map<\n number,\n { readonly targetCount: number; readonly weights?: Float32Array }\n >();\n for (const mesh of params.meshes) {\n const targetCount = mesh.morphTargets?.length ?? 0;\n if (targetCount > 0) {\n morphWeightsByMeshIndex.set(mesh.sourceIndex, {\n targetCount,\n ...(mesh.morphWeights === undefined\n ? {}\n : { weights: new Float32Array(mesh.morphWeights) }),\n });\n }\n }\n if (sceneGuid !== undefined) {\n assets.push(\n buildSceneAsset(params.scene, sceneGuid, {\n meshHandleByIndex,\n skinnedMeshIndex,\n skeletonHandle,\n refs: sceneRefs,\n skinGuids,\n animationTargetIds,\n morphWeightsByMeshIndex,\n }),\n );\n }\n\n // XOR identity rule (aligned with the glTF importer): a single-asset package\n // derives its name from the package path, so the stored entry name is dropped.\n // Only multi-asset packages keep per-entry stored names. FBX is almost always\n // multi-asset (a scene asset is always emitted), so this strips name only in\n // the degenerate single-asset case.\n if (assets.length === 1) {\n const only = assets[0];\n if (only && 'name' in only) {\n const { name: _dropped, ...rest } = only;\n assets[0] = rest;\n }\n }\n\n return assets;\n}\n","// fbx-importer.ts — TS wrapper around the ufbx WASM parser.\n\nimport type { ImportContext, Importer, ImportResult } from '@forgeax/engine-types';\nimport { fbxErr } from './errors.js';\nimport { initFbxWasm, parseFbx } from './index.js';\nimport {\n type FbxRawAnimDoc,\n parseAnimationClips,\n resolveAnimationTargetIds,\n} from './parse-animation-clip.js';\nimport { type FbxRawMaterial, parseMaterial } from './parse-material.js';\nimport { type FbxRawDocument, type FbxRawMesh, parseMesh } from './parse-mesh.js';\nimport { type FbxRawNodes, parseScene } from './parse-scene.js';\nimport { type FbxRawSkeletonDoc, parseSkeleton } from './parse-skeleton.js';\nimport { type FbxRawSkinDoc, parseSkin } from './parse-skin.js';\nimport { parseTextures } from './parse-texture.js';\nimport { toAssetPack } from './to-asset-pack.js';\n\nexport interface FbxSourceKeyOutput {\n readonly kind: string;\n readonly name?: string;\n}\n\nexport type FbxSourceKeyResult =\n | { readonly ok: true; readonly keys: readonly string[] }\n | {\n readonly ok: false;\n readonly code: 'missing-source-key' | 'duplicate-source-key' | 'ambiguous-source-key';\n };\n\n/** Derive FBX output identity from producer semantics, never from sourceIndex. */\nexport function sourceKeyForFbxOutput(output: FbxSourceKeyOutput): string | undefined {\n const kind = output.kind.trim();\n if (kind.length === 0) return undefined;\n const name = output.name?.trim();\n return name === undefined || name.length === 0 ? `fbx:${kind}` : `fbx:${kind}:${name}`;\n}\n\nexport function deriveFbxSourceKeys(outputs: readonly FbxSourceKeyOutput[]): FbxSourceKeyResult {\n const keys = outputs.map(sourceKeyForFbxOutput);\n if (keys.some((key) => key === undefined)) return { ok: false, code: 'missing-source-key' };\n const seen = new Set<string>();\n for (const [index, key] of keys.entries()) {\n if (key === undefined) continue;\n if (seen.has(key)) {\n return {\n ok: false,\n code: outputs[index]?.name === undefined ? 'ambiguous-source-key' : 'duplicate-source-key',\n };\n }\n seen.add(key);\n }\n return { ok: true, keys: keys as string[] };\n}\n\nexport const fbxImporter: Importer = {\n key: 'fbx',\n\n async import(ctx: ImportContext): Promise<ImportResult> {\n // ufbx WASM path: read raw FBX bytes via the import context (browser +\n // Node both resolve through readSource), then parse in-memory. No native\n // addon / SDK build step (the WASM module self-loads its .wasm).\n const read = await ctx.readSource();\n if (!read.ok) {\n const wrapper = new Error(`fbx-source-unreadable: ${ctx.source}`);\n (wrapper as { cause?: unknown }).cause = read.error;\n throw wrapper;\n }\n\n await initFbxWasm();\n const jsonStr = parseFbx(read.value);\n const doc = JSON.parse(jsonStr) as FbxRawDocument &\n FbxRawSkeletonDoc &\n FbxRawSkinDoc &\n FbxRawAnimDoc;\n\n // NURBS / patch fail-fast: the bridge emits an error envelope for\n // unsupported surface types (charter P3 explicit failure).\n const maybeError = doc as unknown as {\n error?: { code: string; meshType: string; meshName: string };\n };\n if (maybeError.error?.code === 'fbx-mesh-type-unsupported') {\n const e = fbxErr('fbx-mesh-type-unsupported', {\n meshType: maybeError.error.meshType as 'nurbs' | 'patch',\n meshName: maybeError.error.meshName,\n });\n // The Importer interface returns Promise<ImportedAsset[]> (not Result),\n // so structural FbxError cannot flow through the import-runner's typed\n // error return. Throw a plain Error with the code in the message so\n // AI users can grep import-internal-error.detail.reason for the\n // 'fbx-mesh-type-unsupported' substring; the structural error rides on\n // `.cause`.\n const wrapper = new Error(`${e.code}: ${e.expected}`);\n (wrapper as { cause?: unknown }).cause = e;\n throw wrapper;\n }\n\n const rawMeshes: readonly FbxRawMesh[] = doc.meshes ?? [];\n const meshes = rawMeshes.map((raw, i) => parseMesh(raw, i));\n\n const scene = parseScene(doc as unknown as FbxRawNodes);\n\n const texturesModule = doc as unknown as { textures?: readonly unknown[] };\n const textures = parseTextures({ textures: texturesModule.textures as never });\n\n const materialDocs =\n (doc as unknown as { materials?: readonly FbxRawMaterial[] }).materials ?? [];\n const materials =\n materialDocs.length > 0\n ? materialDocs.map((raw, i) => parseMaterial(raw, i))\n : [parseMaterial({ kind: 'fallback' }, 0)];\n\n const skeleton = parseSkeleton(doc);\n const skin = parseSkin(doc);\n const animationTargets = resolveAnimationTargetIds(\n (doc as unknown as FbxRawNodes).nodes ?? [],\n doc.clips ?? [],\n );\n if (!animationTargets.ok) {\n const wrapper = new Error(\n `${animationTargets.error.code}: ${animationTargets.error.expected}`,\n );\n (wrapper as { cause?: unknown }).cause = animationTargets.error;\n throw wrapper;\n }\n const animationClips = parseAnimationClips(doc);\n\n return {\n ok: true,\n value: {\n assets: toAssetPack({\n meshes,\n scene,\n materials,\n textures,\n skeleton,\n skin,\n animationClips,\n subAssets: ctx.subAssets,\n ...(ctx.sourceOverrides === undefined ? {} : { sourceOverrides: ctx.sourceOverrides }),\n }),\n sourceDependencies: [],\n },\n };\n },\n};\n","export type FbxTextureResolutionStrategy = 'exact' | 'case-folded' | 'suffix' | 'basename';\n\nexport interface FbxTexturePathRequest {\n readonly declaredRelativePath?: string;\n readonly declaredFilename?: string;\n readonly declaredAbsolutePath?: string;\n}\n\nexport interface FbxTextureCandidate {\n /** Candidate path relative to the FBX source file's directory. */\n readonly relativePath: string;\n}\n\nexport type FbxTextureResolution =\n | {\n readonly ok: true;\n readonly relativePath: string;\n /** URI passed to ImportContext.readSibling from the FBX source. */\n readonly readUri: string;\n readonly strategy: FbxTextureResolutionStrategy;\n }\n | {\n readonly ok: false;\n readonly code: 'fbx-external-texture-missing' | 'fbx-external-texture-ambiguous';\n readonly requestedPath: string;\n readonly candidates: readonly string[];\n };\n\nfunction normalizeSourceRelativePath(raw: string): string | undefined {\n const value = raw.replaceAll('\\\\', '/');\n if (value.startsWith('/') || /^[A-Za-z]:\\//.test(value) || value.startsWith('//'))\n return undefined;\n const parts: string[] = [];\n for (const part of value.split('/')) {\n if (part === '' || part === '.') continue;\n if (part === '..') {\n if (parts.at(-1) !== undefined && parts.at(-1) !== '..') parts.pop();\n else parts.push('..');\n } else {\n parts.push(part);\n }\n }\n return parts.join('/');\n}\n\nfunction requestSegments(raw: string): string[] {\n const value = raw\n .replaceAll('\\\\', '/')\n .replace(/^[A-Za-z]:\\//, '')\n .replace(/^\\/+/, '');\n return value.split('/').filter((part) => part !== '' && part !== '.');\n}\n\nfunction uniqueMatches(paths: readonly string[], predicate: (path: string) => boolean): string[] {\n return [...new Set(paths.filter(predicate))];\n}\n\nfunction longestSuffixLength(request: readonly string[], candidate: readonly string[]): number {\n let count = 0;\n while (\n count < request.length &&\n count < candidate.length &&\n request[request.length - 1 - count]?.toLowerCase() ===\n candidate[candidate.length - 1 - count]?.toLowerCase()\n ) {\n count++;\n }\n return count;\n}\n\n/** Resolve an FBX-declared texture against a caller-authorized candidate tree. */\nexport function resolveFbxTexturePath(\n sourcePath: string,\n request: FbxTexturePathRequest,\n candidates: readonly FbxTextureCandidate[],\n): FbxTextureResolution {\n const candidatePaths = candidates.flatMap((candidate) => {\n const normalized = normalizeSourceRelativePath(candidate.relativePath);\n return normalized === undefined || normalized.length === 0 ? [] : [normalized];\n });\n const requestedPath =\n request.declaredRelativePath ?? request.declaredFilename ?? request.declaredAbsolutePath ?? '';\n void sourcePath;\n\n const choose = (\n matches: readonly string[],\n strategy: FbxTextureResolutionStrategy,\n ): FbxTextureResolution | undefined => {\n const unique = [...new Set(matches)];\n if (unique.length === 1) {\n const relativePath = unique[0];\n if (relativePath === undefined) return undefined;\n return {\n ok: true,\n relativePath,\n readUri: relativePath,\n strategy,\n };\n }\n if (unique.length > 1) {\n return {\n ok: false,\n code: 'fbx-external-texture-ambiguous',\n requestedPath,\n candidates: unique,\n };\n }\n return undefined;\n };\n\n const relativeRequest = request.declaredRelativePath ?? request.declaredFilename;\n if (relativeRequest !== undefined && !/^(?:[A-Za-z]:[\\\\/]|[\\\\/])/.test(relativeRequest)) {\n const normalizedRequest = normalizeSourceRelativePath(relativeRequest);\n if (normalizedRequest !== undefined) {\n const scopeExact = choose(\n uniqueMatches(candidatePaths, (path) => path === normalizedRequest),\n 'exact',\n );\n if (scopeExact !== undefined) return scopeExact;\n const scopeFolded = choose(\n uniqueMatches(\n candidatePaths,\n (path) => path.toLowerCase() === normalizedRequest.toLowerCase(),\n ),\n 'case-folded',\n );\n if (scopeFolded !== undefined) return scopeFolded;\n }\n }\n\n const requestedSegments = requestSegments(requestedPath);\n if (requestedSegments.length > 0) {\n const scored = candidatePaths.map((path) => ({\n path,\n score: longestSuffixLength(requestedSegments, path.split('/')),\n }));\n const bestScore = Math.max(0, ...scored.map((entry) => entry.score));\n if (bestScore > 0) {\n const best = scored.filter((entry) => entry.score === bestScore).map((entry) => entry.path);\n const strategy: FbxTextureResolutionStrategy = bestScore === 1 ? 'basename' : 'suffix';\n const suffix = choose(best, strategy);\n if (suffix !== undefined) return suffix;\n }\n }\n\n return {\n ok: false,\n code: 'fbx-external-texture-missing',\n requestedPath,\n candidates: candidatePaths,\n };\n}\n","/**\n * @forgeax/engine-fbx — barrel entry point.\n *\n * FBX importer via ufbx compiled to WebAssembly. This file carries the WASM\n * runtime (initFbxWasm / parseFbx) plus the barrel re-exports of the\n * parse-*.ts bridge layer + `fbxImporter` (single-entry indexability, charter\n * F1). Both browser and Node resolve through the same self-loading WASM glue.\n *\n * Usage:\n * import { fbxImporter } from '@forgeax/engine-fbx'; // build-time importer\n * // or the low-level parse API:\n * import { initFbxWasm, parseFbx } from '@forgeax/engine-fbx';\n * await initFbxWasm(); // load .wasm once\n * const json = parseFbx(fbxBytes); // Uint8Array -> JSON string\n * const pod = JSON.parse(json); // engine FBX POD schema\n *\n * WASM asset resolution (mirrors @forgeax/engine-wgpu-wasm):\n * - Browser / Vite: new URL() resolves to a fetch-able asset URL.\n * - Node runtime: the emcc glue is built with ENVIRONMENT=web,node, so it\n * self-loads the .wasm via fs from the locateFile URL — no manual\n * fs.readFile + wasmBinary hand-off in this layer (Derive, Don't Duplicate).\n * - vitest: runs under Node; same self-load path.\n */\n\n// The emcc glue (pkg/fbx-wasm.mjs) is a gitignored build artifact — present only\n// after build:wasm / fetch-wasm. It is imported LAZILY inside _loadWasm (not at\n// module top level) so that merely importing @forgeax/engine-fbx — e.g. the\n// studio editor-core barrel re-exporting cookFbxMeta, or the hermetic\n// barrel-export-contract test (bun test, no wasm build) — does NOT require the\n// built artifact. The glue is only needed once a caller invokes initFbxWasm().\ntype CreateFbxModule = (opts?: Record<string, unknown>) => Promise<FbxWasmModule>;\n\n/* ── Types ─────────────────────────────────────────────────────────── */\n\ninterface FbxWasmModule {\n /** @internal emcc-exported C entry: parse FBX bytes at ptr into internal result buffer. */\n _parseFbxWasm(ptr: number, size: number): void;\n /** @internal emcc-exported C entry: pointer to the result JSON string. */\n _getResultPtr(): number;\n /** @internal emcc-exported C entry: byte length of the result JSON string. */\n _getResultLen(): number;\n /** @internal emcc-exported C entry: free the result buffer. */\n _freeResult(): void;\n /** @internal emscripten runtime: allocate `size` bytes in the wasm heap. */\n _malloc(size: number): number;\n /** @internal emscripten runtime: free a wasm-heap pointer. */\n _free(ptr: number): void;\n HEAPU8: Uint8Array;\n UTF8ToString(ptr: number, maxLen?: number): string;\n}\n\nlet wasmModule: FbxWasmModule | null = null;\nlet initPromise: Promise<FbxWasmModule> | null = null;\n\n/* ── Internal loader ───────────────────────────────────────────────── */\n\nasync function _loadWasm(overrideUrl?: string): Promise<FbxWasmModule> {\n // Lazy-load the emcc glue only now that a caller actually wants the wasm.\n // @vite-ignore keeps the bundler from eagerly resolving the (possibly unbuilt)\n // artifact at import-graph time; it resolves at call time in every scenario\n // (browser/Vite, Node, vitest) exactly as the old top-level import did.\n const glueId = '../pkg/fbx-wasm.mjs';\n const createModule = ((await import(/* @vite-ignore */ glueId)) as { default: CreateFbxModule })\n .default;\n\n // The emcc glue (ENVIRONMENT=web,node) self-loads the .wasm from this URL:\n // via fetch() in the browser, via fs in Node. We only tell it where to look.\n const wasmAssetUrl = overrideUrl\n ? new URL(overrideUrl, import.meta.url)\n : new URL('../pkg/fbx-wasm.wasm', import.meta.url);\n\n const opts: Record<string, unknown> = {\n locateFile: () => wasmAssetUrl.href,\n };\n\n try {\n return await createModule(opts);\n } catch (cause) {\n throw new Error(\n `@forgeax/engine-fbx: failed to load WASM from ${wasmAssetUrl.href}. ` +\n 'pkg/fbx-wasm.wasm may be missing. Self-help: ' +\n '(1) fetch a prebuilt artifact via `pnpm -F @forgeax/engine-fbx fetch-wasm`, or ' +\n '(2) compile locally with emcc via `pnpm -F @forgeax/engine-fbx build:wasm`.',\n { cause },\n );\n }\n}\n\n/* ── Public API ────────────────────────────────────────────────────── */\n\n/**\n * Initialize the WASM module. Must be called once before `parseFbx`.\n * Safe to call multiple times (idempotent). Null-resets on failure so\n * transient errors (e.g. fetch jitter) are retryable.\n *\n * @param wasmUrl — optional override URL for the .wasm file\n */\nexport async function initFbxWasm(wasmUrl?: string): Promise<void> {\n if (wasmModule) return;\n\n if (!initPromise) {\n initPromise = _loadWasm(wasmUrl).catch((e: unknown) => {\n initPromise = null;\n throw e;\n });\n }\n\n wasmModule = await initPromise;\n}\n\n/**\n * Parse an FBX file in-memory and return the JSON POD string.\n *\n * The returned JSON follows the engine FBX POD schema, containing:\n * meshes, nodes, materials, skeletons, skins, clips.\n *\n * @param fbxBytes — raw FBX file bytes (binary or ASCII)\n * @returns JSON string matching the engine's FBX POD schema\n * @throws if WASM module is not initialized or parse fails\n */\nexport function parseFbx(fbxBytes: Uint8Array): string {\n if (!wasmModule) {\n throw new Error('@forgeax/engine-fbx: WASM not initialized. Call initFbxWasm() first.');\n }\n\n const mod = wasmModule;\n const size = fbxBytes.byteLength;\n\n const ptr = mod._malloc(size);\n if (!ptr) throw new Error('fbx-wasm: malloc failed for input buffer');\n\n try {\n mod.HEAPU8.set(fbxBytes, ptr);\n mod._parseFbxWasm(ptr, size);\n } finally {\n mod._free(ptr);\n }\n\n const resultPtr = mod._getResultPtr();\n const resultLen = mod._getResultLen();\n\n if (!resultPtr || !resultLen) {\n mod._freeResult();\n throw new Error('fbx-wasm: parseFbxWasm returned empty result');\n }\n\n // Decode via a fresh sliced copy, NOT mod.UTF8ToString. Under\n // ALLOW_MEMORY_GROWTH=1 the emcc glue backs HEAPU8 with a *resizable*\n // ArrayBuffer (wasmMemory.toResizableBuffer()); glue's UTF8ArrayToString then\n // calls TextDecoder.decode(HEAPU8.subarray(...)), which modern Chromium\n // rejects (\"The provided ArrayBuffer value must not be resizable\"). HEAPU8\n // .slice() returns a copy backed by a plain, non-resizable ArrayBuffer, so the\n // decode is accepted in every environment (browser/Vite, Node, vitest).\n const bytes = mod.HEAPU8.slice(resultPtr, resultPtr + resultLen);\n mod._freeResult();\n const json = new TextDecoder().decode(bytes);\n\n const firstChars = json.substring(0, 30);\n if (firstChars.includes('\"error\"')) {\n const parsed = JSON.parse(json);\n if (parsed.error) {\n throw new Error(`fbx-wasm: ${parsed.error.message || 'parse failed'}`);\n }\n }\n\n return json;\n}\n\n/**\n * Convenience: parse FBX bytes and return the parsed POD object.\n */\nexport function parseFbxToObject(fbxBytes: Uint8Array): Record<string, unknown> {\n return JSON.parse(parseFbx(fbxBytes));\n}\n\n/**\n * Check if the WASM module is ready.\n */\nexport function isFbxWasmReady(): boolean {\n return wasmModule !== null;\n}\n\n/* ── Bridge-layer barrel (parse-*.ts + importer + errors) ──────────── */\n\nexport {\n FBX_ERROR_HINTS,\n type FbxError,\n type FbxErrorCode,\n type FbxErrorDetail,\n fbxErr,\n} from './errors.js';\nexport {\n deriveFbxSourceKeys,\n fbxImporter,\n sourceKeyForFbxOutput,\n} from './fbx-importer.js';\nexport {\n type FbxRawAnimDoc,\n type FbxRawClip,\n parseAnimationClips,\n} from './parse-animation-clip.js';\nexport { type FbxRawMaterial, parseMaterial } from './parse-material.js';\nexport { type FbxRawDocument, type FbxRawMesh, parseMesh } from './parse-mesh.js';\nexport { type FbxRawNode, type FbxRawNodes, parseScene } from './parse-scene.js';\nexport { type FbxRawSkeletonDoc, parseSkeleton } from './parse-skeleton.js';\nexport { type FbxRawSkinDoc, parseSkin } from './parse-skin.js';\nexport { type FbxRawTexture, type FbxRawTextures, parseTextures } from './parse-texture.js';\nexport {\n type FbxTextureCandidate,\n type FbxTexturePathRequest,\n type FbxTextureResolution,\n type FbxTextureResolutionStrategy,\n resolveFbxTexturePath,\n} from './resolve-texture-path.js';\nexport { toAssetPack } from './to-asset-pack.js';\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { AnimationClipPod } from '@forgeax/engine-types';
|
|
2
|
+
import { type FbxError, type Result } from './errors.js';
|
|
3
|
+
export interface FbxRawAnimChannel {
|
|
4
|
+
readonly targetNode: string;
|
|
5
|
+
readonly property: 'translation' | 'rotation' | 'scale' | 'weights';
|
|
6
|
+
/** Ascending key timestamps in seconds. */
|
|
7
|
+
readonly keyTimes?: number[];
|
|
8
|
+
/** Interleaved key values, stride 3/4 or weightCount for morph weights. */
|
|
9
|
+
readonly keyValues?: number[];
|
|
10
|
+
/** Number of morph weight elements in each sampled key. */
|
|
11
|
+
readonly weightCount?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface FbxRawClip {
|
|
14
|
+
readonly name?: string;
|
|
15
|
+
readonly duration: number;
|
|
16
|
+
readonly channels: readonly FbxRawAnimChannel[];
|
|
17
|
+
}
|
|
18
|
+
export interface FbxRawAnimDoc {
|
|
19
|
+
readonly clips?: readonly FbxRawClip[];
|
|
20
|
+
}
|
|
21
|
+
interface FbxAnimationNode {
|
|
22
|
+
readonly name: string;
|
|
23
|
+
readonly children: readonly number[];
|
|
24
|
+
}
|
|
25
|
+
export declare function resolveAnimationTargetIds(nodes: readonly FbxAnimationNode[], clips: readonly FbxRawClip[]): Result<void, FbxError>;
|
|
26
|
+
/**
|
|
27
|
+
* Parse animation clips from a C++ JSON POD document.
|
|
28
|
+
* Performs merge-keys + linear resample at the requested fps
|
|
29
|
+
* (default 30). OOS-9: Hermite tangent data is discarded.
|
|
30
|
+
*
|
|
31
|
+
* Returns an empty array when the document has no clip data.
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseAnimationClips(doc: FbxRawAnimDoc, fps?: number): AnimationClipPod[];
|
|
34
|
+
export {};
|
|
35
|
+
//# sourceMappingURL=parse-animation-clip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-animation-clip.d.ts","sourceRoot":"","sources":["../src/parse-animation-clip.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAEV,gBAAgB,EAEjB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAO,KAAK,QAAQ,EAAc,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;IACpE,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,CAAC;CACjD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CACxC;AA0GD,UAAU,gBAAgB;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,SAAS,gBAAgB,EAAE,EAClC,KAAK,EAAE,SAAS,UAAU,EAAE,GAC3B,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CA6ExB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,aAAa,EAClB,GAAG,GAAE,MAAoB,GACxB,gBAAgB,EAAE,CAWpB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MaterialPod } from '@forgeax/engine-types';
|
|
2
|
+
/** JSON shape emitted by binding.cc WriteMaterials for a single material. */
|
|
3
|
+
export interface FbxRawMaterial {
|
|
4
|
+
readonly name?: string;
|
|
5
|
+
readonly kind: 'stingray-pbs' | 'phong' | 'lambert' | 'fallback';
|
|
6
|
+
readonly baseColor?: readonly [number, number, number];
|
|
7
|
+
readonly diffuse?: readonly [number, number, number];
|
|
8
|
+
readonly shininess?: number;
|
|
9
|
+
readonly specular?: readonly [number, number, number];
|
|
10
|
+
readonly stingrayProps?: {
|
|
11
|
+
readonly baseColor?: readonly [number, number, number];
|
|
12
|
+
readonly metallic?: number;
|
|
13
|
+
readonly roughness?: number;
|
|
14
|
+
readonly emissive?: readonly [number, number, number];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse a single FBX raw material JSON node into a MaterialPod.
|
|
19
|
+
*
|
|
20
|
+
* The caller (fbx-importer.ts) iterates the top-level `materials` array
|
|
21
|
+
* from the C++ binding JSON output.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseMaterial(raw: FbxRawMaterial, sourceIndex: number): MaterialPod;
|
|
24
|
+
//# sourceMappingURL=parse-material.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-material.d.ts","sourceRoot":"","sources":["../src/parse-material.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,6EAA6E;AAC7E,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;IACjE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACvD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;KACvD,CAAC;CACH;AAWD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,GAAG,WAAW,CAiDnF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { MeshPod } from '@forgeax/engine-types';
|
|
2
|
+
export interface FbxRawMesh {
|
|
3
|
+
readonly name?: string;
|
|
4
|
+
readonly vertices: number[];
|
|
5
|
+
readonly indices?: number[];
|
|
6
|
+
readonly attributes: Record<string, number[]>;
|
|
7
|
+
readonly polygonCount: number;
|
|
8
|
+
readonly sourceIndex: number;
|
|
9
|
+
readonly materialIndex: number;
|
|
10
|
+
readonly morphTargets?: readonly {
|
|
11
|
+
readonly position?: number[];
|
|
12
|
+
readonly normal?: number[];
|
|
13
|
+
readonly tangent?: number[];
|
|
14
|
+
}[];
|
|
15
|
+
readonly morphWeights?: number[];
|
|
16
|
+
}
|
|
17
|
+
export interface FbxRawDocument {
|
|
18
|
+
readonly meshes?: readonly FbxRawMesh[];
|
|
19
|
+
}
|
|
20
|
+
export declare function parseMesh(raw: FbxRawMesh, sourceIndex: number): MeshPod;
|
|
21
|
+
//# sourceMappingURL=parse-mesh.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-mesh.d.ts","sourceRoot":"","sources":["../src/parse-mesh.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAe,MAAM,uBAAuB,CAAC;AAKlE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS;QAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KAC7B,EAAE,CAAC;IACJ,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CACzC;AAsBD,wBAAgB,SAAS,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CA+KvE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { ScenePod } from '@forgeax/engine-types';
|
|
2
|
+
export interface FbxRawNode {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly transform: {
|
|
5
|
+
readonly translation: [number, number, number];
|
|
6
|
+
readonly rotation: [number, number, number, number];
|
|
7
|
+
readonly scale: [number, number, number];
|
|
8
|
+
};
|
|
9
|
+
readonly meshIndex: number;
|
|
10
|
+
readonly children: readonly number[];
|
|
11
|
+
}
|
|
12
|
+
export interface FbxRawNodes {
|
|
13
|
+
readonly nodes?: readonly FbxRawNode[];
|
|
14
|
+
}
|
|
15
|
+
export type FbxNodePathResult = {
|
|
16
|
+
readonly ok: true;
|
|
17
|
+
readonly value: readonly string[];
|
|
18
|
+
} | {
|
|
19
|
+
readonly ok: false;
|
|
20
|
+
readonly reason: 'name-missing' | 'path-invalid' | 'hierarchy-cycle';
|
|
21
|
+
readonly nodeIndex: number;
|
|
22
|
+
};
|
|
23
|
+
export declare function buildFbxNodePaths(nodes: readonly {
|
|
24
|
+
readonly name?: string;
|
|
25
|
+
readonly children?: readonly number[];
|
|
26
|
+
}[]): readonly FbxNodePathResult[];
|
|
27
|
+
export declare function parseScene(rawNodes: FbxRawNodes): ScenePod;
|
|
28
|
+
//# sourceMappingURL=parse-scene.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-scene.d.ts","sourceRoot":"","sources":["../src/parse-scene.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC/C,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACpD,QAAQ,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;KAC1C,CAAC;IACF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CACxC;AAED,MAAM,MAAM,iBAAiB,GACzB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACxD;IACE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,GAAG,iBAAiB,CAAC;IACrE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEN,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,SAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAAE,GAClF,SAAS,iBAAiB,EAAE,CA0B9B;AAED,wBAAgB,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,QAAQ,CAiB1D"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SkeletonPod } from '@forgeax/engine-types';
|
|
2
|
+
export interface FbxRawSkeleton {
|
|
3
|
+
readonly jointCount: number;
|
|
4
|
+
readonly inverseBindMatrices: number[];
|
|
5
|
+
readonly jointPaths: string[];
|
|
6
|
+
}
|
|
7
|
+
export interface FbxRawSkeletonDoc {
|
|
8
|
+
readonly skeletons?: readonly FbxRawSkeleton[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Parse the first skeleton from a C++ JSON POD document.
|
|
12
|
+
* Returns an empty skeleton when the document has no skeleton data.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseSkeleton(doc: FbxRawSkeletonDoc): SkeletonPod;
|
|
15
|
+
//# sourceMappingURL=parse-skeleton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-skeleton.d.ts","sourceRoot":"","sources":["../src/parse-skeleton.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,cAAc,EAAE,CAAC;CAChD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,WAAW,CAejE"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SkinPod } from '@forgeax/engine-types';
|
|
2
|
+
export interface FbxRawSkinInfluence {
|
|
3
|
+
readonly jointIndices: number[];
|
|
4
|
+
readonly jointWeights: number[];
|
|
5
|
+
}
|
|
6
|
+
export interface FbxRawSkin {
|
|
7
|
+
readonly meshSourceIndex: number;
|
|
8
|
+
readonly jointPaths: string[];
|
|
9
|
+
readonly vertexCount: number;
|
|
10
|
+
readonly influences: readonly FbxRawSkinInfluence[];
|
|
11
|
+
}
|
|
12
|
+
export interface FbxRawSkinDoc {
|
|
13
|
+
readonly skins?: readonly FbxRawSkin[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Parse the first skin from a C++ JSON POD document.
|
|
17
|
+
* Returns an empty skin when the document has no skin data.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseSkin(doc: FbxRawSkinDoc): SkinPod;
|
|
20
|
+
//# sourceMappingURL=parse-skin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-skin.d.ts","sourceRoot":"","sources":["../src/parse-skin.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,OAAO,EAA0B,MAAM,uBAAuB,CAAC;AAE7E,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACrD;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;CACxC;AAmBD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAgBrD"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TexturePod } from '@forgeax/engine-types';
|
|
2
|
+
export interface FbxRawTexture {
|
|
3
|
+
readonly name?: string;
|
|
4
|
+
readonly filePath: string;
|
|
5
|
+
readonly sourceIndex: number;
|
|
6
|
+
}
|
|
7
|
+
export interface FbxRawTextures {
|
|
8
|
+
readonly textures?: readonly FbxRawTexture[];
|
|
9
|
+
}
|
|
10
|
+
export declare function parseTextures(raw: FbxRawTextures): TexturePod[];
|
|
11
|
+
//# sourceMappingURL=parse-texture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-texture.d.ts","sourceRoot":"","sources":["../src/parse-texture.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC9C;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,cAAc,GAAG,UAAU,EAAE,CAO/D"}
|