@lovelace_lol/loom3 1.0.43 → 1.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1755,6 +1755,8 @@ declare class Loom3 implements LoomLarge {
1755
1755
  private computeSideValues;
1756
1756
  private getAUMorphsBySide;
1757
1757
  private applyMorphTargets;
1758
+ private applyVisemeRuntimeState;
1759
+ private getActiveVisemeJawAmount;
1758
1760
  private getMorphValue;
1759
1761
  private getMorphValueByIndex;
1760
1762
  private applyMorphTargetDelta;
@@ -1963,9 +1965,14 @@ interface HairPhysics$1 {
1963
1965
  reset(): void;
1964
1966
  }
1965
1967
 
1968
+ interface ResolvedVisemeBindingTarget {
1969
+ morph: MorphTargetRef;
1970
+ weight: number;
1971
+ }
1966
1972
  declare function getProfileVisemeSlots(profile: Profile): VisemeSlot[];
1967
1973
  declare function getVisemeSlotIndex(profile: Profile, slotId: string): number;
1968
1974
  declare function compileVisemeKeys(profile: Profile): MorphTargetRef[];
1975
+ declare function getVisemeBindingTargets(profile: Profile, visemeIndex: number): ResolvedVisemeBindingTarget[];
1969
1976
  declare function getVisemeJawAmounts(profile: Profile): number[] | undefined;
1970
1977
  declare function resolveVisemeMeshCategory(profile: Profile): string;
1971
1978
  declare function getMeshNamesForVisemeProfile(profile: Profile): string[];
@@ -2638,4 +2645,4 @@ declare function detectFacingDirection(model: THREE.Object3D, eyeBoneNames?: {
2638
2645
  right: string[];
2639
2646
  }): 'forward' | 'backward' | 'unknown';
2640
2647
 
2641
- export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AddMorphTargetOptions, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingEditorModel, type MappingEditorSection, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCandidate, type MorphCandidateMatch, type MorphCandidateReason, type MorphCategory, type MorphInfo, type MorphTargetAttributeData, type MorphTargetDelta, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ProviderVisemeEvent, type ProviderVisemeMatch, type ReadyPayload, type Region, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, type VisemeBinding, type VisemeBindingTarget, type VisemeSlot, type VisemeSlotFeatures, analyzeModel, applyCharacterProfileToPreset, buildMappingEditorModel, collectMorphMeshes, compileVisemeKeys, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getPreset, getPresetWithProfile, getProfileVisemeSlots, getVisemeJawAmounts, getVisemeSlotIndex, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveVisemeMeshCategory, suggestBestPreset, validateMappingConfig, validateMappings };
2648
+ export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AddMorphTargetOptions, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingEditorModel, type MappingEditorSection, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCandidate, type MorphCandidateMatch, type MorphCandidateReason, type MorphCategory, type MorphInfo, type MorphTargetAttributeData, type MorphTargetDelta, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ProviderVisemeEvent, type ProviderVisemeMatch, type ReadyPayload, type Region, type ResolvedVisemeBindingTarget, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, type VisemeBinding, type VisemeBindingTarget, type VisemeSlot, type VisemeSlotFeatures, analyzeModel, applyCharacterProfileToPreset, buildMappingEditorModel, collectMorphMeshes, compileVisemeKeys, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getPreset, getPresetWithProfile, getProfileVisemeSlots, getVisemeBindingTargets, getVisemeJawAmounts, getVisemeSlotIndex, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveVisemeMeshCategory, suggestBestPreset, validateMappingConfig, validateMappings };
package/dist/index.d.ts CHANGED
@@ -1755,6 +1755,8 @@ declare class Loom3 implements LoomLarge {
1755
1755
  private computeSideValues;
1756
1756
  private getAUMorphsBySide;
1757
1757
  private applyMorphTargets;
1758
+ private applyVisemeRuntimeState;
1759
+ private getActiveVisemeJawAmount;
1758
1760
  private getMorphValue;
1759
1761
  private getMorphValueByIndex;
1760
1762
  private applyMorphTargetDelta;
@@ -1963,9 +1965,14 @@ interface HairPhysics$1 {
1963
1965
  reset(): void;
1964
1966
  }
1965
1967
 
1968
+ interface ResolvedVisemeBindingTarget {
1969
+ morph: MorphTargetRef;
1970
+ weight: number;
1971
+ }
1966
1972
  declare function getProfileVisemeSlots(profile: Profile): VisemeSlot[];
1967
1973
  declare function getVisemeSlotIndex(profile: Profile, slotId: string): number;
1968
1974
  declare function compileVisemeKeys(profile: Profile): MorphTargetRef[];
1975
+ declare function getVisemeBindingTargets(profile: Profile, visemeIndex: number): ResolvedVisemeBindingTarget[];
1969
1976
  declare function getVisemeJawAmounts(profile: Profile): number[] | undefined;
1970
1977
  declare function resolveVisemeMeshCategory(profile: Profile): string;
1971
1978
  declare function getMeshNamesForVisemeProfile(profile: Profile): string[];
@@ -2638,4 +2645,4 @@ declare function detectFacingDirection(model: THREE.Object3D, eyeBoneNames?: {
2638
2645
  right: string[];
2639
2646
  }): 'forward' | 'backward' | 'unknown';
2640
2647
 
2641
- export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AddMorphTargetOptions, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingEditorModel, type MappingEditorSection, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCandidate, type MorphCandidateMatch, type MorphCandidateReason, type MorphCategory, type MorphInfo, type MorphTargetAttributeData, type MorphTargetDelta, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ProviderVisemeEvent, type ProviderVisemeMatch, type ReadyPayload, type Region, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, type VisemeBinding, type VisemeBindingTarget, type VisemeSlot, type VisemeSlotFeatures, analyzeModel, applyCharacterProfileToPreset, buildMappingEditorModel, collectMorphMeshes, compileVisemeKeys, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getPreset, getPresetWithProfile, getProfileVisemeSlots, getVisemeJawAmounts, getVisemeSlotIndex, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveVisemeMeshCategory, suggestBestPreset, validateMappingConfig, validateMappings };
2648
+ export { type AUInfo, type AUSelector, AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, type AddMorphTargetOptions, type AnalyzeModelOptions, type Animation, type AnimationActionHandle, type AnimationAnalysis, type AnimationBlendMode, type AnimationClipInfo, type AnimationEasing, type AnimationInfo, type AnimationPlayOptions, type AnimationSource, type AnimationState, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, type BlendingMode, type BoneBinding, type BoneInfo, type BoneKey, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, type CameraRelativeGazeOffset, type CameraRelativeGazeOptions, type CharacterConfig, type CharacterRegistry, type ClipEvent, type ClipEventListener, type ClipHandle, type ClipOptions, type CompositeRotation, type CompositeRotationState, type CurvePoint, type CurvesMap, DEFAULT_HAIR_PHYSICS_CONFIG, type ExpandAnimation, type ExpandedRegionState, FISH_AU_MAPPING_CONFIG, type FaceCenterResult, type FallbackConfig, type FindFaceCenterOptions, type Hair, type HairMorphAxis, type HairMorphOutput$1 as HairMorphOutput, type HairMorphTargetMapping, type HairMorphTargetValueMapping, type HairMorphTargetsConfig, type HairObjectRef, type HairObjectState, HairPhysics, type HairPhysicsConfig$1 as HairPhysicsConfig, type HairPhysicsDirectionConfig, type HairPhysics$1 as HairPhysicsInterface, type HairMorphOutput as HairPhysicsMorphOutput, type HairPhysicsProfileConfig, type HairPhysicsRuntimeConfig, type HairPhysicsRuntimeConfigUpdate, type HairPhysicsState, type HairState, type HairStrand, type HeadState$1 as HeadState, type LineConfig, type LineCurve, type LineStyle, Loom3, type Loom3Config, Loom3 as Loom3Three, type LoomLarge, type LoomLargeConfig, Loom3 as LoomLargeThree, MORPH_TO_MESH, type MappingConsistencyResult, type MappingCorrection, type MappingCorrectionOptions, type MappingCorrectionResult, type MappingEditorModel, type MappingEditorSection, type MappingIssue, type MarkerGroup, type MarkerStyle, type MarkerStyleOverrides, type MeshCategory, type MeshInfo, type MeshMaterialSettings, type MixerLoopMode, type ModelAnalysisReport, type ModelData, type ModelMeshInfo, type MorphCandidate, type MorphCandidateMatch, type MorphCandidateReason, type MorphCategory, type MorphInfo, type MorphTargetAttributeData, type MorphTargetDelta, type MorphTargetRef, type MorphTargetsBySide, type NamedDirection, type PresetType, type Profile, type ProviderVisemeEvent, type ProviderVisemeMatch, type ReadyPayload, type Region, type ResolvedVisemeBindingTarget, type RotationAxis, type RotationsState, type Snippet, type TrackInfo, type TransitionHandle, VISEME_JAW_AMOUNTS, VISEME_KEYS, type ValidateMappingOptions, type ValidationResult, type VisemeBinding, type VisemeBindingTarget, type VisemeSlot, type VisemeSlotFeatures, analyzeModel, applyCharacterProfileToPreset, buildMappingEditorModel, collectMorphMeshes, compileVisemeKeys, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getPreset, getPresetWithProfile, getProfileVisemeSlots, getVisemeBindingTargets, getVisemeJawAmounts, getVisemeSlotIndex, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveVisemeMeshCategory, suggestBestPreset, validateMappingConfig, validateMappings };
package/dist/index.js CHANGED
@@ -53,6 +53,9 @@ function bindingTargets(binding) {
53
53
  if (targets && targets.length > 0) return targets;
54
54
  return binding.morph !== void 0 && binding.morph !== "" ? [binding.morph] : [];
55
55
  }
56
+ function normalizeBindingWeight(weight) {
57
+ return Number.isFinite(weight) ? Math.max(0, weight ?? 1) : 1;
58
+ }
56
59
  function getProfileVisemeSlots(profile) {
57
60
  if (profile.visemeSlots && profile.visemeSlots.length > 0) {
58
61
  return [...profile.visemeSlots].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
@@ -78,6 +81,23 @@ function compileVisemeKeys(profile) {
78
81
  return target ?? profile.visemeKeys?.[index] ?? "";
79
82
  });
80
83
  }
84
+ function getVisemeBindingTargets(profile, visemeIndex) {
85
+ const slots = getProfileVisemeSlots(profile);
86
+ const slot = slots[visemeIndex];
87
+ const binding = slot ? profile.visemeBindings?.[slot.id] : void 0;
88
+ const boundTargets = binding?.targets?.filter((target) => target.morph !== void 0 && target.morph !== "").map((target) => ({
89
+ morph: target.morph,
90
+ weight: normalizeBindingWeight(target.weight)
91
+ }));
92
+ if (boundTargets && boundTargets.length > 0) {
93
+ return boundTargets;
94
+ }
95
+ if (binding?.morph !== void 0 && binding.morph !== "") {
96
+ return [{ morph: binding.morph, weight: 1 }];
97
+ }
98
+ const legacyTarget = profile.visemeKeys?.[visemeIndex];
99
+ return legacyTarget !== void 0 && legacyTarget !== "" ? [{ morph: legacyTarget, weight: 1 }] : [];
100
+ }
81
101
  function getVisemeJawAmounts(profile) {
82
102
  const slots = getProfileVisemeSlots(profile);
83
103
  if (slots.length === 0) return profile.visemeJawAmounts ? [...profile.visemeJawAmounts] : void 0;
@@ -1714,12 +1734,13 @@ var BakedAnimationController = class {
1714
1734
  const globalBalance = options?.balance ?? 0;
1715
1735
  const balanceMap = options?.balanceMap;
1716
1736
  const meshNames = options?.meshNames;
1737
+ const visemeSlotCount = getProfileVisemeSlots(config).length;
1717
1738
  let maxTime = 0;
1718
1739
  const isNumericAU = (id) => /^\d+$/.test(id);
1719
1740
  const isVisemeIndex = (id) => {
1720
1741
  if (options?.snippetCategory !== "visemeSnippet") return false;
1721
1742
  const num = Number(id);
1722
- return !Number.isNaN(num) && num >= 0 && num < config.visemeKeys.length;
1743
+ return !Number.isNaN(num) && num >= 0 && num < visemeSlotCount;
1723
1744
  };
1724
1745
  const sampleAt = (arr, t) => {
1725
1746
  if (!arr.length) return 0;
@@ -1757,11 +1778,13 @@ var BakedAnimationController = class {
1757
1778
  const auId = Number(curveId);
1758
1779
  if (isVisemeIndex(curveId)) {
1759
1780
  const visemeMeshNames = this.getMeshNamesForViseme(config, meshNames);
1760
- const visemeKey = config.visemeKeys[auId];
1761
- if (typeof visemeKey === "number") {
1762
- this.addMorphIndexTracks(tracks, visemeKey, keyframes, intensityScale, visemeMeshNames);
1763
- } else if (visemeKey) {
1764
- this.addMorphTracks(tracks, visemeKey, keyframes, intensityScale, visemeMeshNames);
1781
+ for (const target of getVisemeBindingTargets(config, auId)) {
1782
+ const effectiveScale = intensityScale * target.weight;
1783
+ if (typeof target.morph === "number") {
1784
+ this.addMorphIndexTracks(tracks, target.morph, keyframes, effectiveScale, visemeMeshNames);
1785
+ } else if (target.morph) {
1786
+ this.addMorphTracks(tracks, target.morph, keyframes, effectiveScale, visemeMeshNames);
1787
+ }
1765
1788
  }
1766
1789
  } else {
1767
1790
  const auMeshNames = this.getMeshNamesForAU(auId, config, meshNames);
@@ -1804,7 +1827,7 @@ var BakedAnimationController = class {
1804
1827
  }
1805
1828
  const autoVisemeJaw = options?.autoVisemeJaw !== false;
1806
1829
  const jawScale = options?.jawScale ?? 1;
1807
- const visemeJawAmounts = config.visemeJawAmounts;
1830
+ const visemeJawAmounts = getVisemeJawAmounts(config);
1808
1831
  if (autoVisemeJaw && jawScale > 0 && visemeJawAmounts && options?.snippetCategory === "visemeSnippet" && keyframeTimes.length > 0) {
1809
1832
  const bones = this.host.getBones();
1810
1833
  const jawEntry = bones["JAW"];
@@ -1812,7 +1835,7 @@ var BakedAnimationController = class {
1812
1835
  const jawValues = [];
1813
1836
  for (const t of keyframeTimes) {
1814
1837
  let jawAmount = 0;
1815
- for (let visemeIdx = 0; visemeIdx < config.visemeKeys.length; visemeIdx++) {
1838
+ for (let visemeIdx = 0; visemeIdx < visemeSlotCount; visemeIdx++) {
1816
1839
  const visemeCurve = curves[String(visemeIdx)];
1817
1840
  if (!visemeCurve) continue;
1818
1841
  const visemeValue = clampIntensity(sampleAt(visemeCurve, t) * intensityScale);
@@ -5340,10 +5363,15 @@ var _Loom3 = class _Loom3 {
5340
5363
  };
5341
5364
  this.resolvedAUMorphTargets.set(auId, resolved);
5342
5365
  }
5343
- for (let i = 0; i < (this.config.visemeKeys || []).length; i += 1) {
5344
- const key = this.config.visemeKeys[i];
5366
+ for (let i = 0; i < getProfileVisemeSlots(this.config).length; i += 1) {
5345
5367
  const visemeMeshNames = this.getMeshNamesForViseme();
5346
- const targets = typeof key === "number" ? this.resolveMorphTargetsByIndex(key, visemeMeshNames) : this.resolveMorphTargets(key, visemeMeshNames);
5368
+ const targets = [];
5369
+ for (const bindingTarget of getVisemeBindingTargets(this.config, i)) {
5370
+ const resolved = typeof bindingTarget.morph === "number" ? this.resolveMorphTargetsByIndex(bindingTarget.morph, visemeMeshNames) : this.resolveMorphTargets(bindingTarget.morph, visemeMeshNames);
5371
+ for (const target of resolved) {
5372
+ targets.push({ ...target, weight: bindingTarget.weight });
5373
+ }
5374
+ }
5347
5375
  this.resolvedVisemeTargets[i] = targets;
5348
5376
  }
5349
5377
  }
@@ -5811,46 +5839,33 @@ var _Loom3 = class _Loom3 {
5811
5839
  // VISEME CONTROL
5812
5840
  // ============================================================================
5813
5841
  setViseme(visemeIndex, value, jawScale = 1) {
5814
- if (visemeIndex < 0 || visemeIndex >= this.config.visemeKeys.length) return;
5842
+ if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) return;
5815
5843
  const val = clamp012(value);
5816
5844
  this.visemeValues[visemeIndex] = val;
5817
5845
  this.visemeJawScales[visemeIndex] = jawScale;
5818
- const targets = this.resolvedVisemeTargets[visemeIndex];
5819
- if (targets && targets.length > 0) {
5820
- this.applyMorphTargets(targets, val);
5821
- } else {
5822
- const morphKey = this.config.visemeKeys[visemeIndex];
5823
- const visemeMeshNames = this.getMeshNamesForViseme();
5824
- if (typeof morphKey === "number") {
5825
- this.setMorphInfluence(morphKey, val, visemeMeshNames);
5826
- } else if (typeof morphKey === "string") {
5827
- this.setMorph(morphKey, val, visemeMeshNames);
5828
- }
5829
- }
5830
- const jawAmount = this.getVisemeJawAmount(visemeIndex) * val * jawScale;
5831
- if (Math.abs(jawScale) > 1e-6 && Math.abs(jawAmount) > 1e-6) {
5832
- this.updateBoneRotation("JAW", "pitch", jawAmount);
5833
- }
5846
+ this.applyVisemeRuntimeState();
5834
5847
  }
5835
5848
  transitionViseme(visemeIndex, to, durationMs = 80, jawScale = 1) {
5836
- if (visemeIndex < 0 || visemeIndex >= this.config.visemeKeys.length) {
5849
+ if (visemeIndex < 0 || visemeIndex >= this.visemeValues.length) {
5837
5850
  return { promise: Promise.resolve(), pause: () => {
5838
5851
  }, resume: () => {
5839
5852
  }, cancel: () => {
5840
5853
  } };
5841
5854
  }
5842
- const morphKey = this.config.visemeKeys[visemeIndex];
5843
5855
  const target = clamp012(to);
5844
- this.visemeValues[visemeIndex] = target;
5856
+ const from = this.visemeValues[visemeIndex] ?? 0;
5845
5857
  this.visemeJawScales[visemeIndex] = jawScale;
5846
- const visemeMeshNames = this.getMeshNamesForViseme();
5847
- const morphHandle = typeof morphKey === "number" ? this.transitionMorphInfluence(morphKey, target, durationMs, visemeMeshNames) : this.transitionMorph(morphKey, target, durationMs, visemeMeshNames);
5848
- const jawAmount = this.getVisemeJawAmount(visemeIndex) * target * jawScale;
5849
- if (Math.abs(jawScale) <= 1e-6 || Math.abs(jawAmount) <= 1e-6) {
5850
- return morphHandle;
5851
- }
5852
- const jawHandle = this.transitionBoneRotation("JAW", "pitch", jawAmount, durationMs);
5853
- return this.combineHandles([morphHandle, jawHandle]);
5858
+ return this.animation.addTransition(
5859
+ `viseme_value_${visemeIndex}`,
5860
+ from,
5861
+ target,
5862
+ durationMs,
5863
+ (value) => {
5864
+ this.visemeValues[visemeIndex] = clamp012(value);
5865
+ this.visemeJawScales[visemeIndex] = jawScale;
5866
+ this.applyVisemeRuntimeState();
5867
+ }
5868
+ );
5854
5869
  }
5855
5870
  setVisemeById(slotId, value, jawScale = 1) {
5856
5871
  const index = getVisemeSlotIndex(this.config, slotId);
@@ -5914,8 +5929,9 @@ var _Loom3 = class _Loom3 {
5914
5929
  }
5915
5930
  resetToNeutral() {
5916
5931
  this.auValues = {};
5917
- this.visemeValues = new Array(this.config.visemeKeys.length).fill(0);
5918
- this.visemeJawScales = new Array(this.config.visemeKeys.length).fill(1);
5932
+ const visemeCount = getProfileVisemeSlots(this.config).length;
5933
+ this.visemeValues = new Array(visemeCount).fill(0);
5934
+ this.visemeJawScales = new Array(visemeCount).fill(1);
5919
5935
  this.translations = {};
5920
5936
  this.initBoneRotations();
5921
5937
  this.clearTransitions();
@@ -5949,11 +5965,7 @@ var _Loom3 = class _Loom3 {
5949
5965
  if (Number.isNaN(auId)) continue;
5950
5966
  this.setAU(auId, value, this.auBalances[auId]);
5951
5967
  }
5952
- for (let visemeIndex = 0; visemeIndex < this.visemeValues.length; visemeIndex += 1) {
5953
- const value = this.visemeValues[visemeIndex] ?? 0;
5954
- if (value <= 0) continue;
5955
- this.setViseme(visemeIndex, value, this.visemeJawScales[visemeIndex] ?? 1);
5956
- }
5968
+ this.applyVisemeRuntimeState();
5957
5969
  if (this.model) {
5958
5970
  this.flushPendingComposites();
5959
5971
  this.model.updateMatrixWorld(true);
@@ -6311,6 +6323,37 @@ var _Loom3 = class _Loom3 {
6311
6323
  target.infl[target.idx] = val;
6312
6324
  }
6313
6325
  }
6326
+ applyVisemeRuntimeState() {
6327
+ for (const targets of this.resolvedVisemeTargets) {
6328
+ for (const target of targets || []) {
6329
+ if (target.idx < target.infl.length) {
6330
+ target.infl[target.idx] = 0;
6331
+ }
6332
+ }
6333
+ }
6334
+ for (let index = 0; index < this.visemeValues.length; index += 1) {
6335
+ const value = clamp012(this.visemeValues[index] ?? 0);
6336
+ if (value <= 1e-6) continue;
6337
+ const targets = this.resolvedVisemeTargets[index] || [];
6338
+ for (const target of targets) {
6339
+ if (target.idx >= target.infl.length) continue;
6340
+ const weighted = clamp012(value * target.weight);
6341
+ target.infl[target.idx] = Math.max(target.infl[target.idx] ?? 0, weighted);
6342
+ }
6343
+ }
6344
+ this.updateBoneRotation("JAW", "pitch", this.getActiveVisemeJawAmount());
6345
+ }
6346
+ getActiveVisemeJawAmount() {
6347
+ let jawAmount = 0;
6348
+ for (let index = 0; index < this.visemeValues.length; index += 1) {
6349
+ const value = clamp012(this.visemeValues[index] ?? 0);
6350
+ if (value <= 1e-6) continue;
6351
+ const jawScale = this.visemeJawScales[index] ?? 1;
6352
+ if (Math.abs(jawScale) <= 1e-6) continue;
6353
+ jawAmount = Math.max(jawAmount, this.getVisemeJawAmount(index) * value * jawScale);
6354
+ }
6355
+ return jawAmount;
6356
+ }
6314
6357
  getMorphValue(key) {
6315
6358
  if (this.faceMesh) {
6316
6359
  const dict = this.faceMesh.morphTargetDictionary;
@@ -6496,7 +6539,7 @@ var _Loom3 = class _Loom3 {
6496
6539
  return meshNames?.length ? `idx:${index}@${meshNames.join(",")}` : `idx:${index}`;
6497
6540
  }
6498
6541
  syncVisemeRuntimeState() {
6499
- const visemeCount = this.config.visemeKeys.length;
6542
+ const visemeCount = getProfileVisemeSlots(this.config).length;
6500
6543
  this.visemeValues = Array.from(
6501
6544
  { length: visemeCount },
6502
6545
  (_, index) => this.visemeValues[index] ?? 0
@@ -8569,6 +8612,6 @@ async function analyzeModel(options) {
8569
8612
  };
8570
8613
  }
8571
8614
 
8572
- export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_HAIR_PHYSICS_CONFIG, FISH_AU_MAPPING_CONFIG, HairPhysics, Loom3, Loom3 as Loom3Three, Loom3 as LoomLargeThree, MORPH_TO_MESH, VISEME_JAW_AMOUNTS, VISEME_KEYS, analyzeModel, applyCharacterProfileToPreset, buildMappingEditorModel, collectMorphMeshes, compileVisemeKeys, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getPreset, getPresetWithProfile, getProfileVisemeSlots, getVisemeJawAmounts, getVisemeSlotIndex, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveVisemeMeshCategory, suggestBestPreset, validateMappingConfig, validateMappings };
8615
+ export { AU_INFO, AU_MAPPING_CONFIG, AU_MIX_DEFAULTS, AU_TO_MORPHS, AnimationThree, BETTA_FISH_PRESET, BLENDING_MODES, BONE_AU_TO_BINDINGS, CC4_BONE_NODES, CC4_BONE_PREFIX, CC4_EYE_MESH_NODES, CC4_MAPPING_SECTIONS, CC4_MESHES, CC4_PRESET, CC4_SUFFIX_PATTERN, CC4_VISEME_SLOTS, CC4_VISEME_SYSTEM_ID, COMPOSITE_ROTATIONS, CONTINUUM_LABELS, CONTINUUM_PAIRS_MAP, DEFAULT_HAIR_PHYSICS_CONFIG, FISH_AU_MAPPING_CONFIG, HairPhysics, Loom3, Loom3 as Loom3Three, Loom3 as LoomLargeThree, MORPH_TO_MESH, VISEME_JAW_AMOUNTS, VISEME_KEYS, analyzeModel, applyCharacterProfileToPreset, buildMappingEditorModel, collectMorphMeshes, compileVisemeKeys, computeCameraRelativeGazeOffset, detectFacingDirection, extendCharacterConfigWithPreset, extendPresetWithProfile, extractFromGLTF, extractModelData, extractProfileOverrides, findFaceCenter, fuzzyNameMatch, generateMappingCorrections, getMeshNamesForAUProfile, getMeshNamesForVisemeProfile, getModelForwardDirection, getPreset, getPresetWithProfile, getProfileVisemeSlots, getVisemeBindingTargets, getVisemeJawAmounts, getVisemeSlotIndex, hasLeftRightMorphs, isMixedAU, isPresetCompatible, mapProviderVisemeToSlot, mergeRegionsByName as mergeCharacterRegionsByName, resolveBoneName, resolveBoneNames, resolveFaceCenter, resolvePreset, resolvePresetWithOverrides, resolveVisemeMeshCategory, suggestBestPreset, validateMappingConfig, validateMappings };
8573
8616
  //# sourceMappingURL=index.js.map
8574
8617
  //# sourceMappingURL=index.js.map