@memori.ai/memori-react 7.8.4 → 7.8.6
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/CHANGELOG.md +26 -0
- package/dist/components/Avatar/Avatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +4 -2
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.d.ts +34 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js +147 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.d.ts +17 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.js +73 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.d.ts +17 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js +25 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +2 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +83 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.d.ts +35 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.js +10 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.js.map +1 -0
- package/dist/components/Avatar/AvatarView/index.js.map +1 -1
- package/dist/context/visemeContext.d.ts +1 -1
- package/dist/context/visemeContext.js +2 -2
- package/dist/context/visemeContext.js.map +1 -1
- package/esm/components/Avatar/Avatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +4 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.d.ts +34 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js +143 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.d.ts +17 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.js +69 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.d.ts +17 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js +22 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.d.ts +2 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +80 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.d.ts +35 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.js +7 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.js.map +1 -0
- package/esm/components/Avatar/AvatarView/index.js.map +1 -1
- package/esm/context/visemeContext.d.ts +1 -1
- package/esm/context/visemeContext.js +2 -2
- package/esm/context/visemeContext.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Avatar/Avatar.tsx +2 -3
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +6 -13
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/AnimationController.ts +260 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.ts +123 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.ts +28 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +147 -0
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/types.ts +40 -0
- package/src/components/Avatar/AvatarView/index.tsx +4 -4
- package/src/context/visemeContext.tsx +2 -2
- package/src/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.tsx +0 -281
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visemeContext.js","sourceRoot":"","sources":["../../src/context/visemeContext.tsx"],"names":[],"mappings":";AAAA,OAAc,EACZ,aAAa,EACb,UAAU,EACV,MAAM,EACN,WAAW,EACX,QAAQ,EACR,OAAO,GACR,MAAM,OAAO,CAAC;AAqBf,MAAM,aAAa,GAAG,aAAa,CAAgC,SAAS,CAAC,CAAC;AAE9E,MAAM,UAAU,GAAwC;IACtD,CAAC,EAAE,YAAY;IACf,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,UAAU;IACd,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,WAAW;IACf,EAAE,EAAE,WAAW;CAChB,CAAC;AAGF,MAAM,SAAS,GAAG;IAKhB,uBAAuB,EAAE,GAAG;IAK5B,cAAc,EAAE,IAAI;IAMpB,gBAAgB,EAAE,
|
|
1
|
+
{"version":3,"file":"visemeContext.js","sourceRoot":"","sources":["../../src/context/visemeContext.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -53,7 +53,6 @@ const Avatar: React.FC<Props> = ({
|
|
|
53
53
|
isZoomed = false,
|
|
54
54
|
chatProps,
|
|
55
55
|
}) => {
|
|
56
|
-
|
|
57
56
|
const { t } = useTranslation();
|
|
58
57
|
const [isClient, setIsClient] = useState(false);
|
|
59
58
|
|
|
@@ -118,7 +117,7 @@ const Avatar: React.FC<Props> = ({
|
|
|
118
117
|
|
|
119
118
|
if (
|
|
120
119
|
integrationConfig?.avatar === 'readyplayerme' ||
|
|
121
|
-
integrationConfig?.avatar === 'readyplayerme-full' ||
|
|
120
|
+
integrationConfig?.avatar === 'readyplayerme-full' ||
|
|
122
121
|
integrationConfig?.avatar === 'customrpm'
|
|
123
122
|
) {
|
|
124
123
|
return (
|
|
@@ -145,7 +144,7 @@ const Avatar: React.FC<Props> = ({
|
|
|
145
144
|
style={getAvatarStyle()}
|
|
146
145
|
stopProcessing={stopProcessing}
|
|
147
146
|
resetVisemeQueue={resetVisemeQueue}
|
|
148
|
-
isZoomed={isZoomed}
|
|
147
|
+
isZoomed={isZoomed}
|
|
149
148
|
chatEmission={chatProps?.dialogState?.emission}
|
|
150
149
|
/>
|
|
151
150
|
</ErrorBoundary>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useState, useEffect, useCallback } from 'react';
|
|
2
2
|
import AnimationControlPanel from './components/controls';
|
|
3
|
-
import FullbodyAvatar from './components/fullbodyAvatar';
|
|
3
|
+
import FullbodyAvatar from './components/FullbodyAvatar/fullbodyAvatar';
|
|
4
4
|
import HalfBodyAvatar from './components/halfbodyAvatar';
|
|
5
5
|
|
|
6
6
|
interface Props {
|
|
@@ -87,8 +87,11 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
87
87
|
|
|
88
88
|
// Set the morph target influences for the given emotions
|
|
89
89
|
const setEmotionMorphTargetInfluences = useCallback((action: string) => {
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
if (
|
|
91
|
+
action === 'Loading1' ||
|
|
92
|
+
action === 'Loading2' ||
|
|
93
|
+
action === 'Loading3'
|
|
94
|
+
) {
|
|
92
95
|
return;
|
|
93
96
|
}
|
|
94
97
|
|
|
@@ -99,9 +102,6 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
99
102
|
Tristezza: { Tristezza: 1 },
|
|
100
103
|
Timore: { Timore: 1 },
|
|
101
104
|
};
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
105
|
|
|
106
106
|
// Set all emotions to 0
|
|
107
107
|
const defaultEmotions = Object.keys(emotionMap).reduce((acc, key) => {
|
|
@@ -190,13 +190,6 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
190
190
|
}
|
|
191
191
|
}, [loading]);
|
|
192
192
|
|
|
193
|
-
// useEffect(() => {
|
|
194
|
-
// if (speaking && currentBaseAction.action !== 'Idle1') {
|
|
195
|
-
// const animation = `Idle1`;
|
|
196
|
-
// onBaseActionChange(animation);
|
|
197
|
-
// }
|
|
198
|
-
// }, [speaking]);
|
|
199
|
-
|
|
200
193
|
return (
|
|
201
194
|
<>
|
|
202
195
|
{showControls && (
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { AnimationState, AnimationConfig } from './types';
|
|
2
|
+
import { AnimationAction, AnimationMixer, LoopOnce } from 'three';
|
|
3
|
+
import { DEFAULT_CONFIG } from './constants';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Controller class for managing avatar animations and transitions between states
|
|
7
|
+
*/
|
|
8
|
+
export class AnimationController {
|
|
9
|
+
// Current animation state (LOADING, EMOTION, IDLE)
|
|
10
|
+
private currentState: AnimationState = AnimationState.LOADING;
|
|
11
|
+
// Currently playing animation action
|
|
12
|
+
private currentAction: AnimationAction | null = null;
|
|
13
|
+
// Three.js animation mixer
|
|
14
|
+
private mixer: AnimationMixer;
|
|
15
|
+
// Map of available animation actions
|
|
16
|
+
private actions: Record<string, AnimationAction>;
|
|
17
|
+
// Animation configuration settings
|
|
18
|
+
private config: AnimationConfig;
|
|
19
|
+
// Index of last played idle animation
|
|
20
|
+
private lastIdleIndex: number = -1;
|
|
21
|
+
// Flag to prevent overlapping transitions
|
|
22
|
+
private isTransitioning: boolean = false;
|
|
23
|
+
// Counter for number of times current idle has looped
|
|
24
|
+
private currentIdleLoopCount: number = 0;
|
|
25
|
+
// Maximum number of idle loops before forcing change
|
|
26
|
+
private readonly MAX_IDLE_LOOPS = 5;
|
|
27
|
+
// Timestamp of last animation frame
|
|
28
|
+
private lastAnimationTime: number = 0;
|
|
29
|
+
// Flag to check if chat has already started
|
|
30
|
+
private isChatAlreadyStarted: boolean = false;
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
mixer: AnimationMixer,
|
|
34
|
+
actions: Record<string, AnimationAction>,
|
|
35
|
+
config: AnimationConfig = DEFAULT_CONFIG
|
|
36
|
+
) {
|
|
37
|
+
// console.log('Initializing AnimationController');
|
|
38
|
+
this.mixer = mixer;
|
|
39
|
+
this.actions = actions;
|
|
40
|
+
this.config = config;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Checks if current idle animation has completed a loop
|
|
45
|
+
*/
|
|
46
|
+
private checkForLoop() {
|
|
47
|
+
if (!this.currentAction || this.currentState !== AnimationState.IDLE)
|
|
48
|
+
return;
|
|
49
|
+
|
|
50
|
+
const clip = this.currentAction.getClip();
|
|
51
|
+
const currentTime = this.currentAction.time;
|
|
52
|
+
|
|
53
|
+
// If the current time is less than the last time we recorded,
|
|
54
|
+
// it means the animation has looped
|
|
55
|
+
if (currentTime < this.lastAnimationTime) {
|
|
56
|
+
this.currentIdleLoopCount++;
|
|
57
|
+
// console.log(
|
|
58
|
+
// `[AnimationController] Loop detected! Count: ${this.currentIdleLoopCount}`
|
|
59
|
+
// );
|
|
60
|
+
|
|
61
|
+
// Force idle change after MAX_IDLE_LOOPS
|
|
62
|
+
if (this.currentIdleLoopCount >= this.MAX_IDLE_LOOPS) {
|
|
63
|
+
// console.log(
|
|
64
|
+
// '[AnimationController] Max loops reached, changing idle animation'
|
|
65
|
+
// );
|
|
66
|
+
this.forceIdleChange();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
this.lastAnimationTime = currentTime;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Forces transition to a new idle animation
|
|
75
|
+
*/
|
|
76
|
+
private forceIdleChange() {
|
|
77
|
+
// console.log('[AnimationController] Forcing idle change');
|
|
78
|
+
this.currentIdleLoopCount = 0;
|
|
79
|
+
this.lastAnimationTime = 0;
|
|
80
|
+
this.transitionTo(AnimationState.IDLE);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Selects next random idle animation that differs from last played
|
|
85
|
+
*/
|
|
86
|
+
private getNextIdleAnimation(): AnimationAction {
|
|
87
|
+
let nextIndex;
|
|
88
|
+
do {
|
|
89
|
+
nextIndex = Math.floor(Math.random() * this.config.idleCount) + 1;
|
|
90
|
+
} while (nextIndex === this.lastIdleIndex);
|
|
91
|
+
|
|
92
|
+
// console.log(
|
|
93
|
+
// '[AnimationController] isChatAlreadyStarted',
|
|
94
|
+
// this.isChatAlreadyStarted
|
|
95
|
+
// );
|
|
96
|
+
|
|
97
|
+
if (this.isChatAlreadyStarted && nextIndex === 3) {
|
|
98
|
+
// If chat has already started and the last idle was Idle4, use Idle3 instead
|
|
99
|
+
nextIndex = this.lastIdleIndex !== 4 ? 4 : 2;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// console.log(
|
|
103
|
+
// `[AnimationController] Selected idle animation: Idle${nextIndex}`
|
|
104
|
+
// );
|
|
105
|
+
this.lastIdleIndex = nextIndex;
|
|
106
|
+
const idleAction = this.actions[`Idle${nextIndex}`];
|
|
107
|
+
|
|
108
|
+
if (!idleAction) {
|
|
109
|
+
throw new Error(`Idle animation ${nextIndex} not found`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return idleAction;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Transitions to a new animation state
|
|
117
|
+
*/
|
|
118
|
+
transitionTo(state: AnimationState, emotionName?: string) {
|
|
119
|
+
if (this.isTransitioning) {
|
|
120
|
+
// console.log(
|
|
121
|
+
// '[AnimationController] Transition already in progress, skipping'
|
|
122
|
+
// );
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// console.log(
|
|
127
|
+
// `[AnimationController] Transitioning to ${state}${
|
|
128
|
+
// emotionName ? ` (${emotionName})` : ''
|
|
129
|
+
// }`
|
|
130
|
+
// );
|
|
131
|
+
this.isTransitioning = true;
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
let nextAction: AnimationAction | null = null;
|
|
135
|
+
|
|
136
|
+
switch (state) {
|
|
137
|
+
case AnimationState.LOADING:
|
|
138
|
+
nextAction = this.actions[emotionName || 'Loading1'];
|
|
139
|
+
this.currentIdleLoopCount = 0;
|
|
140
|
+
this.lastAnimationTime = 0;
|
|
141
|
+
break;
|
|
142
|
+
case AnimationState.EMOTION:
|
|
143
|
+
nextAction = this.actions[emotionName || 'Timore1'];
|
|
144
|
+
this.currentIdleLoopCount = 0;
|
|
145
|
+
this.lastAnimationTime = 0;
|
|
146
|
+
break;
|
|
147
|
+
case AnimationState.IDLE:
|
|
148
|
+
nextAction = this.getNextIdleAnimation();
|
|
149
|
+
// Only reset loop count if we're coming from a different idle animation
|
|
150
|
+
if (this.currentState !== AnimationState.IDLE) {
|
|
151
|
+
this.currentIdleLoopCount = 0;
|
|
152
|
+
this.lastAnimationTime = 0;
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!nextAction) {
|
|
158
|
+
throw new Error(`No animation found for state: ${state}`);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Fade out current animation
|
|
162
|
+
if (this.currentAction) {
|
|
163
|
+
this.currentAction.fadeOut(this.config.fadeOutDuration);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Setup next animation
|
|
167
|
+
nextAction.reset().fadeIn(this.config.fadeInDuration).play();
|
|
168
|
+
|
|
169
|
+
// Configure animation properties
|
|
170
|
+
nextAction.timeScale = this.config.timeScale;
|
|
171
|
+
if (state !== AnimationState.IDLE) {
|
|
172
|
+
nextAction.setLoop(LoopOnce, 1);
|
|
173
|
+
nextAction.clampWhenFinished = true;
|
|
174
|
+
} else {
|
|
175
|
+
nextAction.setLoop(Infinity, Infinity);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.currentAction = nextAction;
|
|
179
|
+
this.currentState = state;
|
|
180
|
+
// console.log('[AnimationController] Transition completed successfully');
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error(
|
|
183
|
+
'[AnimationController] Error during animation transition:',
|
|
184
|
+
error
|
|
185
|
+
);
|
|
186
|
+
if (state !== AnimationState.IDLE) {
|
|
187
|
+
this.transitionTo(AnimationState.IDLE);
|
|
188
|
+
}
|
|
189
|
+
} finally {
|
|
190
|
+
this.isTransitioning = false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Updates animation state on each frame
|
|
196
|
+
*/
|
|
197
|
+
update(delta: number) {
|
|
198
|
+
if (!this.currentAction) return;
|
|
199
|
+
|
|
200
|
+
// Check for loop completion in idle animations
|
|
201
|
+
this.checkForLoop();
|
|
202
|
+
|
|
203
|
+
// Check if emotion/loading animation is finished
|
|
204
|
+
if (
|
|
205
|
+
this.currentState !== AnimationState.IDLE &&
|
|
206
|
+
this.currentAction.time >= this.currentAction.getClip().duration * 0.9
|
|
207
|
+
) {
|
|
208
|
+
// console.log(
|
|
209
|
+
// '[AnimationController] Non-idle animation completed, transitioning to idle'
|
|
210
|
+
// );
|
|
211
|
+
this.transitionTo(AnimationState.IDLE);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.mixer.update(delta);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Returns current animation state
|
|
219
|
+
*/
|
|
220
|
+
getCurrentState(): AnimationState {
|
|
221
|
+
return this.currentState;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Returns number of times current idle has looped
|
|
226
|
+
*/
|
|
227
|
+
getLoopCount(): number {
|
|
228
|
+
return this.currentIdleLoopCount;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Updates animation playback speed
|
|
233
|
+
*/
|
|
234
|
+
setTimeScale(timeScale: number) {
|
|
235
|
+
// console.log(`[AnimationController] Setting time scale to ${timeScale}`);
|
|
236
|
+
this.config.timeScale = timeScale;
|
|
237
|
+
if (this.currentAction) {
|
|
238
|
+
this.currentAction.timeScale = timeScale;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
updateIsChatAlreadyStarted(isChatAlreadyStarted: boolean) {
|
|
243
|
+
this.isChatAlreadyStarted = isChatAlreadyStarted;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Returns debug information about current animation state
|
|
248
|
+
*/
|
|
249
|
+
getDebugInfo() {
|
|
250
|
+
return {
|
|
251
|
+
currentState: this.currentState,
|
|
252
|
+
currentIdleIndex: this.lastIdleIndex,
|
|
253
|
+
loopCount: this.currentIdleLoopCount,
|
|
254
|
+
currentTime: this.currentAction?.time || 0,
|
|
255
|
+
lastTime: this.lastAnimationTime,
|
|
256
|
+
isTransitioning: this.isTransitioning,
|
|
257
|
+
isChatAlreadyStarted: this.isChatAlreadyStarted,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SkinnedMesh } from 'three';
|
|
2
|
+
import { MathUtils } from 'three';
|
|
3
|
+
import { EMOTION_SMOOTHING, VISEME_SMOOTHING, BLINK_CONFIG } from './constants';
|
|
4
|
+
|
|
5
|
+
export class MorphTargetController {
|
|
6
|
+
private headMesh: SkinnedMesh;
|
|
7
|
+
private currentEmotionValues: Record<string, number> = {};
|
|
8
|
+
private previousEmotionKeys: Set<string> = new Set();
|
|
9
|
+
|
|
10
|
+
constructor(headMesh: SkinnedMesh) {
|
|
11
|
+
this.headMesh = headMesh;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
updateMorphTargets(
|
|
15
|
+
currentTime: number,
|
|
16
|
+
emotionMorphTargets: Record<string, number>,
|
|
17
|
+
currentViseme: { name: string; weight: number } | null,
|
|
18
|
+
eyeBlink: boolean,
|
|
19
|
+
blinkState: {
|
|
20
|
+
isBlinking: boolean;
|
|
21
|
+
lastBlinkTime: number;
|
|
22
|
+
nextBlinkTime: number;
|
|
23
|
+
blinkStartTime: number;
|
|
24
|
+
}
|
|
25
|
+
) {
|
|
26
|
+
if (
|
|
27
|
+
!this.headMesh.morphTargetDictionary ||
|
|
28
|
+
!this.headMesh.morphTargetInfluences
|
|
29
|
+
) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const blinkValue = this.calculateBlinkValue(
|
|
34
|
+
currentTime,
|
|
35
|
+
blinkState,
|
|
36
|
+
eyeBlink
|
|
37
|
+
);
|
|
38
|
+
const currentEmotionKeys = new Set(Object.keys(emotionMorphTargets));
|
|
39
|
+
|
|
40
|
+
Object.entries(this.headMesh.morphTargetDictionary).forEach(
|
|
41
|
+
([key, index]) => {
|
|
42
|
+
if (typeof index !== 'number') return;
|
|
43
|
+
|
|
44
|
+
let targetValue = 0;
|
|
45
|
+
|
|
46
|
+
// Handle emotion morphs
|
|
47
|
+
if (currentEmotionKeys.has(key)) {
|
|
48
|
+
const targetEmotionValue = emotionMorphTargets[key];
|
|
49
|
+
const currentEmotionValue = this.currentEmotionValues[key] || 0;
|
|
50
|
+
const newEmotionValue = MathUtils.lerp(
|
|
51
|
+
currentEmotionValue,
|
|
52
|
+
targetEmotionValue * 2.5,
|
|
53
|
+
EMOTION_SMOOTHING
|
|
54
|
+
);
|
|
55
|
+
this.currentEmotionValues[key] = newEmotionValue;
|
|
56
|
+
targetValue += newEmotionValue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Handle viseme
|
|
60
|
+
if (currentViseme && key === currentViseme.name) {
|
|
61
|
+
targetValue += currentViseme.weight;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Handle blinking
|
|
65
|
+
if (key === 'eyesClosed' && eyeBlink) {
|
|
66
|
+
targetValue += blinkValue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Apply final value
|
|
70
|
+
targetValue = MathUtils.clamp(targetValue, 0, 1);
|
|
71
|
+
if (this.headMesh.morphTargetInfluences) {
|
|
72
|
+
this.headMesh.morphTargetInfluences[index] = MathUtils.lerp(
|
|
73
|
+
this.headMesh.morphTargetInfluences[index] || 0,
|
|
74
|
+
targetValue,
|
|
75
|
+
VISEME_SMOOTHING
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
this.previousEmotionKeys = currentEmotionKeys;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private calculateBlinkValue(
|
|
85
|
+
currentTime: number,
|
|
86
|
+
blinkState: {
|
|
87
|
+
isBlinking: boolean;
|
|
88
|
+
lastBlinkTime: number;
|
|
89
|
+
nextBlinkTime: number;
|
|
90
|
+
blinkStartTime: number;
|
|
91
|
+
},
|
|
92
|
+
eyeBlink: boolean
|
|
93
|
+
): number {
|
|
94
|
+
if (!eyeBlink) return 0;
|
|
95
|
+
|
|
96
|
+
let blinkValue = 0;
|
|
97
|
+
|
|
98
|
+
if (currentTime >= blinkState.nextBlinkTime && !blinkState.isBlinking) {
|
|
99
|
+
blinkState.isBlinking = true;
|
|
100
|
+
blinkState.blinkStartTime = currentTime;
|
|
101
|
+
blinkState.lastBlinkTime = currentTime;
|
|
102
|
+
blinkState.nextBlinkTime =
|
|
103
|
+
currentTime +
|
|
104
|
+
Math.random() * (BLINK_CONFIG.maxInterval - BLINK_CONFIG.minInterval) +
|
|
105
|
+
BLINK_CONFIG.minInterval;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (blinkState.isBlinking) {
|
|
109
|
+
const blinkProgress =
|
|
110
|
+
(currentTime - blinkState.blinkStartTime) / BLINK_CONFIG.blinkDuration;
|
|
111
|
+
if (blinkProgress <= 0.5) {
|
|
112
|
+
blinkValue = blinkProgress * 2;
|
|
113
|
+
} else if (blinkProgress <= 1) {
|
|
114
|
+
blinkValue = 2 - blinkProgress * 2;
|
|
115
|
+
} else {
|
|
116
|
+
blinkState.isBlinking = false;
|
|
117
|
+
blinkValue = 0;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return blinkValue;
|
|
122
|
+
}
|
|
123
|
+
}
|
package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Vector3, Euler } from 'three';
|
|
2
|
+
import { AnimationConfig } from './types';
|
|
3
|
+
|
|
4
|
+
export const AVATAR_POSITION = new Vector3(0, -1, 0);
|
|
5
|
+
export const AVATAR_ROTATION = new Euler(0.175, 0, 0);
|
|
6
|
+
export const AVATAR_POSITION_ZOOMED = new Vector3(0, -1.45, 0);
|
|
7
|
+
|
|
8
|
+
export const ANIMATION_URLS = {
|
|
9
|
+
MALE: 'https://assets.memori.ai/api/v2/asset/2c5e88a4-cf62-408b-9ef0-518b099dfcb2.glb',
|
|
10
|
+
FEMALE:
|
|
11
|
+
'https://assets.memori.ai/api/v2/asset/2adc934b-24b2-45bd-94ad-ffec58d3cb32.glb',
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const BLINK_CONFIG = {
|
|
15
|
+
minInterval: 1000,
|
|
16
|
+
maxInterval: 5000,
|
|
17
|
+
blinkDuration: 150,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const DEFAULT_CONFIG: AnimationConfig = {
|
|
21
|
+
fadeInDuration: 0.8,
|
|
22
|
+
fadeOutDuration: 0.8,
|
|
23
|
+
idleCount: 5,
|
|
24
|
+
timeScale: 1.0,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const EMOTION_SMOOTHING = 0.3;
|
|
28
|
+
export const VISEME_SMOOTHING = 0.5;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import React, { useEffect, useRef, useMemo, useCallback } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Vector3,
|
|
4
|
+
Euler,
|
|
5
|
+
AnimationMixer,
|
|
6
|
+
SkinnedMesh,
|
|
7
|
+
Object3D,
|
|
8
|
+
MathUtils,
|
|
9
|
+
AnimationAction,
|
|
10
|
+
LoopOnce,
|
|
11
|
+
} from 'three';
|
|
12
|
+
import { useAnimations, useGLTF } from '@react-three/drei';
|
|
13
|
+
import { useFrame } from '@react-three/fiber';
|
|
14
|
+
import { AnimationState, FullbodyAvatarProps } from './types';
|
|
15
|
+
import { AnimationController } from './AnimationController';
|
|
16
|
+
import { MorphTargetController } from './MorhTargetController';
|
|
17
|
+
import {
|
|
18
|
+
AVATAR_POSITION,
|
|
19
|
+
AVATAR_ROTATION,
|
|
20
|
+
AVATAR_POSITION_ZOOMED,
|
|
21
|
+
ANIMATION_URLS,
|
|
22
|
+
DEFAULT_CONFIG,
|
|
23
|
+
} from './constants';
|
|
24
|
+
|
|
25
|
+
export default function FullbodyAvatar({
|
|
26
|
+
url,
|
|
27
|
+
sex,
|
|
28
|
+
currentBaseAction,
|
|
29
|
+
timeScale,
|
|
30
|
+
isZoomed,
|
|
31
|
+
eyeBlink,
|
|
32
|
+
updateCurrentViseme,
|
|
33
|
+
setMorphTargetDictionary,
|
|
34
|
+
setMorphTargetInfluences,
|
|
35
|
+
emotionMorphTargets,
|
|
36
|
+
}: FullbodyAvatarProps) {
|
|
37
|
+
const { scene } = useGLTF(url);
|
|
38
|
+
const { animations } = useGLTF(ANIMATION_URLS[sex]);
|
|
39
|
+
const { actions } = useAnimations(animations, scene);
|
|
40
|
+
|
|
41
|
+
const animationControllerRef = useRef<AnimationController>();
|
|
42
|
+
const morphTargetControllerRef = useRef<MorphTargetController>();
|
|
43
|
+
const blinkStateRef = useRef({
|
|
44
|
+
isBlinking: false,
|
|
45
|
+
lastBlinkTime: 0,
|
|
46
|
+
nextBlinkTime: 0,
|
|
47
|
+
blinkStartTime: 0,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Find head mesh
|
|
51
|
+
const headMesh = useMemo(() => {
|
|
52
|
+
let foundMesh: SkinnedMesh | undefined;
|
|
53
|
+
scene.traverse((object: Object3D) => {
|
|
54
|
+
if (
|
|
55
|
+
object instanceof SkinnedMesh &&
|
|
56
|
+
(object.name === 'GBNL__Head' || object.name === 'Wolf3D_Avatar')
|
|
57
|
+
) {
|
|
58
|
+
foundMesh = object;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return foundMesh;
|
|
62
|
+
}, [scene]);
|
|
63
|
+
|
|
64
|
+
// Initialize controllers
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
if (!actions || !headMesh) return;
|
|
67
|
+
|
|
68
|
+
const mixer = new AnimationMixer(scene);
|
|
69
|
+
animationControllerRef.current = new AnimationController(
|
|
70
|
+
mixer,
|
|
71
|
+
actions as Record<string, AnimationAction>,
|
|
72
|
+
{ ...DEFAULT_CONFIG }
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
morphTargetControllerRef.current = new MorphTargetController(headMesh);
|
|
76
|
+
|
|
77
|
+
// Initialize morph target dictionary and influences
|
|
78
|
+
if (headMesh.morphTargetDictionary && headMesh.morphTargetInfluences) {
|
|
79
|
+
setMorphTargetDictionary(headMesh.morphTargetDictionary);
|
|
80
|
+
const initialInfluences = Object.keys(
|
|
81
|
+
headMesh.morphTargetDictionary
|
|
82
|
+
).reduce((acc, key) => ({ ...acc, [key]: 0 }), {});
|
|
83
|
+
setMorphTargetInfluences(initialInfluences);
|
|
84
|
+
}
|
|
85
|
+
}, [
|
|
86
|
+
actions,
|
|
87
|
+
headMesh,
|
|
88
|
+
scene,
|
|
89
|
+
setMorphTargetDictionary,
|
|
90
|
+
setMorphTargetInfluences,
|
|
91
|
+
timeScale,
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
// Handle animation state changes
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (!animationControllerRef.current) return;
|
|
97
|
+
|
|
98
|
+
if (currentBaseAction.action.startsWith('Loading')) {
|
|
99
|
+
animationControllerRef.current.transitionTo(
|
|
100
|
+
AnimationState.LOADING,
|
|
101
|
+
currentBaseAction.action
|
|
102
|
+
);
|
|
103
|
+
} else if (currentBaseAction.action.startsWith('Idle')) {
|
|
104
|
+
animationControllerRef.current.transitionTo(AnimationState.IDLE);
|
|
105
|
+
} else {
|
|
106
|
+
animationControllerRef.current.updateIsChatAlreadyStarted(true);
|
|
107
|
+
animationControllerRef.current.transitionTo(
|
|
108
|
+
AnimationState.EMOTION,
|
|
109
|
+
currentBaseAction.action
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}, [currentBaseAction]);
|
|
113
|
+
|
|
114
|
+
// Update timeScale when it changes
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
animationControllerRef.current?.setTimeScale(timeScale);
|
|
117
|
+
}, [timeScale]);
|
|
118
|
+
|
|
119
|
+
// Animation update loop
|
|
120
|
+
useFrame(state => {
|
|
121
|
+
const currentTime = state.clock.elapsedTime * 1000;
|
|
122
|
+
|
|
123
|
+
// Update animations
|
|
124
|
+
animationControllerRef.current?.update(state.clock.getDelta());
|
|
125
|
+
|
|
126
|
+
// Update morph targets
|
|
127
|
+
if (morphTargetControllerRef.current) {
|
|
128
|
+
const currentViseme = updateCurrentViseme(currentTime / 1000);
|
|
129
|
+
morphTargetControllerRef.current.updateMorphTargets(
|
|
130
|
+
currentTime,
|
|
131
|
+
emotionMorphTargets,
|
|
132
|
+
currentViseme,
|
|
133
|
+
eyeBlink || false,
|
|
134
|
+
blinkStateRef.current
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<group
|
|
141
|
+
position={isZoomed ? AVATAR_POSITION_ZOOMED : AVATAR_POSITION}
|
|
142
|
+
rotation={AVATAR_ROTATION}
|
|
143
|
+
>
|
|
144
|
+
<primitive object={scene} />
|
|
145
|
+
</group>
|
|
146
|
+
);
|
|
147
|
+
}
|