@helix3/helix-cli 0.1.4-helix3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +64 -0
  3. package/dist/ability.d.ts +73 -0
  4. package/dist/ability.js +120 -0
  5. package/dist/ability.js.map +1 -0
  6. package/dist/api.d.ts +24 -0
  7. package/dist/api.js +83 -0
  8. package/dist/api.js.map +1 -0
  9. package/dist/browserLogin.d.ts +22 -0
  10. package/dist/browserLogin.js +148 -0
  11. package/dist/browserLogin.js.map +1 -0
  12. package/dist/bundle.d.ts +15 -0
  13. package/dist/bundle.js +98 -0
  14. package/dist/bundle.js.map +1 -0
  15. package/dist/character/canonicalSkeleton.d.ts +3 -0
  16. package/dist/character/canonicalSkeleton.js +23 -0
  17. package/dist/character/canonicalSkeleton.js.map +1 -0
  18. package/dist/character/canonicalSkeletonData.d.ts +6 -0
  19. package/dist/character/canonicalSkeletonData.js +92 -0
  20. package/dist/character/canonicalSkeletonData.js.map +1 -0
  21. package/dist/character/esm.d.ts +1 -0
  22. package/dist/character/esm.js +6 -0
  23. package/dist/character/esm.js.map +1 -0
  24. package/dist/character/importCharacter.d.ts +88 -0
  25. package/dist/character/importCharacter.js +293 -0
  26. package/dist/character/importCharacter.js.map +1 -0
  27. package/dist/character/mat4.d.ts +29 -0
  28. package/dist/character/mat4.js +103 -0
  29. package/dist/character/mat4.js.map +1 -0
  30. package/dist/character/meshyToHelixMap.d.ts +2 -0
  31. package/dist/character/meshyToHelixMap.js +40 -0
  32. package/dist/character/meshyToHelixMap.js.map +1 -0
  33. package/dist/character/quat.d.ts +15 -0
  34. package/dist/character/quat.js +137 -0
  35. package/dist/character/quat.js.map +1 -0
  36. package/dist/character/stages/bakeTexture.d.ts +20 -0
  37. package/dist/character/stages/bakeTexture.js +396 -0
  38. package/dist/character/stages/bakeTexture.js.map +1 -0
  39. package/dist/character/stages/conform.d.ts +56 -0
  40. package/dist/character/stages/conform.js +292 -0
  41. package/dist/character/stages/conform.js.map +1 -0
  42. package/dist/character/stages/ktx2.d.ts +22 -0
  43. package/dist/character/stages/ktx2.js +97 -0
  44. package/dist/character/stages/ktx2.js.map +1 -0
  45. package/dist/character/stages/mergeLods.d.ts +15 -0
  46. package/dist/character/stages/mergeLods.js +42 -0
  47. package/dist/character/stages/mergeLods.js.map +1 -0
  48. package/dist/character/stages/report.d.ts +2 -0
  49. package/dist/character/stages/report.js +19 -0
  50. package/dist/character/stages/report.js.map +1 -0
  51. package/dist/character/stages/resizeTextures.d.ts +11 -0
  52. package/dist/character/stages/resizeTextures.js +62 -0
  53. package/dist/character/stages/resizeTextures.js.map +1 -0
  54. package/dist/character/stages/retarget.d.ts +49 -0
  55. package/dist/character/stages/retarget.js +105 -0
  56. package/dist/character/stages/retarget.js.map +1 -0
  57. package/dist/character/stages/retargetClip.d.ts +27 -0
  58. package/dist/character/stages/retargetClip.js +237 -0
  59. package/dist/character/stages/retargetClip.js.map +1 -0
  60. package/dist/character/stages/simplifyMesh.d.ts +15 -0
  61. package/dist/character/stages/simplifyMesh.js +37 -0
  62. package/dist/character/stages/simplifyMesh.js.map +1 -0
  63. package/dist/character/stages/splitFacePrimitive.d.ts +30 -0
  64. package/dist/character/stages/splitFacePrimitive.js +115 -0
  65. package/dist/character/stages/splitFacePrimitive.js.map +1 -0
  66. package/dist/character/stages/weldedSimplify.d.ts +32 -0
  67. package/dist/character/stages/weldedSimplify.js +202 -0
  68. package/dist/character/stages/weldedSimplify.js.map +1 -0
  69. package/dist/character/testutil/syntheticRig.d.ts +9 -0
  70. package/dist/character/testutil/syntheticRig.js +84 -0
  71. package/dist/character/testutil/syntheticRig.js.map +1 -0
  72. package/dist/config.d.ts +25 -0
  73. package/dist/config.js +103 -0
  74. package/dist/config.js.map +1 -0
  75. package/dist/index.d.ts +2 -0
  76. package/dist/index.js +378 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/init.d.ts +1 -0
  79. package/dist/init.js +87 -0
  80. package/dist/init.js.map +1 -0
  81. package/dist/initAbility.d.ts +1 -0
  82. package/dist/initAbility.js +71 -0
  83. package/dist/initAbility.js.map +1 -0
  84. package/dist/install.d.ts +51 -0
  85. package/dist/install.js +201 -0
  86. package/dist/install.js.map +1 -0
  87. package/dist/lib.d.ts +88 -0
  88. package/dist/lib.js +347 -0
  89. package/dist/lib.js.map +1 -0
  90. package/dist/package.d.ts +11 -0
  91. package/dist/package.js +136 -0
  92. package/dist/package.js.map +1 -0
  93. package/dist/prompt.d.ts +2 -0
  94. package/dist/prompt.js +55 -0
  95. package/dist/prompt.js.map +1 -0
  96. package/dist/resolve.d.ts +57 -0
  97. package/dist/resolve.js +103 -0
  98. package/dist/resolve.js.map +1 -0
  99. package/dist/tsconfig.build.tsbuildinfo +1 -0
  100. package/package.json +58 -0
  101. package/vendor/ability-manifest.mjs +558 -0
  102. package/vendor/installed-index.mjs +71 -0
@@ -0,0 +1,56 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ import type { BoneMap } from './retarget';
3
+ export interface SkelNodeDef {
4
+ name: string;
5
+ /** local rest transform, column-major 16 */
6
+ local: number[];
7
+ parent: string | null;
8
+ }
9
+ export interface CanonicalSkeleton {
10
+ /** every node in the skeleton subtree (joints + structural, e.g. metacarpals), DFS order */
11
+ nodes: SkelNodeDef[];
12
+ /** the 68 skin joints, in skin joint order */
13
+ jointNames: string[];
14
+ /** world rest transform per node, accumulated from the skeleton root (root parent = identity) */
15
+ worldByName: Map<string, number[]>;
16
+ skeletonRootName: string;
17
+ }
18
+ /**
19
+ * Reads the canonical helix-humanoid@1 rest skeleton out of a shipped body GLB (body-m-default): the
20
+ * full bone subtree (local rest transforms + hierarchy) and the skin's joint order. World transforms
21
+ * are recomputed from the skeleton root down (independent of the source file's mesh-node ancestor),
22
+ * so a rebuilt copy with the root at scene identity reproduces them exactly.
23
+ */
24
+ export declare function extractCanonicalSkeleton(document: Document): CanonicalSkeleton;
25
+ export interface ConformResult {
26
+ mode: 'embed' | 'repose';
27
+ verticesProcessed: number;
28
+ jointsRebuilt: number;
29
+ /** warrior joint name -> helix joint that received its weights (via map, or nearest mapped ancestor) */
30
+ weightTargets: Record<string, string>;
31
+ }
32
+ export interface ConformOptions {
33
+ /**
34
+ * 'embed' (default): keep the source mesh EXACTLY (no distortion), embed the canonical skeleton at the
35
+ * source's own joint positions with canonical orientations. 'repose': re-pose the mesh onto the
36
+ * canonical rest via frame-based deltas (mesh conforms to canonical proportions — use only when a rig
37
+ * with canonical proportions is wanted over preserving the source character's silhouette).
38
+ */
39
+ mode?: 'embed' | 'repose';
40
+ }
41
+ /**
42
+ * Retargets a source character onto `helix-humanoid@1` so the PLATFORM's shared clips drive it.
43
+ *
44
+ * 'embed' (default, the better retarget): the source mesh is left byte-for-byte unchanged and the
45
+ * canonical 68-bone skeleton is fitted INTO it (canonical bone orientations at the source's joint
46
+ * positions, §fitSkeletonToWarrior). Clips — authored as local rotations relative to the canonical rest
47
+ * — produce the correct WORLD-space motion regardless of the source's bone-axis convention, because the
48
+ * mesh rides the bones in world space (we never route the mesh through mismatched local frames). Output
49
+ * IBMs = inverse(fitted world), so LBS at rest reproduces the pristine source bind pose.
50
+ *
51
+ * 'repose' re-poses the mesh onto the canonical rest via frame-based rest-pose correction (kept for
52
+ * cases wanting canonical proportions); it reshapes the mesh and is not the default.
53
+ *
54
+ * Source joints with no map entry fold onto their nearest mapped ancestor.
55
+ */
56
+ export declare function conformToHelixRest(warrior: Document, canon: CanonicalSkeleton, boneMap: BoneMap, opts?: ConformOptions): ConformResult;
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ // PORTED from helix-web-engine-new/tools/character-pipeline — the source of truth for the character
3
+ // pipeline. SYNC OBLIGATION: fix bugs there first, then mirror the change here; do not diverge.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.extractCanonicalSkeleton = extractCanonicalSkeleton;
6
+ exports.conformToHelixRest = conformToHelixRest;
7
+ const core_1 = require("@gltf-transform/core");
8
+ const mat4_1 = require("../mat4");
9
+ const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
10
+ const posOf = (m) => [m[12], m[13], m[14]];
11
+ const vlen = (v) => Math.hypot(v[0], v[1], v[2]);
12
+ /** Apply the transpose (=inverse, for a rotation) of a column-major matrix's upper 3x3 to a vector. */
13
+ const applyRotT = (m, v) => [m[0] * v[0] + m[1] * v[1] + m[2] * v[2], m[4] * v[0] + m[5] * v[1] + m[6] * v[2], m[8] * v[0] + m[9] * v[1] + m[10] * v[2]];
14
+ function parentNode(node) {
15
+ for (const p of node.listParents())
16
+ if (p.propertyType === core_1.PropertyType.NODE)
17
+ return p;
18
+ return null;
19
+ }
20
+ /**
21
+ * Reads the canonical helix-humanoid@1 rest skeleton out of a shipped body GLB (body-m-default): the
22
+ * full bone subtree (local rest transforms + hierarchy) and the skin's joint order. World transforms
23
+ * are recomputed from the skeleton root down (independent of the source file's mesh-node ancestor),
24
+ * so a rebuilt copy with the root at scene identity reproduces them exactly.
25
+ */
26
+ function extractCanonicalSkeleton(document) {
27
+ const skin = document.getRoot().listSkins()[0];
28
+ if (skin === undefined)
29
+ throw new Error('extractCanonicalSkeleton: no skin in the canonical body GLB');
30
+ const jointNames = skin.listJoints().map((j) => j.getName());
31
+ const rootNode = skin.getSkeleton() ?? skin.listJoints()[0];
32
+ const nodes = [];
33
+ const worldByName = new Map();
34
+ const visit = (node, parent, parentWorld) => {
35
+ const local = node.getMatrix();
36
+ const world = (0, mat4_1.mul4)(parentWorld, local);
37
+ const name = node.getName();
38
+ nodes.push({ name, local, parent });
39
+ worldByName.set(name, world);
40
+ for (const child of node.listChildren())
41
+ visit(child, name, world);
42
+ };
43
+ visit(rootNode, null, IDENTITY);
44
+ return { nodes, jointNames, worldByName, skeletonRootName: rootNode.getName() };
45
+ }
46
+ /**
47
+ * Fits the canonical skeleton onto a source character's proportions: KEEPS every canonical bone's local
48
+ * REST ROTATION (so target clips apply natively) but sets each bone's WORLD POSITION to the source's
49
+ * corresponding joint — directly for mapped bones, and for unmapped in-betweens (spine_02/04, neck_02,
50
+ * twists, fingers) by scaling their canonical offset-from-parent by the enclosing mapped segment's
51
+ * scale. The result is a rig with canonical orientations at the source's own joint positions, so the
52
+ * source mesh binds to it UNCHANGED (no shape distortion — the whole point vs. re-posing the mesh).
53
+ */
54
+ function fitSkeletonToWarrior(canon, directPos) {
55
+ const canonPos = (n) => posOf(canon.worldByName.get(n));
56
+ // Pass 1 — desired world position per bone (canon.nodes is DFS, parent before child).
57
+ const desired = new Map();
58
+ const scaleBy = new Map();
59
+ for (const def of canon.nodes) {
60
+ if (def.parent === null) {
61
+ desired.set(def.name, canonPos(def.name));
62
+ scaleBy.set(def.name, 1);
63
+ continue;
64
+ }
65
+ const pPos = desired.get(def.parent);
66
+ const canonOff = (0, mat4_1.sub3)(canonPos(def.name), canonPos(def.parent));
67
+ if (directPos.has(def.name)) {
68
+ const dp = directPos.get(def.name);
69
+ desired.set(def.name, dp);
70
+ const cl = vlen(canonOff);
71
+ scaleBy.set(def.name, cl > 1e-6 ? vlen((0, mat4_1.sub3)(dp, pPos)) / cl : (scaleBy.get(def.parent) ?? 1));
72
+ }
73
+ else {
74
+ const s = scaleBy.get(def.parent) ?? 1;
75
+ desired.set(def.name, [pPos[0] + canonOff[0] * s, pPos[1] + canonOff[1] * s, pPos[2] + canonOff[2] * s]);
76
+ scaleBy.set(def.name, s);
77
+ }
78
+ }
79
+ // Pass 2 — rebuild local matrices = canonical local ROTATION + fitted local TRANSLATION; recompute world.
80
+ // Exception — CLAVICLE rest-correction: the source's shoulder mesh is authored for its own clavicle
81
+ // direction (Meshy is ~horizontal; MetaHuman droops ~9°). Keeping the canonical clavicle rest binds the
82
+ // shoulder to the wrong reference, so a SHARED canonical clip drives the animated shoulder ~9° too
83
+ // horizontal (a shrug). Fix: rebase ONLY the two clavicle bones' rest ORIENTATION to point along the
84
+ // SOURCE clavicle direction. The IBM (inverse of this rest) then re-references the clip — the ~9° gap
85
+ // between the clip's canonical clavicle pose and this source-aligned rest becomes the corrective pull,
86
+ // so the animated shoulder matches the stock body. Children keep canonical local rotation and ride the
87
+ // correction. Positions/proportions untouched (lt kept); rest render stays pristine (M·IBM = I).
88
+ const ORIGIN = [0, 0, 0];
89
+ const CLAVICLE_CHILD = { clavicle_l: 'upperarm_l', clavicle_r: 'upperarm_r' };
90
+ const world = new Map();
91
+ const nodes = [];
92
+ for (const def of canon.nodes) {
93
+ const parentWorld = def.parent !== null ? world.get(def.parent) : IDENTITY;
94
+ const worldOff = def.parent !== null ? (0, mat4_1.sub3)(desired.get(def.name), desired.get(def.parent)) : desired.get(def.name);
95
+ const lt = def.parent !== null ? applyRotT(parentWorld, worldOff) : worldOff; // into parent's (canonical) frame
96
+ let rot = (0, mat4_1.rigidize)(def.local); // default: canonical local orientation
97
+ const clavChild = CLAVICLE_CHILD[def.name];
98
+ if (clavChild !== undefined && directPos.has(def.name) && directPos.has(clavChild)) {
99
+ const srcDir = (0, mat4_1.normalize3)((0, mat4_1.sub3)(directPos.get(clavChild), directPos.get(def.name))); // warrior clavicle dir
100
+ const canonDir = (0, mat4_1.normalize3)((0, mat4_1.sub3)(canonPos(clavChild), canonPos(def.name))); // canonical clavicle dir
101
+ const O = (0, mat4_1.mul4)((0, mat4_1.frameFromAxis)(canonDir, ORIGIN), (0, mat4_1.invert4)((0, mat4_1.frameFromAxis)(srcDir, ORIGIN))); // world src->canon
102
+ const worldRotDes = (0, mat4_1.mul4)((0, mat4_1.invert4)(O), (0, mat4_1.rigidize)(canon.worldByName.get(def.name))); // canon->src rest world
103
+ rot = (0, mat4_1.mul4)((0, mat4_1.invert4)((0, mat4_1.rigidize)(parentWorld)), worldRotDes); // back to local
104
+ }
105
+ const local = [rot[0], rot[1], rot[2], 0, rot[4], rot[5], rot[6], 0, rot[8], rot[9], rot[10], 0, lt[0], lt[1], lt[2], 1];
106
+ nodes.push({ name: def.name, local, parent: def.parent });
107
+ world.set(def.name, (0, mat4_1.mul4)(parentWorld, local));
108
+ }
109
+ return { nodes, jointNames: canon.jointNames, worldByName: world, skeletonRootName: canon.skeletonRootName };
110
+ }
111
+ /**
112
+ * Retargets a source character onto `helix-humanoid@1` so the PLATFORM's shared clips drive it.
113
+ *
114
+ * 'embed' (default, the better retarget): the source mesh is left byte-for-byte unchanged and the
115
+ * canonical 68-bone skeleton is fitted INTO it (canonical bone orientations at the source's joint
116
+ * positions, §fitSkeletonToWarrior). Clips — authored as local rotations relative to the canonical rest
117
+ * — produce the correct WORLD-space motion regardless of the source's bone-axis convention, because the
118
+ * mesh rides the bones in world space (we never route the mesh through mismatched local frames). Output
119
+ * IBMs = inverse(fitted world), so LBS at rest reproduces the pristine source bind pose.
120
+ *
121
+ * 'repose' re-poses the mesh onto the canonical rest via frame-based rest-pose correction (kept for
122
+ * cases wanting canonical proportions); it reshapes the mesh and is not the default.
123
+ *
124
+ * Source joints with no map entry fold onto their nearest mapped ancestor.
125
+ */
126
+ function conformToHelixRest(warrior, canon, boneMap, opts = {}) {
127
+ const mode = opts.mode ?? 'embed';
128
+ const root = warrior.getRoot();
129
+ const wskin = root.listSkins()[0];
130
+ if (wskin === undefined)
131
+ throw new Error('conformToHelixRest: warrior GLB has no skin');
132
+ const wjoints = wskin.listJoints();
133
+ // Resolve each warrior joint to a helix joint (map, else nearest mapped ancestor).
134
+ const jointByNode = new Map(wjoints.map((j) => [j, true]));
135
+ const helixFor = (joint) => {
136
+ let cur = joint;
137
+ while (cur !== null) {
138
+ const mapped = boneMap.map[cur.getName()];
139
+ if (mapped !== undefined)
140
+ return mapped;
141
+ const p = parentNode(cur);
142
+ cur = p !== null && jointByNode.has(p) ? p : null;
143
+ }
144
+ throw new Error(`conformToHelixRest: warrior joint '${joint.getName()}' has no mapped ancestor`);
145
+ };
146
+ const helixByWarriorIdx = wjoints.map((j) => helixFor(j));
147
+ const weightTargets = {};
148
+ wjoints.forEach((j, i) => (weightTargets[j.getName()] = helixByWarriorIdx[i]));
149
+ // Warrior joint hierarchy + world rest positions.
150
+ const idxByNode = new Map(wjoints.map((j, i) => [j, i]));
151
+ const parentIdx = wjoints.map((j) => { const p = parentNode(j); return p !== null && idxByNode.has(p) ? idxByNode.get(p) : -1; });
152
+ const childIdxs = wjoints.map(() => []);
153
+ parentIdx.forEach((p, i) => { if (p >= 0)
154
+ childIdxs[p].push(i); });
155
+ const Tsrc = wjoints.map((j) => posOf(j.getWorldMatrix()));
156
+ // The rig the mesh binds to. 'embed': canonical orientations at the source's joint positions
157
+ // (proportions preserved). 'repose': the pristine canonical rest.
158
+ const directPos = new Map();
159
+ wjoints.forEach((j, i) => { const m = boneMap.map[j.getName()]; if (m !== undefined)
160
+ directPos.set(m, Tsrc[i]); });
161
+ const rig = mode === 'embed' ? fitSkeletonToWarrior(canon, directPos) : canon;
162
+ const Tdst = (helix) => posOf(rig.worldByName.get(helix));
163
+ // 'repose' only: per-warrior-joint frame-based delta D_i = frameDst·frameSrc⁻¹ (both frames from
164
+ // GEOMETRY, so the bone-axis CONVENTION cancels). Unused in 'embed' (mesh is not re-posed).
165
+ const incomingDirSrc = (i) => (parentIdx[i] >= 0 ? (0, mat4_1.normalize3)((0, mat4_1.sub3)(Tsrc[i], Tsrc[parentIdx[i]])) : [0, 1, 0]);
166
+ const incomingDirDst = (i) => parentIdx[i] >= 0 ? (0, mat4_1.normalize3)((0, mat4_1.sub3)(Tdst(helixByWarriorIdx[i]), Tdst(helixByWarriorIdx[parentIdx[i]]))) : [0, 1, 0];
167
+ const D = mode === 'repose' ? wjoints.map((_, i) => {
168
+ const inDir = incomingDirSrc(i);
169
+ let primary = -1, best = -Infinity;
170
+ for (const c of childIdxs[i]) {
171
+ if (helixByWarriorIdx[c] === helixByWarriorIdx[i])
172
+ continue;
173
+ const d = (0, mat4_1.dot3)((0, mat4_1.normalize3)((0, mat4_1.sub3)(Tsrc[c], Tsrc[i])), inDir);
174
+ if (d > best) {
175
+ best = d;
176
+ primary = c;
177
+ }
178
+ }
179
+ const axisSrc = primary >= 0 ? (0, mat4_1.normalize3)((0, mat4_1.sub3)(Tsrc[primary], Tsrc[i])) : inDir;
180
+ const axisDst = primary >= 0 ? (0, mat4_1.normalize3)((0, mat4_1.sub3)(Tdst(helixByWarriorIdx[primary]), Tdst(helixByWarriorIdx[i]))) : incomingDirDst(i);
181
+ return (0, mat4_1.mul4)((0, mat4_1.frameFromAxis)(axisDst, Tdst(helixByWarriorIdx[i])), (0, mat4_1.invert4)((0, mat4_1.frameFromAxis)(axisSrc, Tsrc[i])));
182
+ }) : null;
183
+ const canonIndexByName = new Map(canon.jointNames.map((n, i) => [n, i]));
184
+ const newIndexForWarriorIdx = wjoints.map((_, i) => {
185
+ const idx = canonIndexByName.get(helixByWarriorIdx[i]);
186
+ if (idx === undefined)
187
+ throw new Error(`conformToHelixRest: '${helixByWarriorIdx[i]}' not a canonical joint`);
188
+ return idx;
189
+ });
190
+ // Remap JOINTS_* to the canonical joint order on every primitive; in 'repose' also blend D into
191
+ // POSITION/NORMAL. In 'embed' the geometry is left untouched.
192
+ let verticesProcessed = 0;
193
+ for (const node of root.listNodes()) {
194
+ if (node.getSkin() !== wskin || node.getMesh() === null)
195
+ continue;
196
+ for (const prim of node.getMesh().listPrimitives()) {
197
+ const setCount = prim.listSemantics().filter((s) => s.startsWith('JOINTS_')).length;
198
+ if (setCount === 0)
199
+ continue;
200
+ const pos = prim.getAttribute('POSITION');
201
+ const nrm = prim.getAttribute('NORMAL');
202
+ const vCount = pos.getCount();
203
+ const jointSets = Array.from({ length: setCount }, (_, s) => new Uint32Array(prim.getAttribute(`JOINTS_${s}`).getArray()));
204
+ if (D !== null) {
205
+ const weightSets = Array.from({ length: setCount }, (_, s) => prim.getAttribute(`WEIGHTS_${s}`).getArray());
206
+ const posArr = Float32Array.from(pos.getArray());
207
+ const nrmArr = nrm !== null ? Float32Array.from(nrm.getArray()) : null;
208
+ for (let v = 0; v < vCount; v++) {
209
+ const p = [posArr[v * 3], posArr[v * 3 + 1], posArr[v * 3 + 2]];
210
+ const n = nrmArr !== null ? [nrmArr[v * 3], nrmArr[v * 3 + 1], nrmArr[v * 3 + 2]] : null;
211
+ let px = 0, py = 0, pz = 0, nx = 0, ny = 0, nz = 0, wsum = 0;
212
+ for (let s = 0; s < setCount; s++)
213
+ for (let c = 0; c < 4; c++) {
214
+ const w = weightSets[s][v * 4 + c];
215
+ if (w === 0)
216
+ continue;
217
+ const d = D[jointSets[s][v * 4 + c]];
218
+ const tp = (0, mat4_1.transformPoint)(d, p);
219
+ px += w * tp[0];
220
+ py += w * tp[1];
221
+ pz += w * tp[2];
222
+ if (n !== null) {
223
+ const td = (0, mat4_1.transformDir)(d, n);
224
+ nx += w * td[0];
225
+ ny += w * td[1];
226
+ nz += w * td[2];
227
+ }
228
+ wsum += w;
229
+ }
230
+ if (wsum > 0) {
231
+ px /= wsum;
232
+ py /= wsum;
233
+ pz /= wsum;
234
+ }
235
+ posArr[v * 3] = px;
236
+ posArr[v * 3 + 1] = py;
237
+ posArr[v * 3 + 2] = pz;
238
+ if (nrmArr !== null) {
239
+ const l = Math.hypot(nx, ny, nz) || 1;
240
+ nrmArr[v * 3] = nx / l;
241
+ nrmArr[v * 3 + 1] = ny / l;
242
+ nrmArr[v * 3 + 2] = nz / l;
243
+ }
244
+ }
245
+ pos.setArray(posArr);
246
+ if (nrm !== null && nrmArr !== null)
247
+ nrm.setArray(nrmArr);
248
+ }
249
+ for (let s = 0; s < setCount; s++) {
250
+ const src = jointSets[s];
251
+ const out = new Uint16Array(src.length);
252
+ for (let k = 0; k < src.length; k++)
253
+ out[k] = newIndexForWarriorIdx[src[k]];
254
+ prim.getAttribute(`JOINTS_${s}`).setArray(out);
255
+ }
256
+ verticesProcessed += vCount;
257
+ }
258
+ }
259
+ // Rebuild the target skeleton (`rig`) in the warrior doc.
260
+ const buffer = root.listBuffers()[0];
261
+ const created = new Map();
262
+ for (const def of rig.nodes)
263
+ created.set(def.name, warrior.createNode(def.name).setMatrix(def.local));
264
+ for (const def of rig.nodes)
265
+ if (def.parent !== null)
266
+ created.get(def.parent).addChild(created.get(def.name));
267
+ const skeletonRoot = created.get(rig.skeletonRootName);
268
+ root.listScenes()[0].addChild(skeletonRoot);
269
+ const newIbm = new Float32Array(rig.jointNames.length * 16);
270
+ rig.jointNames.forEach((name, i) => newIbm.set((0, mat4_1.invert4)(rig.worldByName.get(name)), i * 16));
271
+ const newIbmAcc = warrior.createAccessor().setType('MAT4').setArray(newIbm).setBuffer(buffer);
272
+ const newSkin = warrior.createSkin('helix-humanoid').setInverseBindMatrices(newIbmAcc).setSkeleton(skeletonRoot);
273
+ for (const name of rig.jointNames)
274
+ newSkin.addJoint(created.get(name));
275
+ // Rebind the mesh nodes, reparent to the scene at identity, and delete the old rig + its bind-pose anim.
276
+ const scene = root.listScenes()[0];
277
+ for (const node of root.listNodes()) {
278
+ if (node.getSkin() === wskin && node.getMesh() !== null) {
279
+ node.setSkin(newSkin);
280
+ node.setMatrix(IDENTITY);
281
+ scene.addChild(node);
282
+ }
283
+ }
284
+ for (const anim of root.listAnimations())
285
+ anim.dispose();
286
+ wskin.dispose();
287
+ const topOld = (() => { let cur = wjoints[0]; for (let p = parentNode(cur); p !== null; p = parentNode(cur))
288
+ cur = p; return cur; })();
289
+ topOld.dispose();
290
+ return { mode, verticesProcessed, jointsRebuilt: rig.jointNames.length, weightTargets };
291
+ }
292
+ //# sourceMappingURL=conform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conform.js","sourceRoot":"","sources":["../../../src/character/stages/conform.ts"],"names":[],"mappings":";AAAA,oGAAoG;AACpG,gGAAgG;;AAyChG,4DAkBC;AAoGD,gDA2IC;AAxSD,+CAA2E;AAC3E,kCAAkI;AAoBlI,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAClE,MAAM,KAAK,GAAG,CAAC,CAAoB,EAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAE,EAAE,CAAC,CAAC,EAAE,CAAE,EAAE,CAAC,CAAC,EAAE,CAAE,CAAC,CAAC;AACvE,MAAM,IAAI,GAAG,CAAC,CAAO,EAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/D,uGAAuG;AACvG,MAAM,SAAS,GAAG,CAAC,CAAoB,EAAE,CAAO,EAA4B,EAAE,CAC5E,CAAC,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAExI,SAAS,UAAU,CAAC,IAAU;IAC5B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE;QAAE,IAAI,CAAC,CAAC,YAAY,KAAK,mBAAY,CAAC,IAAI;YAAE,OAAO,CAAS,CAAC;IAC/F,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAgB,wBAAwB,CAAC,QAAkB;IACzD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,IAAI,IAAI,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IACvG,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC7D,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAE,CAAC;IAE7D,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAoB,CAAC;IAChD,MAAM,KAAK,GAAG,CAAC,IAAU,EAAE,MAAqB,EAAE,WAAqB,EAAQ,EAAE;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAc,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAA,WAAI,EAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC7B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,YAAY,EAAE;YAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACrE,CAAC,CAAC;IACF,KAAK,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC;IAChC,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;AAClF,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,oBAAoB,CAAC,KAAwB,EAAE,SAA4B;IAClF,MAAM,QAAQ,GAAG,CAAC,CAAS,EAAQ,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC;IAEvE,sFAAsF;IACtF,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgB,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC9B,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;YAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YAAC,SAAS;QAAC,CAAC;QAC3G,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,IAAA,WAAI,EAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;QAChE,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC1B,MAAM,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAA,WAAI,EAAC,EAAE,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChG,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACzG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,0GAA0G;IAC1G,oGAAoG;IACpG,wGAAwG;IACxG,mGAAmG;IACnG,qGAAqG;IACrG,sGAAsG;IACtG,uGAAuG;IACvG,uGAAuG;IACvG,iGAAiG;IACjG,MAAM,MAAM,GAAS,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/B,MAAM,cAAc,GAAuC,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;IAClH,MAAM,KAAK,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC1C,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;QAC9B,MAAM,WAAW,GAAG,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC5E,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAA,WAAI,EAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QACvH,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,kCAAkC;QAEhH,IAAI,GAAG,GAAG,IAAA,eAAQ,EAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,uCAAuC;QACtE,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YACnF,MAAM,MAAM,GAAG,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAE,EAAE,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,CAAC,uBAAuB;YAC7G,MAAM,QAAQ,GAAG,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAW,yBAAyB;YAC/G,MAAM,CAAC,GAAG,IAAA,WAAI,EAAC,IAAA,oBAAa,EAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,IAAA,cAAO,EAAC,IAAA,oBAAa,EAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,mBAAmB;YAC5G,MAAM,WAAW,GAAG,IAAA,WAAI,EAAC,IAAA,cAAO,EAAC,CAAC,CAAC,EAAE,IAAA,eAAQ,EAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,CAAS,wBAAwB;YAClH,GAAG,GAAG,IAAA,WAAI,EAAC,IAAA,cAAO,EAAC,IAAA,eAAQ,EAAC,WAAW,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAkC,gBAAgB;QAC5G,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,CAAC,CAAE,EAAE,GAAG,CAAC,EAAE,CAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClI,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAC1D,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAA,WAAI,EAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,WAAW,EAAE,KAAK,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,CAAC;AAC/G,CAAC;AAoBD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,kBAAkB,CAAC,OAAiB,EAAE,KAAwB,EAAE,OAAgB,EAAE,OAAuB,EAAE;IACzH,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAClC,IAAI,KAAK,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACxF,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC;IAEnC,mFAAmF;IACnF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAU,CAAC,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,CAAC,KAAW,EAAU,EAAE;QACvC,IAAI,GAAG,GAAgB,KAAK,CAAC;QAC7B,OAAO,GAAG,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC1C,IAAI,MAAM,KAAK,SAAS;gBAAE,OAAO,MAAM,CAAC;YACxC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YAC1B,GAAG,GAAG,CAAC,KAAK,IAAI,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACpD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,sCAAsC,KAAK,CAAC,OAAO,EAAE,0BAA0B,CAAC,CAAC;IACnG,CAAC,CAAC;IACF,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1D,MAAM,aAAa,GAA2B,EAAE,CAAC;IACjD,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC;IAEhF,kDAAkD;IAClD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAU,CAAC,CAAC,CAAC;IAClE,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnI,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,GAAa,EAAE,CAAC,EAAE,CAAC,CAAC;IAClD,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,IAAI,CAAC;QAAE,SAAS,CAAC,CAAC,CAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,cAAc,EAAc,CAAC,CAAC,CAAC;IAEvE,6FAA6F;IAC7F,kEAAkE;IAClE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAgB,CAAC;IAC1C,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,SAAS;QAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpH,MAAM,GAAG,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAC9E,MAAM,IAAI,GAAG,CAAC,KAAa,EAAQ,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,CAAC;IAEzE,iGAAiG;IACjG,4FAA4F;IAC5F,MAAM,cAAc,GAAG,CAAC,CAAS,EAAQ,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,IAAI,CAAC,CAAC,CAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAE,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChI,MAAM,cAAc,GAAG,CAAC,CAAS,EAAQ,EAAE,CACzC,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAE,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAE,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1H,MAAM,CAAC,GAAG,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjD,MAAM,KAAK,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,OAAO,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,CAAC,QAAQ,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,CAAC,CAAE,EAAE,CAAC;YAC9B,IAAI,iBAAiB,CAAC,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC,CAAC;gBAAE,SAAS;YAC5D,MAAM,CAAC,GAAG,IAAA,WAAI,EAAC,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,IAAI,CAAC,CAAC,CAAE,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAC5D,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC;gBAAC,IAAI,GAAG,CAAC,CAAC;gBAAC,OAAO,GAAG,CAAC,CAAC;YAAC,CAAC;QAC1C,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,IAAI,CAAC,OAAO,CAAE,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;QAClF,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,IAAA,iBAAU,EAAC,IAAA,WAAI,EAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAE,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;QACpI,OAAO,IAAA,WAAI,EAAC,IAAA,oBAAa,EAAC,OAAO,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAE,CAAC,CAAC,EAAE,IAAA,cAAO,EAAC,IAAA,oBAAa,EAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC;IAC9G,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEV,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,qBAAqB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACjD,MAAM,GAAG,GAAG,gBAAgB,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAE,CAAC,CAAC;QACxD,IAAI,GAAG,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,iBAAiB,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;QAC9G,OAAO,GAAG,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,gGAAgG;IAChG,8DAA8D;IAC9D,IAAI,iBAAiB,GAAG,CAAC,CAAC;IAC1B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,IAAI;YAAE,SAAS;QAClE,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,EAAG,CAAC,cAAc,EAAE,EAAE,CAAC;YACpD,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;YACpF,IAAI,QAAQ,KAAK,CAAC;gBAAE,SAAS;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,UAAU,CAAE,CAAC;YAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;YACxC,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAE,CAAC,QAAQ,EAAG,CAAC,CAAC,CAAC;YAE7H,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBACf,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAE,CAAC,QAAQ,EAAG,CAAC,CAAC;gBAC9G,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAG,CAAC,CAAC;gBAClD,MAAM,MAAM,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBACxE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBAChC,MAAM,CAAC,GAA6B,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC;oBAC7F,MAAM,CAAC,GAAoC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;oBAC7H,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC;oBAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE;wBAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;4BAC9D,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,CAAC;4BACrC,IAAI,CAAC,KAAK,CAAC;gCAAE,SAAS;4BACtB,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAE,CAAE,CAAC;4BACxC,MAAM,EAAE,GAAG,IAAA,qBAAc,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC;4BAChC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;4BAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;4BAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;4BAClD,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gCAAC,MAAM,EAAE,GAAG,IAAA,mBAAY,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gCAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;gCAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;gCAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;4BAAC,CAAC;4BACrG,IAAI,IAAI,CAAC,CAAC;wBACZ,CAAC;oBACD,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;wBAAC,EAAE,IAAI,IAAI,CAAC;wBAAC,EAAE,IAAI,IAAI,CAAC;wBAAC,EAAE,IAAI,IAAI,CAAC;oBAAC,CAAC;oBACrD,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;oBAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;oBAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;oBACnE,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;wBAAC,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;wBAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;oBAAC,CAAC;gBACjJ,CAAC;gBACD,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACrB,IAAI,GAAG,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI;oBAAE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC5D,CAAC;YAED,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClC,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;oBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAE,CAAE,CAAC;gBAC9E,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAClD,CAAC;YACD,iBAAiB,IAAI,MAAM,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,0DAA0D;IAC1D,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,CAAE,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAgB,CAAC;IACxC,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK;QAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,KAAc,CAAC,CAAC,CAAC;IAC/G,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK;QAAE,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC;IAChH,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,gBAAgB,CAAE,CAAC;IACxD,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;IAE7C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IAC5D,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAA,cAAO,EAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IAC7F,MAAM,SAAS,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9F,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IACjH,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,UAAU;QAAE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,CAAC;IAExE,yGAAyG;IACzG,MAAM,KAAK,GAAU,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAE,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QACpC,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,KAAK,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,CAAC;YACxD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACtB,IAAI,CAAC,SAAS,CAAC,QAAiB,CAAC,CAAC;YAClC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE;QAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IACzD,KAAK,CAAC,OAAO,EAAE,CAAC;IAChB,MAAM,MAAM,GAAG,CAAC,GAAS,EAAE,GAAG,IAAI,GAAG,GAAG,OAAO,CAAC,CAAC,CAAE,CAAC,CAAC,KAAK,IAAI,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC;QAAE,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9I,MAAM,CAAC,OAAO,EAAE,CAAC;IAEjB,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,aAAa,EAAE,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Document } from '@gltf-transform/core';
2
+ export type Ktx2Mode = 'etc1s' | 'uastc';
3
+ export interface Ktx2Result {
4
+ encoder: 'basis-wasm';
5
+ mode: Ktx2Mode;
6
+ encoded: {
7
+ name: string;
8
+ before: number;
9
+ after: number;
10
+ }[];
11
+ }
12
+ /**
13
+ * Encodes the document's color textures to KTX2 / Basis (KHR_texture_basisu) via the BasisU WASM
14
+ * encoder — GPU-compressed in VRAM (ETC1S ~6–8×, UASTC ~4×) and transcoded once at load by the
15
+ * client's KTX2Loader. Run on the FINAL merged web GLB. The import pipeline carries a single baked
16
+ * base-color atlas, so every remaining texture is an sRGB color/albedo map. Textures already in
17
+ * image/ktx2 are skipped (idempotent).
18
+ */
19
+ export declare function encodeKtx2(document: Document, opts?: {
20
+ mode?: Ktx2Mode;
21
+ quality?: number;
22
+ }): Promise<Ktx2Result>;
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ // PORTED from helix-web-engine-new/tools/character-pipeline — the source of truth for the character
3
+ // pipeline. SYNC OBLIGATION: fix bugs there first, then mirror the change here; do not diverge.
4
+ // Deliberate divergence (the one rewrite): the engine tool shells out to the toktx binary; the CLI
5
+ // encodes in-process via the ktx2-encoder WASM (BasisU) so `helix character import` needs no native
6
+ // install. Options mirror the engine's toktx flags (--encode etc1s --clevel 2 --qlevel 196 --genmipmap
7
+ // --assign_oetf srgb). Walk/extension/idempotence/result shape are kept identical.
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.encodeKtx2 = encodeKtx2;
43
+ const extensions_1 = require("@gltf-transform/extensions");
44
+ const esm_1 = require("../esm");
45
+ /**
46
+ * Encodes the document's color textures to KTX2 / Basis (KHR_texture_basisu) via the BasisU WASM
47
+ * encoder — GPU-compressed in VRAM (ETC1S ~6–8×, UASTC ~4×) and transcoded once at load by the
48
+ * client's KTX2Loader. Run on the FINAL merged web GLB. The import pipeline carries a single baked
49
+ * base-color atlas, so every remaining texture is an sRGB color/albedo map. Textures already in
50
+ * image/ktx2 are skipped (idempotent).
51
+ */
52
+ async function encodeKtx2(document, opts) {
53
+ const mode = opts?.mode ?? 'etc1s';
54
+ document.createExtension(extensions_1.KHRTextureBasisu).setRequired(true);
55
+ const { encodeToKTX2 } = (await (0, esm_1.importEsm)('ktx2-encoder'));
56
+ const sharp = (await Promise.resolve().then(() => __importStar(require('sharp')))).default;
57
+ const imageDecoder = async (buf) => {
58
+ const { data, info } = await sharp(Buffer.from(buf)).ensureAlpha().raw().toBuffer({ resolveWithObject: true });
59
+ return { width: info.width, height: info.height, data: new Uint8Array(data) };
60
+ };
61
+ // ETC1S: qualityLevel 1..255 (default 128). UASTC: uastcLDRQualityLevel 0..4. Faces are
62
+ // quality-sensitive, so default ETC1S quality high; raise/switch to uastc if blocking shows.
63
+ const options = mode === 'uastc'
64
+ ? {
65
+ isUASTC: true,
66
+ uastcLDRQualityLevel: opts?.quality ?? 2,
67
+ needSupercompression: true,
68
+ generateMipmap: true,
69
+ isPerceptual: true,
70
+ isSetKTX2SRGBTransferFunc: true,
71
+ isKTX2File: true,
72
+ imageDecoder,
73
+ }
74
+ : {
75
+ isUASTC: false,
76
+ qualityLevel: opts?.quality ?? 196,
77
+ compressionLevel: 2,
78
+ generateMipmap: true,
79
+ isPerceptual: true,
80
+ isSetKTX2SRGBTransferFunc: true,
81
+ isKTX2File: true,
82
+ imageDecoder,
83
+ };
84
+ const encoded = [];
85
+ for (const texture of document.getRoot().listTextures()) {
86
+ if (texture.getMimeType() === 'image/ktx2')
87
+ continue;
88
+ const img = texture.getImage();
89
+ if (img === null)
90
+ continue;
91
+ const ktx2 = await encodeToKTX2(img, options);
92
+ encoded.push({ name: texture.getName() || '(unnamed)', before: img.byteLength, after: ktx2.byteLength });
93
+ texture.setImage(ktx2).setMimeType('image/ktx2');
94
+ }
95
+ return { encoder: 'basis-wasm', mode, encoded };
96
+ }
97
+ //# sourceMappingURL=ktx2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ktx2.js","sourceRoot":"","sources":["../../../src/character/stages/ktx2.ts"],"names":[],"mappings":";AAAA,oGAAoG;AACpG,gGAAgG;AAChG,mGAAmG;AACnG,oGAAoG;AACpG,uGAAuG;AACvG,mFAAmF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BnF,gCA8CC;AA1ED,2DAA8D;AAC9D,gCAAmC;AAoBnC;;;;;;GAMG;AACI,KAAK,UAAU,UAAU,CAAC,QAAkB,EAAE,IAA4C;IAC/F,MAAM,IAAI,GAAa,IAAI,EAAE,IAAI,IAAI,OAAO,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,6BAAgB,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAE7D,MAAM,EAAE,YAAY,EAAE,GAAG,CAAC,MAAM,IAAA,eAAS,EAAC,cAAc,CAAC,CAAsB,CAAC;IAChF,MAAM,KAAK,GAAG,CAAC,wDAAa,OAAO,GAAC,CAAC,CAAC,OAAO,CAAC;IAC9C,MAAM,YAAY,GAAG,KAAK,EAAE,GAAe,EAAyB,EAAE;QACpE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/G,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IAChF,CAAC,CAAC;IAEF,wFAAwF;IACxF,6FAA6F;IAC7F,MAAM,OAAO,GACX,IAAI,KAAK,OAAO;QACd,CAAC,CAAC;YACE,OAAO,EAAE,IAAI;YACb,oBAAoB,EAAE,IAAI,EAAE,OAAO,IAAI,CAAC;YACxC,oBAAoB,EAAE,IAAI;YAC1B,cAAc,EAAE,IAAI;YACpB,YAAY,EAAE,IAAI;YAClB,yBAAyB,EAAE,IAAI;YAC/B,UAAU,EAAE,IAAI;YAChB,YAAY;SACb;QACH,CAAC,CAAC;YACE,OAAO,EAAE,KAAK;YACd,YAAY,EAAE,IAAI,EAAE,OAAO,IAAI,GAAG;YAClC,gBAAgB,EAAE,CAAC;YACnB,cAAc,EAAE,IAAI;YACpB,YAAY,EAAE,IAAI;YAClB,yBAAyB,EAAE,IAAI;YAC/B,UAAU,EAAE,IAAI;YAChB,YAAY;SACb,CAAC;IAER,MAAM,OAAO,GAA0B,EAAE,CAAC;IAC1C,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC;QACxD,IAAI,OAAO,CAAC,WAAW,EAAE,KAAK,YAAY;YAAE,SAAS;QACrD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QAC/B,IAAI,GAAG,KAAK,IAAI;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;QACzG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAClD,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ export interface MergeLodsResult {
3
+ document: Document;
4
+ scenes: string[];
5
+ texturesBefore: number;
6
+ texturesAfter: number;
7
+ }
8
+ /**
9
+ * Merges per-LOD GLBs into one multi-scene document: scene i = LOD level i (named `lodN`, document
10
+ * order = level order), then dedup() collapses the byte-identical embedded images/materials the
11
+ * per-LOD optimize runs each carried. Three.js GLTFLoader exposes the levels as gltf.scenes[i] and
12
+ * its per-index caching shares one Texture/Material instance across levels — the runtime GPU dedupe
13
+ * falls out of the file format, no runtime code. (C2 materials backlog items 1+4.)
14
+ */
15
+ export declare function mergeLods(documents: Document[]): Promise<MergeLodsResult>;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ // PORTED from helix-web-engine-new/tools/character-pipeline — the source of truth for the character
3
+ // pipeline. SYNC OBLIGATION: fix bugs there first, then mirror the change here; do not diverge.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.mergeLods = mergeLods;
6
+ const core_1 = require("@gltf-transform/core");
7
+ const functions_1 = require("@gltf-transform/functions");
8
+ /**
9
+ * Merges per-LOD GLBs into one multi-scene document: scene i = LOD level i (named `lodN`, document
10
+ * order = level order), then dedup() collapses the byte-identical embedded images/materials the
11
+ * per-LOD optimize runs each carried. Three.js GLTFLoader exposes the levels as gltf.scenes[i] and
12
+ * its per-index caching shares one Texture/Material instance across levels — the runtime GPU dedupe
13
+ * falls out of the file format, no runtime code. (C2 materials backlog items 1+4.)
14
+ */
15
+ async function mergeLods(documents) {
16
+ if (documents.length < 2)
17
+ throw new Error('merge-lods: needs at least two LOD documents');
18
+ const [target, ...rest] = documents;
19
+ let texturesBefore = target.getRoot().listTextures().length;
20
+ for (const source of rest) {
21
+ texturesBefore += source.getRoot().listTextures().length;
22
+ (0, functions_1.mergeDocuments)(target, source);
23
+ }
24
+ const sceneList = target.getRoot().listScenes();
25
+ if (sceneList.length !== documents.length) {
26
+ throw new Error(`merge-lods: expected ${documents.length} scenes after merge, found ${sceneList.length} (multi-scene input?)`);
27
+ }
28
+ const scenes = sceneList.map((scene, i) => {
29
+ scene.setName(`lod${i + 1}`);
30
+ return scene.getName();
31
+ });
32
+ target.getRoot().setDefaultScene(sceneList[0]);
33
+ // dedup everything EXCEPT meshes: a bare dedup() also fuses byte-identical MESHES, silently
34
+ // collapsing same-density LOD levels (e.g. a seam-floored import whose low LODs land at the same
35
+ // tri count) into one shared mesh object. Identical ACCESSORS may still merge — that only shrinks
36
+ // the GLB, never the scene/mesh structure. keepSolidTextures stops a near-solid bake from being
37
+ // folded into a material factor (which would delete the texture).
38
+ // unpartition: merged docs carry one buffer per source; GLB output requires exactly one.
39
+ await target.transform((0, functions_1.dedup)({ propertyTypes: [core_1.PropertyType.ACCESSOR, core_1.PropertyType.TEXTURE, core_1.PropertyType.MATERIAL, core_1.PropertyType.SKIN] }), (0, functions_1.prune)({ keepSolidTextures: true }), (0, functions_1.unpartition)());
40
+ return { document: target, scenes, texturesAfter: target.getRoot().listTextures().length, texturesBefore };
41
+ }
42
+ //# sourceMappingURL=mergeLods.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeLods.js","sourceRoot":"","sources":["../../../src/character/stages/mergeLods.ts"],"names":[],"mappings":";AAAA,oGAAoG;AACpG,gGAAgG;;AAmBhG,8BA+BC;AAhDD,+CAA8D;AAC9D,yDAAsF;AAStF;;;;;;GAMG;AACI,KAAK,UAAU,SAAS,CAAC,SAAqB;IACnD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAC1F,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,SAAS,CAAC;IACpC,IAAI,cAAc,GAAG,MAAO,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC;IAC7D,KAAK,MAAM,MAAM,IAAI,IAAI,EAAE,CAAC;QAC1B,cAAc,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,CAAC;QACzD,IAAA,0BAAc,EAAC,MAAO,EAAE,MAAM,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,SAAS,GAAG,MAAO,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,CAAC;IACjD,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,wBAAwB,SAAS,CAAC,MAAM,8BAA8B,SAAS,CAAC,MAAM,uBAAuB,CAAC,CAAC;IACjI,CAAC;IACD,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACxC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC,OAAO,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;IACH,MAAO,CAAC,OAAO,EAAE,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAE,CAAC,CAAC;IAEjD,4FAA4F;IAC5F,iGAAiG;IACjG,kGAAkG;IAClG,gGAAgG;IAChG,kEAAkE;IAClE,yFAAyF;IACzF,MAAM,MAAO,CAAC,SAAS,CACrB,IAAA,iBAAK,EAAC,EAAE,aAAa,EAAE,CAAC,mBAAY,CAAC,QAAQ,EAAE,mBAAY,CAAC,OAAO,EAAE,mBAAY,CAAC,QAAQ,EAAE,mBAAY,CAAC,IAAI,CAAC,EAAE,CAAC,EACjH,IAAA,iBAAK,EAAC,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,EAClC,IAAA,uBAAW,GAAE,CACd,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,MAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAO,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC;AAC/G,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ export declare function countTriangles(document: Document): number;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ // PORTED from helix-web-engine-new/tools/character-pipeline — the source of truth for the character
3
+ // pipeline. SYNC OBLIGATION: fix bugs there first, then mirror the change here; do not diverge.
4
+ // Slim port: only countTriangles — the sole export the ported stages need (budgets/reports stay in the engine tool).
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.countTriangles = countTriangles;
7
+ function countTriangles(document) {
8
+ let tris = 0;
9
+ for (const mesh of document.getRoot().listMeshes()) {
10
+ for (const prim of mesh.listPrimitives()) {
11
+ const indices = prim.getIndices();
12
+ const vertexCount = indices !== null ? indices.getCount() : (prim.getAttribute('POSITION')?.getCount() ?? 0);
13
+ if (prim.getMode() === 4)
14
+ tris += Math.floor(vertexCount / 3);
15
+ }
16
+ }
17
+ return tris;
18
+ }
19
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/character/stages/report.ts"],"names":[],"mappings":";AAAA,oGAAoG;AACpG,gGAAgG;AAChG,qHAAqH;;AAIrH,wCAUC;AAVD,SAAgB,cAAc,CAAC,QAAkB;IAC/C,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC;QACnD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YACzC,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAClC,MAAM,WAAW,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC;YAC7G,IAAI,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC;gBAAE,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ export interface ResizeTexturesResult {
3
+ /** `name WxH -> WxH` per resized texture. */
4
+ resized: string[];
5
+ }
6
+ /**
7
+ * Downsizes every embedded texture whose longest edge exceeds maxSize (PNG re-encode via sharp).
8
+ * Covers textures that arrive embedded in the UE export (the baked eye materials) — the head/body
9
+ * bake goes through its own TGA-decode resize in the CLI before it ever enters the document.
10
+ */
11
+ export declare function resizeTextures(document: Document, maxSize: number): Promise<ResizeTexturesResult>;