@sage-rsc/talking-head-react 1.4.0 → 1.4.1
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.cjs +1 -1
- package/dist/index.js +3174 -1350
- package/package.json +1 -1
- package/src/lib/talkinghead.mjs +46 -20
- package/src/lib/talkinghead.mjs.new +2 -2
package/package.json
CHANGED
package/src/lib/talkinghead.mjs
CHANGED
|
@@ -1128,7 +1128,7 @@ class TalkingHead {
|
|
|
1128
1128
|
});
|
|
1129
1129
|
} else {
|
|
1130
1130
|
if (obj.material.map) obj.material.map.dispose();
|
|
1131
|
-
|
|
1131
|
+
obj.material.dispose();
|
|
1132
1132
|
}
|
|
1133
1133
|
}
|
|
1134
1134
|
}
|
|
@@ -1244,7 +1244,7 @@ class TalkingHead {
|
|
|
1244
1244
|
this.lockedPosition = null;
|
|
1245
1245
|
this.originalPosition = null;
|
|
1246
1246
|
this.positionWasLocked = false;
|
|
1247
|
-
|
|
1247
|
+
|
|
1248
1248
|
// Initialize FBX animation loader
|
|
1249
1249
|
this.fbxAnimationLoader = null;
|
|
1250
1250
|
|
|
@@ -1256,7 +1256,7 @@ class TalkingHead {
|
|
|
1256
1256
|
this.mixer.removeEventListener('finished', this._mixerHandler);
|
|
1257
1257
|
this.mixer.stopAllAction();
|
|
1258
1258
|
this.mixer.uncacheRoot(this.armature);
|
|
1259
|
-
|
|
1259
|
+
this.mixer = null;
|
|
1260
1260
|
this._mixerHandler = null;
|
|
1261
1261
|
}
|
|
1262
1262
|
if ( this.isAvatarOnly ) {
|
|
@@ -2040,6 +2040,11 @@ class TalkingHead {
|
|
|
2040
2040
|
*/
|
|
2041
2041
|
setPoseFromTemplate(template, ms=2000) {
|
|
2042
2042
|
|
|
2043
|
+
// Guard against disposal: check if required objects exist
|
|
2044
|
+
if (!this.poseFactory || !this.poseTemplates) {
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
|
|
2043
2048
|
// Special cases
|
|
2044
2049
|
const isIntermediate = template && this.poseTarget && this.poseTarget.template && ((this.poseTarget.template.standing && template.lying) || (this.poseTarget.template.lying && template.standing));
|
|
2045
2050
|
const isSameTemplate = template && (template === this.poseCurrentTemplate);
|
|
@@ -2053,13 +2058,18 @@ class TalkingHead {
|
|
|
2053
2058
|
this.setPoseFromTemplate(template,ms);
|
|
2054
2059
|
}, duration);
|
|
2055
2060
|
} else {
|
|
2056
|
-
this.poseCurrentTemplate = template ||
|
|
2061
|
+
this.poseCurrentTemplate = template || this.poseCurrentTemplate;
|
|
2057
2062
|
}
|
|
2058
2063
|
|
|
2059
2064
|
// Set target
|
|
2060
2065
|
this.poseTarget = this.poseFactory(this.poseCurrentTemplate, duration);
|
|
2061
2066
|
this.poseWeightOnLeft = true;
|
|
2062
2067
|
|
|
2068
|
+
// Guard: ensure poseTarget was created successfully
|
|
2069
|
+
if (!this.poseTarget || !this.poseTarget.props) {
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2063
2073
|
// Mirror properties, if necessary
|
|
2064
2074
|
if ( (!isSameTemplate && !isWeightOnLeft) || (isSameTemplate && isWeightOnLeft ) ) {
|
|
2065
2075
|
this.poseTarget.props = this.mirrorPose(this.poseTarget.props);
|
|
@@ -2078,13 +2088,16 @@ class TalkingHead {
|
|
|
2078
2088
|
}
|
|
2079
2089
|
|
|
2080
2090
|
// Make sure deltas are included in the target
|
|
2091
|
+
// Guard against disposal: check if poseBase and its props exist
|
|
2092
|
+
if (this.poseBase && this.poseBase.props && this.poseDelta && this.poseDelta.props) {
|
|
2081
2093
|
Object.keys(this.poseDelta.props).forEach( key => {
|
|
2082
|
-
|
|
2094
|
+
if ( !this.poseTarget.props.hasOwnProperty(key) && this.poseBase.props[key] ) {
|
|
2083
2095
|
this.poseTarget.props[key] = this.poseBase.props[key].clone();
|
|
2084
2096
|
this.poseTarget.props[key].t = this.animClock;
|
|
2085
2097
|
this.poseTarget.props[key].d = duration;
|
|
2086
2098
|
}
|
|
2087
2099
|
});
|
|
2100
|
+
}
|
|
2088
2101
|
|
|
2089
2102
|
}
|
|
2090
2103
|
|
|
@@ -2868,17 +2881,24 @@ class TalkingHead {
|
|
|
2868
2881
|
}
|
|
2869
2882
|
|
|
2870
2883
|
/**
|
|
2871
|
-
* Get lip-sync processor based on language.
|
|
2884
|
+
* Get lip-sync processor based on language. Use statically imported modules.
|
|
2872
2885
|
* @param {string} lang Language
|
|
2873
|
-
* @param {string} [path="./"] Module path
|
|
2886
|
+
* @param {string} [path="./"] Module path (ignored, using static imports)
|
|
2874
2887
|
*/
|
|
2875
2888
|
lipsyncGetProcessor(lang, path="./") {
|
|
2876
2889
|
if ( !this.lipsync.hasOwnProperty(lang) ) {
|
|
2877
|
-
const
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2890
|
+
const langLower = lang.toLowerCase();
|
|
2891
|
+
// Use statically imported modules from LIPSYNC_MODULES
|
|
2892
|
+
if (LIPSYNC_MODULES[langLower]) {
|
|
2893
|
+
const className = 'Lipsync' + lang.charAt(0).toUpperCase() + lang.slice(1);
|
|
2894
|
+
if (LIPSYNC_MODULES[langLower][className]) {
|
|
2895
|
+
this.lipsync[lang] = new LIPSYNC_MODULES[langLower][className];
|
|
2896
|
+
} else {
|
|
2897
|
+
console.warn(`Lipsync class ${className} not found in module for language ${lang}`);
|
|
2898
|
+
}
|
|
2899
|
+
} else {
|
|
2900
|
+
console.warn(`Lipsync module for language ${lang} not found in static imports`);
|
|
2901
|
+
}
|
|
2882
2902
|
}
|
|
2883
2903
|
}
|
|
2884
2904
|
|
|
@@ -4326,10 +4346,10 @@ class TalkingHead {
|
|
|
4326
4346
|
setSlowdownRate(k) {
|
|
4327
4347
|
this.animSlowdownRate = k;
|
|
4328
4348
|
if ( this.audioSpeechSource ) {
|
|
4329
|
-
|
|
4349
|
+
this.audioSpeechSource.playbackRate.value = 1 / this.animSlowdownRate;
|
|
4330
4350
|
}
|
|
4331
4351
|
if ( this.audioBackgroundSource ) {
|
|
4332
|
-
|
|
4352
|
+
this.audioBackgroundSource.playbackRate.value = 1 / this.animSlowdownRate;
|
|
4333
4353
|
}
|
|
4334
4354
|
}
|
|
4335
4355
|
|
|
@@ -4737,7 +4757,7 @@ class TalkingHead {
|
|
|
4737
4757
|
this.mixer = null;
|
|
4738
4758
|
this._mixerHandler = null;
|
|
4739
4759
|
}
|
|
4740
|
-
|
|
4760
|
+
|
|
4741
4761
|
// Unlock position if it was locked
|
|
4742
4762
|
if (this.positionWasLocked) {
|
|
4743
4763
|
this.unlockAvatarPosition();
|
|
@@ -4747,7 +4767,7 @@ class TalkingHead {
|
|
|
4747
4767
|
}
|
|
4748
4768
|
|
|
4749
4769
|
// Restart gesture
|
|
4750
|
-
if ( this.gesture ) {
|
|
4770
|
+
if ( this.gesture && this.poseTarget && this.poseTarget.props ) {
|
|
4751
4771
|
for( let [p,v] of Object.entries(this.gesture) ) {
|
|
4752
4772
|
v.t = this.animClock;
|
|
4753
4773
|
v.d = 1000;
|
|
@@ -4760,11 +4780,17 @@ class TalkingHead {
|
|
|
4760
4780
|
}
|
|
4761
4781
|
|
|
4762
4782
|
// Restart pose animation
|
|
4783
|
+
if ( this.animQueue ) {
|
|
4763
4784
|
let anim = this.animQueue.find( x => x.template.name === 'pose' );
|
|
4764
4785
|
if ( anim ) {
|
|
4765
4786
|
anim.ts[0] = this.animClock;
|
|
4766
4787
|
}
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
// Only call setPoseFromTemplate if poseFactory exists (not disposed)
|
|
4791
|
+
if ( this.poseFactory ) {
|
|
4767
4792
|
this.setPoseFromTemplate( null );
|
|
4793
|
+
}
|
|
4768
4794
|
|
|
4769
4795
|
}
|
|
4770
4796
|
|
|
@@ -4799,7 +4825,7 @@ class TalkingHead {
|
|
|
4799
4825
|
this.mixer.removeEventListener('finished', this._mixerHandler);
|
|
4800
4826
|
this.mixer.stopAllAction();
|
|
4801
4827
|
this.mixer.uncacheRoot(this.armature);
|
|
4802
|
-
|
|
4828
|
+
this.mixer = null;
|
|
4803
4829
|
this._mixerHandler = null;
|
|
4804
4830
|
}
|
|
4805
4831
|
let anim = this.animQueue.find( x => x.template.name === 'pose' );
|
|
@@ -5514,7 +5540,7 @@ class TalkingHead {
|
|
|
5514
5540
|
this.clearThree(this.scene);
|
|
5515
5541
|
this.resizeobserver.disconnect();
|
|
5516
5542
|
this.resizeobserver = null;
|
|
5517
|
-
|
|
5543
|
+
|
|
5518
5544
|
if ( this.renderer ) {
|
|
5519
5545
|
this.renderer.dispose();
|
|
5520
5546
|
const gl = this.renderer.getContext();
|
|
@@ -5527,12 +5553,12 @@ class TalkingHead {
|
|
|
5527
5553
|
if ( this.controls ) {
|
|
5528
5554
|
this.controls.dispose();
|
|
5529
5555
|
this.controls = null;
|
|
5530
|
-
|
|
5556
|
+
}
|
|
5531
5557
|
}
|
|
5532
5558
|
|
|
5533
5559
|
this.clearThree( this.ikMesh );
|
|
5534
5560
|
this.dynamicbones.dispose();
|
|
5535
|
-
|
|
5561
|
+
|
|
5536
5562
|
// Clean up FBX animation loader
|
|
5537
5563
|
if (this.fbxAnimationLoader) {
|
|
5538
5564
|
this.fbxAnimationLoader.stopCurrentAnimation();
|
|
@@ -4448,7 +4448,7 @@ class TalkingHead {
|
|
|
4448
4448
|
|
|
4449
4449
|
// Use existing mixer or create new one if none exists
|
|
4450
4450
|
if (!this.mixer) {
|
|
4451
|
-
|
|
4451
|
+
this.mixer = new THREE.AnimationMixer(this.armature);
|
|
4452
4452
|
console.log('Created new mixer for FBX animation');
|
|
4453
4453
|
} else {
|
|
4454
4454
|
console.log('Using existing mixer for FBX animation, preserving morph targets');
|
|
@@ -4465,7 +4465,7 @@ class TalkingHead {
|
|
|
4465
4465
|
this.currentFBXAction = action;
|
|
4466
4466
|
|
|
4467
4467
|
try {
|
|
4468
|
-
|
|
4468
|
+
action.fadeIn(0.5).play();
|
|
4469
4469
|
console.log('FBX animation started successfully:', url);
|
|
4470
4470
|
} catch (error) {
|
|
4471
4471
|
console.warn('FBX animation failed to start:', error);
|