@lovelace_lol/embody 0.0.3 → 0.0.5

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.
@@ -1,17 +1,14 @@
1
1
  import type { BoneFrameDelta, FrameDelta, ModelDescriptor, MorphTargetFrameDelta } from './contracts';
2
2
  import type { Profile } from '../mappings/types';
3
3
  import type { EmbodyCoreWasmModule } from '../wasmTypes';
4
- export declare const AU_MORPH_BINDING_STRIDE = 5;
5
- export declare const VISEME_MORPH_BINDING_STRIDE = 4;
6
- export type MorphBindingSide = 0 | 1 | 2;
7
4
  export interface WasmRuntimeCoreOptions {
8
5
  readonly profile: Profile;
9
6
  readonly model: ModelDescriptor;
10
7
  readonly wasm: EmbodyCoreWasmModule;
11
8
  }
12
9
  /**
13
- * TypeScript facade over the Rust Wasm RuntimeCore for live morph FrameDelta
14
- * evaluation. Bones/composites remain on TsRuntimeCore until a later slice.
10
+ * TypeScript facade over the host-neutral Rust Wasm RuntimeCore.
11
+ * JavaScript only owns JSON handoff and packed FrameDelta unpacking here.
15
12
  */
16
13
  export declare class WasmRuntimeCore {
17
14
  private readonly wasm;
@@ -32,24 +29,5 @@ export declare class WasmRuntimeCore {
32
29
  evaluateFrameDelta(deltaSeconds?: number): FrameDelta;
33
30
  private reloadBindings;
34
31
  }
35
- export declare function compileMorphBindings(profile: Profile, model: ModelDescriptor): {
36
- auBindings: Float32Array;
37
- visemeBindings: Float32Array;
38
- mixedAus: Uint32Array;
39
- };
40
- export interface CompiledBoneBindings {
41
- restTransforms: Float32Array;
42
- compositeAxes: Float32Array;
43
- translations: Float32Array;
44
- jawBinding: Float32Array;
45
- visemeJawAmounts: Float32Array;
46
- }
47
- /**
48
- * Compile profile bone mappings into the packed tables the Rust RuntimeCore
49
- * consumes: rest transforms, composite rotation axes (in yaw/pitch/roll
50
- * application order), AU translations, and the auto viseme jaw binding.
51
- * Mirrors the mapping resolution in TsRuntimeCore.collectBoneWrites.
52
- */
53
- export declare function compileBoneBindings(profile: Profile, model: ModelDescriptor): CompiledBoneBindings;
54
32
  export declare function unpackBoneFrameDelta(values: ArrayLike<number>): BoneFrameDelta[];
55
33
  export declare function unpackMorphFrameDelta(values: ArrayLike<number>): MorphTargetFrameDelta[];
@@ -2,7 +2,7 @@ export type { BoneDescriptor, BoneFrameDelta, BoneId, BoneTransformTrackTarget,
2
2
  export { TEMPLATE_SKELETON_FIT_METADATA_KIND, TEMPLATE_SKELETON_FIT_METADATA_VERSION, MESH_PROPORTIONS_FIELDS, MESH_PROPORTIONS_STRIDE, TEMPLATE_SKELETON_FIT_STATUSES, TEMPLATE_SKELETON_FIT_SOLUTION_FIELDS, TEMPLATE_SKELETON_FIT_SOLUTION_STRIDE, TEMPLATE_SKELETON_FIT_TRANSFORM_FIELDS, TEMPLATE_SKELETON_FIT_TRANSFORM_STRIDE, TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS, TEMPLATE_SKELETON_FIT_VERTICAL_AXES, composeTemplateSkeletonFitTransform, isTemplateSkeletonFitStatus, validateTemplateSkeletonFitMetadata, } from './contracts';
3
3
  export { TsClipCompiler, numericArrayToNumbers, } from './TsClipCompiler';
4
4
  export { TsRuntimeCore } from './TsRuntimeCore';
5
- export { AU_MORPH_BINDING_STRIDE, VISEME_MORPH_BINDING_STRIDE, WasmRuntimeCore, compileMorphBindings, compileBoneBindings, unpackMorphFrameDelta, unpackBoneFrameDelta, } from './WasmRuntimeCore';
6
- export type { CompiledBoneBindings, MorphBindingSide, WasmRuntimeCoreOptions, } from './WasmRuntimeCore';
5
+ export { WasmRuntimeCore, unpackMorphFrameDelta, unpackBoneFrameDelta, } from './WasmRuntimeCore';
6
+ export type { WasmRuntimeCoreOptions, } from './WasmRuntimeCore';
7
7
  export type { TsClipCompilerInput, TsClipCompilerKeyframe, TsClipCompilerTrackInput, TsClipCurveTarget, TsClipCurvesInput, } from './TsClipCompiler';
8
8
  export type { TsRuntimeCoreOptions } from './TsRuntimeCore';
package/dist/core.cjs CHANGED
@@ -698,16 +698,6 @@ function morphWriteKey(meshId, morphTargetId) {
698
698
  }
699
699
 
700
700
  // src/core/WasmRuntimeCore.ts
701
- var AU_MORPH_BINDING_STRIDE = 5;
702
- var VISEME_MORPH_BINDING_STRIDE = 4;
703
- var AXIS_GROUP_NEGATIVE = 0;
704
- var AXIS_GROUP_POSITIVE = 1;
705
- var AXIS_GROUP_PLAIN = 2;
706
- var BONE_SIDE_NONE = 0;
707
- var BONE_SIDE_LEFT = 1;
708
- var BONE_SIDE_RIGHT = 2;
709
- var ROTATION_CHANNELS = { rx: 0, ry: 1, rz: 2 };
710
- var TRANSLATION_CHANNELS = { tx: 0, ty: 1, tz: 2 };
711
701
  var WasmRuntimeCore = class {
712
702
  constructor(options) {
713
703
  __publicField(this, "wasm");
@@ -721,12 +711,11 @@ var WasmRuntimeCore = class {
721
711
  if (!RuntimeCtor) {
722
712
  throw new Error("Embody Wasm module does not export RuntimeCore");
723
713
  }
724
- this.core = new RuntimeCtor(getProfileVisemeSlots(options.profile).length);
714
+ this.core = new RuntimeCtor(0);
725
715
  this.reloadBindings();
726
716
  }
727
717
  setProfile(profile) {
728
718
  this.profile = profile;
729
- this.core.set_viseme_slot_count(getProfileVisemeSlots(profile).length);
730
719
  this.reloadBindings();
731
720
  }
732
721
  setModelDescriptor(model) {
@@ -771,191 +760,9 @@ var WasmRuntimeCore = class {
771
760
  };
772
761
  }
773
762
  reloadBindings() {
774
- const { auBindings, mixedAus, visemeBindings } = compileMorphBindings(this.profile, this.model);
775
- this.core.load_au_morph_bindings(auBindings);
776
- this.core.load_viseme_morph_bindings(visemeBindings);
777
- this.core.set_mixed_aus(mixedAus);
778
- const boneBindings = compileBoneBindings(this.profile, this.model);
779
- this.core.load_bone_rest_transforms(boneBindings.restTransforms);
780
- this.core.load_composite_axes(boneBindings.compositeAxes);
781
- this.core.load_bone_translations(boneBindings.translations);
782
- this.core.load_jaw_binding(boneBindings.jawBinding);
783
- this.core.load_viseme_jaw_amounts(boneBindings.visemeJawAmounts);
763
+ this.core.configure_with_profile(JSON.stringify(this.profile), JSON.stringify(this.model));
784
764
  }
785
765
  };
786
- function compileMorphBindings(profile, model) {
787
- const auRows = [];
788
- const mixed = [];
789
- for (const [auIdText, entry] of Object.entries(profile.auToMorphs || {})) {
790
- const auId = Number(auIdText);
791
- if (Number.isNaN(auId) || !entry) continue;
792
- const meshNames = getMeshNamesForAUProfile(profile, auId);
793
- const hasMorphs = !!(entry.left?.length || entry.right?.length || entry.center?.length);
794
- if (hasMorphs && profile.auToBones?.[auId]?.length) {
795
- mixed.push(auId);
796
- }
797
- pushAuSide(auRows, auId, 0, entry.left || [], meshNames, model, profile);
798
- pushAuSide(auRows, auId, 1, entry.right || [], meshNames, model, profile);
799
- pushAuSide(auRows, auId, 2, entry.center || [], meshNames, model, profile);
800
- }
801
- const visemeRows = [];
802
- const visemeMeshNames = getMeshNamesForVisemeProfile(profile);
803
- const slotCount = getProfileVisemeSlots(profile).length;
804
- for (let index = 0; index < slotCount; index += 1) {
805
- for (const bindingTarget of getVisemeBindingTargets(profile, index)) {
806
- for (const resolved of resolveMorphTargets(model, profile, bindingTarget.morph, visemeMeshNames)) {
807
- visemeRows.push(
808
- index,
809
- Number(resolved.mesh.id),
810
- Number(resolved.morphTarget.id),
811
- bindingTarget.weight
812
- );
813
- }
814
- }
815
- }
816
- return {
817
- auBindings: Float32Array.from(auRows),
818
- visemeBindings: Float32Array.from(visemeRows),
819
- mixedAus: Uint32Array.from(mixed)
820
- };
821
- }
822
- function compileBoneBindings(profile, model) {
823
- const referencedBones = /* @__PURE__ */ new Map();
824
- const findBone = (nodeKey) => {
825
- const bone = findBoneDescriptor(profile, model, nodeKey);
826
- if (bone) referencedBones.set(bone.id, bone);
827
- return bone;
828
- };
829
- const boneSideForAU = (auId, nodeKey) => {
830
- const side = profile.auToBones?.[auId]?.find((candidate) => candidate.node === nodeKey)?.side;
831
- if (side === "left") return BONE_SIDE_LEFT;
832
- if (side === "right") return BONE_SIDE_RIGHT;
833
- return BONE_SIDE_NONE;
834
- };
835
- const compositeRows = [];
836
- for (const composite of profile.compositeRotations || []) {
837
- const bone = findBone(composite.node);
838
- if (!bone) continue;
839
- const axes = [
840
- { axis: 1, config: composite.yaw },
841
- { axis: 0, config: composite.pitch },
842
- { axis: 2, config: composite.roll }
843
- ];
844
- for (const { axis, config } of axes) {
845
- if (!config) continue;
846
- const negativeAUs = toAUList(config.negative);
847
- const positiveAUs = toAUList(config.positive);
848
- const hasDirectional = negativeAUs.length > 0 && positiveAUs.length > 0;
849
- const valueRows = [];
850
- if (hasDirectional) {
851
- for (const auId of negativeAUs) {
852
- valueRows.push([auId, AXIS_GROUP_NEGATIVE, boneSideForAU(auId, composite.node)]);
853
- }
854
- for (const auId of positiveAUs) {
855
- valueRows.push([auId, AXIS_GROUP_POSITIVE, boneSideForAU(auId, composite.node)]);
856
- }
857
- } else {
858
- for (const auId of config.aus) {
859
- valueRows.push([auId, AXIS_GROUP_PLAIN, boneSideForAU(auId, composite.node)]);
860
- }
861
- }
862
- const bindingRows = [];
863
- const pushBindingRows = (auIds, group) => {
864
- for (const auId of auIds) {
865
- const binding = profile.auToBones?.[auId]?.find(
866
- (candidate) => candidate.node === composite.node
867
- );
868
- if (!binding?.maxDegrees) continue;
869
- const channel = ROTATION_CHANNELS[binding.channel];
870
- if (channel === void 0) continue;
871
- bindingRows.push([
872
- auId,
873
- group,
874
- boneSideForAU(auId, composite.node),
875
- channel,
876
- binding.scale,
877
- binding.maxDegrees
878
- ]);
879
- }
880
- };
881
- pushBindingRows(negativeAUs, AXIS_GROUP_NEGATIVE);
882
- pushBindingRows(positiveAUs, AXIS_GROUP_POSITIVE);
883
- pushBindingRows(config.aus, AXIS_GROUP_PLAIN);
884
- compositeRows.push(
885
- Number(bone.id),
886
- axis,
887
- hasDirectional ? 1 : 0,
888
- valueRows.length,
889
- bindingRows.length,
890
- 0,
891
- 0,
892
- 0
893
- );
894
- for (const row of valueRows) compositeRows.push(...row);
895
- for (const row of bindingRows) compositeRows.push(...row);
896
- }
897
- }
898
- const translationRows = [];
899
- for (const [auIdText, bindings] of Object.entries(profile.auToBones || {})) {
900
- const auId = Number(auIdText);
901
- if (Number.isNaN(auId)) continue;
902
- for (const binding of bindings || []) {
903
- const channel = TRANSLATION_CHANNELS[binding.channel];
904
- if (channel === void 0 || binding.maxUnits === void 0) continue;
905
- const bone = findBone(binding.node);
906
- if (!bone) continue;
907
- translationRows.push(auId, Number(bone.id), channel, binding.scale, binding.maxUnits);
908
- }
909
- }
910
- const jawRow = [];
911
- const jawBinding = findAutoVisemeJawBinding(profile, model);
912
- if (jawBinding?.maxDegrees) {
913
- const bone = findBone(jawBinding.node);
914
- const channel = ROTATION_CHANNELS[jawBinding.channel];
915
- if (bone && channel !== void 0) {
916
- jawRow.push(Number(bone.id), channel, jawBinding.scale, jawBinding.maxDegrees);
917
- }
918
- }
919
- const restRows = [];
920
- for (const bone of referencedBones.values()) {
921
- const position = bone.restTransform?.position;
922
- const rotation = bone.restTransform?.rotation;
923
- restRows.push(
924
- Number(bone.id),
925
- position?.x ?? 0,
926
- position?.y ?? 0,
927
- position?.z ?? 0,
928
- rotation?.x ?? 0,
929
- rotation?.y ?? 0,
930
- rotation?.z ?? 0,
931
- rotation?.w ?? 1
932
- );
933
- }
934
- return {
935
- restTransforms: Float32Array.from(restRows),
936
- compositeAxes: Float32Array.from(compositeRows),
937
- translations: Float32Array.from(translationRows),
938
- jawBinding: Float32Array.from(jawRow),
939
- visemeJawAmounts: Float32Array.from(getVisemeJawAmounts(profile) ?? [])
940
- };
941
- }
942
- function findBoneDescriptor(profile, model, nodeKey) {
943
- const configuredName = profile.boneNodes?.[nodeKey] || nodeKey;
944
- const prefix = profile.bonePrefix ?? "";
945
- const suffix = profile.boneSuffix ?? "";
946
- const prefixedName = prefix && !configuredName.startsWith(prefix) ? `${prefix}${configuredName}` : configuredName;
947
- const fullName = suffix && !prefixedName.endsWith(suffix) ? `${prefixedName}${suffix}` : prefixedName;
948
- const candidates = /* @__PURE__ */ new Set([nodeKey, configuredName, fullName]);
949
- return model.bones.find((bone) => candidates.has(bone.name));
950
- }
951
- function findAutoVisemeJawBinding(profile, model) {
952
- const isRotation = (binding) => binding?.channel === "rx" || binding?.channel === "ry" || binding?.channel === "rz";
953
- const candidates = [
954
- profile.auToBones?.[103]?.find(isRotation),
955
- profile.auToBones?.[26]?.find(isRotation)
956
- ].filter((binding) => !!binding);
957
- return candidates.find((binding) => !!findBoneDescriptor(profile, model, binding.node)) ?? candidates[0] ?? null;
958
- }
959
766
  function unpackBoneFrameDelta(values) {
960
767
  const stride = PACKED_BONE_FRAME_DELTA_STRIDE;
961
768
  const writes = [];
@@ -996,48 +803,7 @@ function unpackMorphFrameDelta(values) {
996
803
  }
997
804
  return writes;
998
805
  }
999
- function pushAuSide(rows, auId, side, morphs, meshNames, model, profile) {
1000
- for (const morph of morphs) {
1001
- for (const resolved of resolveMorphTargets(model, profile, morph, meshNames)) {
1002
- rows.push(
1003
- auId,
1004
- side,
1005
- Number(resolved.mesh.id),
1006
- Number(resolved.morphTarget.id),
1007
- 1
1008
- );
1009
- }
1010
- }
1011
- }
1012
- function resolveMorphTargets(model, profile, morph, meshNames) {
1013
- const result = [];
1014
- for (const meshName of meshNames) {
1015
- const mesh = model.meshes.find((candidate) => candidate.name === meshName);
1016
- if (!mesh) continue;
1017
- const morphTargets = mesh.morphTargetIds.map((id) => model.morphTargets.find((candidate) => candidate.id === id)).filter((target2) => !!target2);
1018
- const target = typeof morph === "number" ? morphTargets.find((candidate) => candidate.hostIndex === morph) : resolveMorphTargetByName2(morphTargets, morph, profile);
1019
- if (target) {
1020
- result.push({ mesh, morphTarget: target });
1021
- }
1022
- }
1023
- return result;
1024
- }
1025
- function resolveMorphTargetByName2(targets, key, profile) {
1026
- const prefix = profile.morphPrefix || "";
1027
- const suffix = profile.morphSuffix || "";
1028
- const fullName = prefix + key + suffix;
1029
- const exact = targets.find((target) => target.name === fullName);
1030
- if (exact) return exact;
1031
- const suffixRegex = profile.suffixPattern ? new RegExp(profile.suffixPattern) : null;
1032
- if (!suffixRegex) return void 0;
1033
- return targets.find((target) => {
1034
- if (!target.name.startsWith(fullName)) return false;
1035
- const candidateSuffix = target.name.slice(fullName.length);
1036
- return candidateSuffix === "" || suffixRegex.test(candidateSuffix);
1037
- });
1038
- }
1039
806
 
1040
- exports.AU_MORPH_BINDING_STRIDE = AU_MORPH_BINDING_STRIDE;
1041
807
  exports.MESH_PROPORTIONS_FIELDS = MESH_PROPORTIONS_FIELDS;
1042
808
  exports.MESH_PROPORTIONS_STRIDE = MESH_PROPORTIONS_STRIDE;
1043
809
  exports.TEMPLATE_SKELETON_FIT_METADATA_KIND = TEMPLATE_SKELETON_FIT_METADATA_KIND;
@@ -1051,10 +817,7 @@ exports.TEMPLATE_SKELETON_FIT_VERTICAL_ANCHORS = TEMPLATE_SKELETON_FIT_VERTICAL_
1051
817
  exports.TEMPLATE_SKELETON_FIT_VERTICAL_AXES = TEMPLATE_SKELETON_FIT_VERTICAL_AXES;
1052
818
  exports.TsClipCompiler = TsClipCompiler;
1053
819
  exports.TsRuntimeCore = TsRuntimeCore;
1054
- exports.VISEME_MORPH_BINDING_STRIDE = VISEME_MORPH_BINDING_STRIDE;
1055
820
  exports.WasmRuntimeCore = WasmRuntimeCore;
1056
- exports.compileBoneBindings = compileBoneBindings;
1057
- exports.compileMorphBindings = compileMorphBindings;
1058
821
  exports.composeTemplateSkeletonFitTransform = composeTemplateSkeletonFitTransform;
1059
822
  exports.isTemplateSkeletonFitStatus = isTemplateSkeletonFitStatus;
1060
823
  exports.numericArrayToNumbers = numericArrayToNumbers;