@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,62 @@
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
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.resizeTextures = resizeTextures;
39
+ /**
40
+ * Downsizes every embedded texture whose longest edge exceeds maxSize (PNG re-encode via sharp).
41
+ * Covers textures that arrive embedded in the UE export (the baked eye materials) — the head/body
42
+ * bake goes through its own TGA-decode resize in the CLI before it ever enters the document.
43
+ */
44
+ async function resizeTextures(document, maxSize) {
45
+ const sharp = (await Promise.resolve().then(() => __importStar(require('sharp')))).default;
46
+ const resized = [];
47
+ for (const texture of document.getRoot().listTextures()) {
48
+ const image = texture.getImage();
49
+ if (image === null)
50
+ continue;
51
+ const meta = await sharp(image).metadata();
52
+ const width = meta.width ?? 0;
53
+ const height = meta.height ?? 0;
54
+ if (width <= 0 || height <= 0 || Math.max(width, height) <= maxSize)
55
+ continue;
56
+ const out = await sharp(image).resize(maxSize, maxSize, { fit: 'inside' }).png().toBuffer();
57
+ texture.setImage(new Uint8Array(out)).setMimeType('image/png');
58
+ resized.push(`${texture.getName()} ${width}x${height} -> <=${maxSize}`);
59
+ }
60
+ return { resized };
61
+ }
62
+ //# sourceMappingURL=resizeTextures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resizeTextures.js","sourceRoot":"","sources":["../../../src/character/stages/resizeTextures.ts"],"names":[],"mappings":";AAAA,oGAAoG;AACpG,gGAAgG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAchG,wCAeC;AApBD;;;;GAIG;AACI,KAAK,UAAU,cAAc,CAAC,QAAkB,EAAE,OAAe;IACtE,MAAM,KAAK,GAAG,CAAC,wDAAa,OAAO,GAAC,CAAC,CAAC,OAAO,CAAC;IAC9C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,OAAO,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC;QACxD,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QACjC,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QAChC,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,OAAO;YAAE,SAAS;QAC9E,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QAC5F,OAAO,CAAC,QAAQ,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,IAAI,KAAK,IAAI,MAAM,SAAS,OAAO,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,CAAC;AACrB,CAAC"}
@@ -0,0 +1,49 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ export interface BoneMap {
3
+ name: string;
4
+ version: string;
5
+ comment?: string;
6
+ /** source bone name -> helix-humanoid@1 bone name */
7
+ map: Record<string, string>;
8
+ /** source bones with no helix target, removed if they are childless leaves */
9
+ drop?: string[];
10
+ }
11
+ export interface RetargetResult {
12
+ /** source name -> helix name, for every joint actually renamed */
13
+ renamed: Record<string, string>;
14
+ /** source bones present in the rig but absent from the map (left untouched) */
15
+ unmapped: string[];
16
+ /** dropped leaf helper bones */
17
+ dropped: string[];
18
+ }
19
+ export interface MapCoverage {
20
+ /** number of skin joints found on the source rig (0 = not a skinned character at all) */
21
+ sourceJoints: number;
22
+ /** map keys present on the source rig */
23
+ matched: string[];
24
+ /** canonical (helix) bone names the matched sources cover */
25
+ coveredTargets: Set<string>;
26
+ /** source joints in neither map nor drop (kept as-is by retargetSkeleton; deformation unverified) */
27
+ extra: string[];
28
+ /** true when the rig uses raw Mixamo download naming ('mixamorig:' prefixes) — the bundled map expects bare names */
29
+ mixamoPrefixed: boolean;
30
+ }
31
+ /**
32
+ * Preflight for retarget/conform: how much of the source rig does a bone map actually cover?
33
+ * Coverage is judged in CANONICAL terms (which helix bones receive a source match), so callers can
34
+ * enforce the same requirements against any custom map, not just the bundled Meshy one.
35
+ */
36
+ export declare function checkMapCoverage(document: Document, boneMap: BoneMap): MapCoverage;
37
+ /**
38
+ * Renames a source biped rig's joints to `helix-humanoid@1` bone names by an explicit map.
39
+ *
40
+ * This is the NAME half of the retarget (architecture §6.2): glTF animation channels target nodes
41
+ * by INDEX, so a joint rename automatically re-homes every clip track and the skin's joint list —
42
+ * the mesh's inverse bind matrices are untouched, so the body renders identically, now driven by
43
+ * helix bone names. The REST-POSE correction half (aligning the source rest orientation to the
44
+ * MetaHuman rest so the platform's own clips look right) is a separate stage; this alone is enough
45
+ * to drive the rig with clips authored IN ITS OWN rest frame (its bundled walk).
46
+ *
47
+ * Drop-list leaves (Meshy's head_end/headfront helpers) are removed from the graph + skin + IBMs.
48
+ */
49
+ export declare function retargetSkeleton(document: Document, boneMap: BoneMap): RetargetResult;
@@ -0,0 +1,105 @@
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.checkMapCoverage = checkMapCoverage;
6
+ exports.retargetSkeleton = retargetSkeleton;
7
+ const core_1 = require("@gltf-transform/core");
8
+ function parentOf(node) {
9
+ for (const parent of node.listParents()) {
10
+ if (parent.propertyType === core_1.PropertyType.NODE)
11
+ return parent;
12
+ if (parent.propertyType === core_1.PropertyType.SCENE)
13
+ return parent;
14
+ }
15
+ return null;
16
+ }
17
+ /**
18
+ * Preflight for retarget/conform: how much of the source rig does a bone map actually cover?
19
+ * Coverage is judged in CANONICAL terms (which helix bones receive a source match), so callers can
20
+ * enforce the same requirements against any custom map, not just the bundled Meshy one.
21
+ */
22
+ function checkMapCoverage(document, boneMap) {
23
+ const joints = new Set();
24
+ for (const skin of document.getRoot().listSkins())
25
+ for (const j of skin.listJoints())
26
+ joints.add(j.getName());
27
+ const drop = new Set(boneMap.drop ?? []);
28
+ const matched = Object.keys(boneMap.map).filter((k) => joints.has(k));
29
+ return {
30
+ sourceJoints: joints.size,
31
+ matched,
32
+ coveredTargets: new Set(matched.map((k) => boneMap.map[k])),
33
+ extra: [...joints].filter((n) => !(n in boneMap.map) && !drop.has(n)),
34
+ mixamoPrefixed: [...joints].some((n) => n.startsWith('mixamorig')),
35
+ };
36
+ }
37
+ /**
38
+ * Renames a source biped rig's joints to `helix-humanoid@1` bone names by an explicit map.
39
+ *
40
+ * This is the NAME half of the retarget (architecture §6.2): glTF animation channels target nodes
41
+ * by INDEX, so a joint rename automatically re-homes every clip track and the skin's joint list —
42
+ * the mesh's inverse bind matrices are untouched, so the body renders identically, now driven by
43
+ * helix bone names. The REST-POSE correction half (aligning the source rest orientation to the
44
+ * MetaHuman rest so the platform's own clips look right) is a separate stage; this alone is enough
45
+ * to drive the rig with clips authored IN ITS OWN rest frame (its bundled walk).
46
+ *
47
+ * Drop-list leaves (Meshy's head_end/headfront helpers) are removed from the graph + skin + IBMs.
48
+ */
49
+ function retargetSkeleton(document, boneMap) {
50
+ const root = document.getRoot();
51
+ const map = boneMap.map;
52
+ const dropSet = new Set(boneMap.drop ?? []);
53
+ const renamed = {};
54
+ const unmapped = [];
55
+ const dropped = [];
56
+ // Collect joint nodes from every skin (a source name may appear once; rename is idempotent per node).
57
+ const jointNodes = new Set();
58
+ for (const skin of root.listSkins())
59
+ for (const j of skin.listJoints())
60
+ jointNodes.add(j);
61
+ // 1. Drop childless leaf helpers first (so they never enter the rename/IBM bookkeeping).
62
+ for (const skin of root.listSkins()) {
63
+ const joints = skin.listJoints();
64
+ const dropIdx = joints
65
+ .map((j, i) => ({ j, i }))
66
+ .filter(({ j }) => dropSet.has(j.getName()) && j.listChildren().length === 0);
67
+ if (dropIdx.length === 0)
68
+ continue;
69
+ const oldIbm = skin.getInverseBindMatrices();
70
+ const keep = joints.filter((j) => !(dropSet.has(j.getName()) && j.listChildren().length === 0));
71
+ if (oldIbm !== null) {
72
+ const oldData = oldIbm.getArray();
73
+ const newData = new Float32Array(keep.length * 16);
74
+ keep.forEach((j, newIndex) => {
75
+ const oldIndex = joints.indexOf(j);
76
+ newData.set(oldData.subarray(oldIndex * 16, oldIndex * 16 + 16), newIndex * 16);
77
+ });
78
+ oldIbm.setArray(newData);
79
+ }
80
+ for (const { j } of dropIdx) {
81
+ skin.removeJoint(j);
82
+ if (!dropped.includes(j.getName()))
83
+ dropped.push(j.getName());
84
+ jointNodes.delete(j);
85
+ const parent = parentOf(j);
86
+ if (parent !== null)
87
+ for (const child of [...j.listChildren()])
88
+ parent.addChild(child);
89
+ j.dispose();
90
+ }
91
+ }
92
+ // 2. Rename mapped joints. Channels target nodes by index → clip tracks follow the rename for free.
93
+ for (const node of jointNodes) {
94
+ const src = node.getName();
95
+ const dst = map[src];
96
+ if (dst === undefined) {
97
+ unmapped.push(src);
98
+ continue;
99
+ }
100
+ node.setName(dst);
101
+ renamed[src] = dst;
102
+ }
103
+ return { renamed, unmapped, dropped };
104
+ }
105
+ //# sourceMappingURL=retarget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retarget.js","sourceRoot":"","sources":["../../../src/character/stages/retarget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ import type { BoneMap } from './retarget';
3
+ import type { CanonicalSkeleton } from './conform';
4
+ export interface RetargetClipResult {
5
+ document: Document;
6
+ meta: {
7
+ name: string;
8
+ duration: number;
9
+ loop: boolean;
10
+ strideSpeed: null;
11
+ additive: false;
12
+ };
13
+ frames: number;
14
+ /** helix bones that received a retargeted rotation track */
15
+ animatedBones: string[];
16
+ }
17
+ /**
18
+ * Retargets a source animation CLIP onto the canonical `helix-humanoid@1` skeleton via world-space
19
+ * motion transfer (the architecture §6.2 / three-vrm approach): each mapped bone's WORLD-space rotation
20
+ * delta from the SOURCE rest is re-applied to the TARGET rest, then converted back to the target's local
21
+ * frame. Because the motion is transferred as a delta-from-rest in world space, the source↔target
22
+ * bone-axis convention cancels — the same reason the mesh embed is convention-proof. Root (pelvis)
23
+ * translation is retargeted as an in-place bob/sway scaled to the target's hip height. Unmapped target
24
+ * bones (spine_02/04, twists, fingers) stay at rest. Output is a clip-only GLB (canonical skeleton
25
+ * nodes + one animation, no mesh/skin) — the platform clip format.
26
+ */
27
+ export declare function retargetClip(source: Document, canon: CanonicalSkeleton, boneMap: BoneMap, clipName: string): RetargetClipResult;
@@ -0,0 +1,237 @@
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
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.retargetClip = retargetClip;
39
+ const core_1 = require("@gltf-transform/core");
40
+ const mat4_1 = require("../mat4");
41
+ const q = __importStar(require("../quat"));
42
+ function jointParent(node, jointSet) {
43
+ for (const p of node.listParents())
44
+ if (p.propertyType === core_1.PropertyType.NODE && jointSet.has(p))
45
+ return p;
46
+ return null;
47
+ }
48
+ /**
49
+ * Retargets a source animation CLIP onto the canonical `helix-humanoid@1` skeleton via world-space
50
+ * motion transfer (the architecture §6.2 / three-vrm approach): each mapped bone's WORLD-space rotation
51
+ * delta from the SOURCE rest is re-applied to the TARGET rest, then converted back to the target's local
52
+ * frame. Because the motion is transferred as a delta-from-rest in world space, the source↔target
53
+ * bone-axis convention cancels — the same reason the mesh embed is convention-proof. Root (pelvis)
54
+ * translation is retargeted as an in-place bob/sway scaled to the target's hip height. Unmapped target
55
+ * bones (spine_02/04, twists, fingers) stay at rest. Output is a clip-only GLB (canonical skeleton
56
+ * nodes + one animation, no mesh/skin) — the platform clip format.
57
+ */
58
+ function retargetClip(source, canon, boneMap, clipName) {
59
+ // ---- source rig: hierarchy (DFS parent-first), rest local/world rotations, and clip tracks --------
60
+ const srcSkin = source.getRoot().listSkins()[0];
61
+ if (srcSkin === undefined)
62
+ throw new Error('retargetClip: source has no skin');
63
+ const srcJoints = srcSkin.listJoints();
64
+ const jointSet = new Set(srcJoints);
65
+ const srcRoot = srcSkin.getSkeleton() ?? srcJoints.find((j) => jointParent(j, jointSet) === null) ?? srcJoints[0];
66
+ const srcOrder = [];
67
+ (function dfs(n) { srcOrder.push(n); for (const c of n.listChildren())
68
+ if (jointSet.has(c))
69
+ dfs(c); })(srcRoot);
70
+ const srcParentName = new Map();
71
+ for (const j of srcOrder)
72
+ srcParentName.set(j.getName(), jointParent(j, jointSet)?.getName() ?? null);
73
+ const srcRestLocalQuat = new Map(srcOrder.map((j) => [j.getName(), j.getRotation()]));
74
+ const srcRestLocalTrans = new Map(srcOrder.map((j) => [j.getName(), [...j.getTranslation()]]));
75
+ const srcRestWorldQuat = new Map();
76
+ for (const j of srcOrder) {
77
+ const p = srcParentName.get(j.getName());
78
+ srcRestWorldQuat.set(j.getName(), q.normalize(p === null ? srcRestLocalQuat.get(j.getName()) : q.mul(srcRestWorldQuat.get(p), srcRestLocalQuat.get(j.getName()))));
79
+ }
80
+ const anim = source.getRoot().listAnimations()[0];
81
+ if (anim === undefined)
82
+ throw new Error('retargetClip: source has no animation');
83
+ const rotTrack = new Map();
84
+ const transTrack = new Map();
85
+ const allTimes = new Set();
86
+ let hasRot = false;
87
+ for (const ch of anim.listChannels()) {
88
+ const node = ch.getTargetNode();
89
+ const s = ch.getSampler();
90
+ if (node === null || s === null)
91
+ continue;
92
+ const times = s.getInput().getArray();
93
+ const out = s.getOutput().getArray();
94
+ // Master timeline = union of rotation ∪ translation input times, so a bob key at a different density
95
+ // than the rotation keys isn't aliased away (scale/STEP tracks are dropped and don't contribute).
96
+ if (ch.getTargetPath() === 'rotation') {
97
+ rotTrack.set(node.getName(), { times, quats: out });
98
+ hasRot = true;
99
+ for (const t of times)
100
+ allTimes.add(t);
101
+ }
102
+ else if (ch.getTargetPath() === 'translation') {
103
+ transTrack.set(node.getName(), { times, vals: out });
104
+ for (const t of times)
105
+ allTimes.add(t);
106
+ }
107
+ }
108
+ if (!hasRot)
109
+ throw new Error('retargetClip: source animation has no rotation channels');
110
+ const srcTimes = [...allTimes].sort((a, b) => a - b);
111
+ const t0 = srcTimes[0];
112
+ const outTimes = srcTimes.map((t) => t - t0);
113
+ const frames = srcTimes.length;
114
+ // ---- target rig: canonical rest local/world rotations + pelvis rest ------------------------------
115
+ const canonParent = new Map(canon.nodes.map((n) => [n.name, n.parent]));
116
+ const canonLocalMat = new Map(canon.nodes.map((n) => [n.name, n.local]));
117
+ const canonRestLocalQuat = new Map(canon.nodes.map((n) => [n.name, q.fromMat((0, mat4_1.rigidize)(n.local))]));
118
+ const canonRestWorldQuat = new Map();
119
+ for (const n of canon.nodes) {
120
+ const p = n.parent;
121
+ canonRestWorldQuat.set(n.name, q.normalize(p === null ? canonRestLocalQuat.get(n.name) : q.mul(canonRestWorldQuat.get(p), canonRestLocalQuat.get(n.name))));
122
+ }
123
+ const pelvisLocal = canonLocalMat.get('pelvis');
124
+ const canonPelvisRestLocalTrans = [pelvisLocal[12], pelvisLocal[13], pelvisLocal[14]];
125
+ const canonPelvisRestWorldY = canon.worldByName.get('pelvis')[13];
126
+ // invert the bone map (helix -> source), direct entries only
127
+ const invMap = new Map();
128
+ for (const [src, helix] of Object.entries(boneMap.map))
129
+ invMap.set(helix, src);
130
+ // pelvis bob scale: source hips local translation (armature-scaled, ~cm) -> canonical-meter bob.
131
+ const hipsSrcName = invMap.get('pelvis');
132
+ const hipsNode = srcJoints.find((j) => j.getName() === hipsSrcName);
133
+ const hipsWorldRestY = hipsNode.getWorldMatrix()[13];
134
+ const hipsLocalRest = srcRestLocalTrans.get(hipsSrcName);
135
+ const bobScale = Math.abs(hipsLocalRest[1]) > 1e-6 ? canonPelvisRestWorldY / hipsLocalRest[1] : 1;
136
+ // Rotation that carries a vector from the source pelvis-parent local frame into the target pelvis-parent
137
+ // local frame (via world): conj(dstParentWorld)·srcParentWorld. Without it a vertical bob in the source
138
+ // frame lands on the wrong target axis (the two rigs' conventions differ) → a sideways shove.
139
+ const srcHipsParentName = srcParentName.get(hipsSrcName) ?? null;
140
+ const srcHipsParentWorldRot = srcHipsParentName !== null ? srcRestWorldQuat.get(srcHipsParentName) : [0, 0, 0, 1];
141
+ const canonPelvisParentName = canonParent.get('pelvis') ?? null;
142
+ const canonPelvisParentWorldRot = canonPelvisParentName !== null ? canonRestWorldQuat.get(canonPelvisParentName) : [0, 0, 0, 1];
143
+ const bobRot = q.mul(q.conj(canonPelvisParentWorldRot), srcHipsParentWorldRot);
144
+ // Clavicle rest-correction (mirror of the embed lane). The rigs' clavicle RESTS differ ~9° (Meshy
145
+ // shoulder ~horizontal, MetaHuman droops). The transfer maps source-rest → canonical-rest, so a Meshy
146
+ // shoulder held horizontal lands ~9° too low (dropped shoulders). For the two clavicles, use a rest
147
+ // REFERENCE aligned to the SOURCE clavicle direction, so the imported animation preserves the source's
148
+ // shoulder carriage. Only the clavicle bone shifts — the child upperarm's local compensates (its world
149
+ // orientation is unchanged), so the arm just rides the lifted shoulder instead of tilting.
150
+ const ORIGIN = [0, 0, 0];
151
+ const posOf = (m) => [m[12], m[13], m[14]];
152
+ const restRef = new Map(canon.nodes.map((n) => [n.name, canonRestWorldQuat.get(n.name)]));
153
+ for (const [clav, upper] of [['clavicle_l', 'upperarm_l'], ['clavicle_r', 'upperarm_r']]) {
154
+ const srcClav = invMap.get(clav), srcUpper = invMap.get(upper);
155
+ const scn = srcClav !== undefined ? srcJoints.find((j) => j.getName() === srcClav) : undefined;
156
+ const sun = srcUpper !== undefined ? srcJoints.find((j) => j.getName() === srcUpper) : undefined;
157
+ if (scn === undefined || sun === undefined)
158
+ continue;
159
+ const srcDir = (0, mat4_1.normalize3)((0, mat4_1.sub3)(posOf(sun.getWorldMatrix()), posOf(scn.getWorldMatrix())));
160
+ const canonDir = (0, mat4_1.normalize3)((0, mat4_1.sub3)(posOf(canon.worldByName.get(upper)), posOf(canon.worldByName.get(clav))));
161
+ const O = q.fromMat((0, mat4_1.mul4)((0, mat4_1.frameFromAxis)(canonDir, ORIGIN), (0, mat4_1.invert4)((0, mat4_1.frameFromAxis)(srcDir, ORIGIN)))); // src->canon world rot
162
+ restRef.set(clav, q.normalize(q.mul(q.conj(O), canonRestWorldQuat.get(clav)))); // canon rest, re-aimed at source dir
163
+ }
164
+ // ---- per-frame retarget --------------------------------------------------------------------------
165
+ const animatedBones = [...invMap.keys()].filter((c) => canonParent.has(c));
166
+ const outRot = new Map(animatedBones.map((c) => [c, new Float32Array(frames * 4)]));
167
+ const outPelvis = new Float32Array(frames * 3);
168
+ for (let f = 0; f < frames; f++) {
169
+ const tOrig = srcTimes[f];
170
+ // 1. source FK pose
171
+ const srcWorld = new Map();
172
+ for (const j of srcOrder) {
173
+ const name = j.getName();
174
+ const track = rotTrack.get(name);
175
+ const local = track ? q.sampleQuat(track.times, track.quats, tOrig) : srcRestLocalQuat.get(name);
176
+ const p = srcParentName.get(name);
177
+ srcWorld.set(name, q.normalize(p === null ? local : q.mul(srcWorld.get(p), local)));
178
+ }
179
+ // 2+3. target world rotations. Mapped bones follow the source's world delta-from-rest. UNMAPPED
180
+ // bones PROPAGATE their (already-retargeted) parent's motion while keeping their canonical rest
181
+ // LOCAL — matching how they behave at playback (no track ⇒ rest-local under a moving parent). Freezing
182
+ // them at rest WORLD instead would make a mapped child counter-rotate and shear the spine.
183
+ const dstWorld = new Map();
184
+ for (const n of canon.nodes) {
185
+ const s = invMap.get(n.name);
186
+ if (s !== undefined && srcWorld.has(s)) {
187
+ const delta = q.mul(srcWorld.get(s), q.conj(srcRestWorldQuat.get(s)));
188
+ dstWorld.set(n.name, q.normalize(q.mul(delta, restRef.get(n.name)))); // restRef = canon rest, clavicle re-aimed at source
189
+ }
190
+ else if (n.parent === null) {
191
+ dstWorld.set(n.name, canonRestWorldQuat.get(n.name));
192
+ }
193
+ else {
194
+ dstWorld.set(n.name, q.normalize(q.mul(dstWorld.get(n.parent), canonRestLocalQuat.get(n.name))));
195
+ }
196
+ }
197
+ // 4. mapped bones -> local rotation track
198
+ for (const c of animatedBones) {
199
+ const p = canonParent.get(c);
200
+ const local = p === null ? dstWorld.get(c) : q.mul(q.conj(dstWorld.get(p)), dstWorld.get(c));
201
+ outRot.get(c).set(local, f * 4);
202
+ }
203
+ // 5. pelvis in-place bob — route the source-local delta through world into the target-local frame.
204
+ const hipsTrack = transTrack.get(hipsSrcName);
205
+ const hips = hipsTrack ? q.sampleVec3(hipsTrack.times, hipsTrack.vals, tOrig) : hipsLocalRest;
206
+ const bob = q.rotateVec(bobRot, [bobScale * (hips[0] - hipsLocalRest[0]), bobScale * (hips[1] - hipsLocalRest[1]), bobScale * (hips[2] - hipsLocalRest[2])]);
207
+ outPelvis[f * 3] = canonPelvisRestLocalTrans[0] + bob[0];
208
+ outPelvis[f * 3 + 1] = canonPelvisRestLocalTrans[1] + bob[1];
209
+ outPelvis[f * 3 + 2] = canonPelvisRestLocalTrans[2] + bob[2];
210
+ }
211
+ // ---- assemble the clip-only GLB: canonical skeleton nodes + one animation ------------------------
212
+ const doc = new core_1.Document();
213
+ const buffer = doc.createBuffer();
214
+ const scene = doc.createScene('clip');
215
+ const created = new Map();
216
+ for (const def of canon.nodes)
217
+ created.set(def.name, doc.createNode(def.name).setMatrix(def.local));
218
+ for (const def of canon.nodes)
219
+ if (def.parent !== null)
220
+ created.get(def.parent).addChild(created.get(def.name));
221
+ scene.addChild(created.get(canon.skeletonRootName));
222
+ const clip = doc.createAnimation(clipName);
223
+ const input = doc.createAccessor().setType('SCALAR').setArray(new Float32Array(outTimes)).setBuffer(buffer);
224
+ for (const c of animatedBones) {
225
+ const output = doc.createAccessor().setType('VEC4').setArray(outRot.get(c)).setBuffer(buffer);
226
+ const sampler = doc.createAnimationSampler().setInput(input).setOutput(output).setInterpolation('LINEAR');
227
+ clip.addSampler(sampler);
228
+ clip.addChannel(doc.createAnimationChannel().setTargetNode(created.get(c)).setTargetPath('rotation').setSampler(sampler));
229
+ }
230
+ const pelvisOut = doc.createAccessor().setType('VEC3').setArray(outPelvis).setBuffer(buffer);
231
+ const pelvisSampler = doc.createAnimationSampler().setInput(input).setOutput(pelvisOut).setInterpolation('LINEAR');
232
+ clip.addSampler(pelvisSampler);
233
+ clip.addChannel(doc.createAnimationChannel().setTargetNode(created.get('pelvis')).setTargetPath('translation').setSampler(pelvisSampler));
234
+ const duration = outTimes[frames - 1] - outTimes[0];
235
+ return { document: doc, meta: { name: clipName, duration: Math.round(duration * 1000) / 1000, loop: true, strideSpeed: null, additive: false }, frames, animatedBones };
236
+ }
237
+ //# sourceMappingURL=retargetClip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retargetClip.js","sourceRoot":"","sources":["../../../src/character/stages/retargetClip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ export interface SimplifyResult {
3
+ before: number;
4
+ after: number;
5
+ }
6
+ /**
7
+ * Attribute-preserving simplification to a triangle target via meshopt. `lockBorder` additionally
8
+ * locks open-border vertices (architecture §6: never re-UV — the platform's identity-as-textures
9
+ * depends on the original layout), so it stays TRUE for first-party bodies; importers with real open
10
+ * borders (hair cards, garments) may pass false. Note meshopt ALWAYS preserves attribute-seam
11
+ * vertices regardless of these knobs — a micro-chart baked atlas (Meshy) therefore floors at its
12
+ * chart-border ring (~34% on the reference warrior) whatever the error budget; that case needs
13
+ * weldedSimplify, not bigger `errorCap` (0.001 first-party; ~0.02 for imports).
14
+ */
15
+ export declare function simplifyToTarget(document: Document, targetTris: number, errorCap?: number, lockBorder?: boolean): Promise<SimplifyResult>;
@@ -0,0 +1,37 @@
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.simplifyToTarget = simplifyToTarget;
6
+ const functions_1 = require("@gltf-transform/functions");
7
+ const meshoptimizer_1 = require("meshoptimizer");
8
+ const report_1 = require("./report");
9
+ /**
10
+ * Attribute-preserving simplification to a triangle target via meshopt. `lockBorder` additionally
11
+ * locks open-border vertices (architecture §6: never re-UV — the platform's identity-as-textures
12
+ * depends on the original layout), so it stays TRUE for first-party bodies; importers with real open
13
+ * borders (hair cards, garments) may pass false. Note meshopt ALWAYS preserves attribute-seam
14
+ * vertices regardless of these knobs — a micro-chart baked atlas (Meshy) therefore floors at its
15
+ * chart-border ring (~34% on the reference warrior) whatever the error budget; that case needs
16
+ * weldedSimplify, not bigger `errorCap` (0.001 first-party; ~0.02 for imports).
17
+ */
18
+ async function simplifyToTarget(document, targetTris, errorCap = 0.001, lockBorder = true) {
19
+ const before = (0, report_1.countTriangles)(document);
20
+ if (before <= targetTris)
21
+ return { before, after: before };
22
+ await meshoptimizer_1.MeshoptSimplifier.ready;
23
+ await document.transform((0, functions_1.weld)());
24
+ // meshopt treats ratio as a hint (lockBorder / the error budget raise the floor), so iterate until
25
+ // at/under target or the count stops moving — the floor is then the honest result. Seam-locked
26
+ // imports (micro-chart atlases) floor by attempt 2 no matter what; weldedSimplify is the tool there.
27
+ let current = before;
28
+ for (let attempt = 0; attempt < 4 && current > targetTris; attempt++) {
29
+ await document.transform((0, functions_1.simplify)({ simplifier: meshoptimizer_1.MeshoptSimplifier, ratio: targetTris / current, error: errorCap, lockBorder }));
30
+ const after = (0, report_1.countTriangles)(document);
31
+ if (after >= current)
32
+ break;
33
+ current = after;
34
+ }
35
+ return { before, after: current };
36
+ }
37
+ //# sourceMappingURL=simplifyMesh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"simplifyMesh.js","sourceRoot":"","sources":["../../../src/character/stages/simplifyMesh.ts"],"names":[],"mappings":";AAAA,oGAAoG;AACpG,gGAAgG;;AAqBhG,4CAiBC;AAnCD,yDAA2D;AAC3D,iDAAkD;AAClD,qCAA0C;AAO1C;;;;;;;;GAQG;AACI,KAAK,UAAU,gBAAgB,CAAC,QAAkB,EAAE,UAAkB,EAAE,QAAQ,GAAG,KAAK,EAAE,UAAU,GAAG,IAAI;IAChH,MAAM,MAAM,GAAG,IAAA,uBAAc,EAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,MAAM,IAAI,UAAU;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAE3D,MAAM,iCAAiB,CAAC,KAAK,CAAC;IAC9B,MAAM,QAAQ,CAAC,SAAS,CAAC,IAAA,gBAAI,GAAE,CAAC,CAAC;IACjC,mGAAmG;IACnG,+FAA+F;IAC/F,qGAAqG;IACrG,IAAI,OAAO,GAAG,MAAM,CAAC;IACrB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;QACrE,MAAM,QAAQ,CAAC,SAAS,CAAC,IAAA,oBAAQ,EAAC,EAAE,UAAU,EAAE,iCAAiB,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;QAChI,MAAM,KAAK,GAAG,IAAA,uBAAc,EAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,KAAK,IAAI,OAAO;YAAE,MAAM;QAC5B,OAAO,GAAG,KAAK,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { Document } from '@gltf-transform/core';
2
+ export interface SplitFaceResult {
3
+ split: boolean;
4
+ faceTris: number;
5
+ bodyTris: number;
6
+ /** joints in the head subtree that drove the classification */
7
+ headJoints: number;
8
+ }
9
+ /**
10
+ * Slices the head geometry out of a single-mesh character into its own 'FaceMesh' node, so the
11
+ * runtime's first-person mode can hide it (CameraRig `fpHideMeshes` matches mesh names containing
12
+ * 'FaceMesh'; the stock character ships its face as a separate part — imports are one welded mesh).
13
+ *
14
+ * The split is WEIGHT-driven and therefore rig-agnostic: after conform the skeleton is canonical,
15
+ * so a triangle belongs to the face part when its mean skin weight into the NECK-AND-UP subtree
16
+ * (neck_01 -> neck_02 -> head -> facial root; falls back to 'head' when no neck joint exists)
17
+ * exceeds 0.5. Rooting at the neck matters on auto-rigged imports: their face skin blends head WITH
18
+ * neck (head alone rarely crosses 0.5 outside the skull), and the stock face part includes a neck
19
+ * skirt too (see CameraRig's skull-measure). Scalp-anchored hair/hats ride along; LONG draped hair
20
+ * that auto-rigs weight to the clavicles stays on the body — in first person it behaves like
21
+ * shoulder-wear, swaying at the screen edges the way the visible shoulders do. Only the index
22
+ * buffer splits — the face primitive SHARES the body's attribute accessors, so the file grows by
23
+ * one index accessor and one node per scene. The MATERIAL however must be a distinct instance
24
+ * (textures still shared): the runtime hides the face by mutating material.colorWrite, and
25
+ * GLTFLoader gives prims that reference one glTF material the same THREE.Material — a shared
26
+ * material would hide the body. For that same reason this stage MUST run AFTER merge-lods: its
27
+ * dedup compares materials by value (names ignored) and would fold the face clone back into the
28
+ * body material. Every scene of the merged document is split (scene i = LOD level i).
29
+ */
30
+ export declare function splitFacePrimitive(document: Document): SplitFaceResult;