@memori.ai/memori-react 7.13.4 → 7.14.0
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 +15 -0
- package/dist/components/Avatar/Avatar.css +2 -2
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +15 -7
- package/dist/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +7 -4
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.d.ts +38 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js +181 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarPositionController.d.ts +19 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarPositionController.js +60 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarPositionController.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/{FullbodyAvatar/MorhTargetController.js → controllers/MorphTargetController.js} +6 -4
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js.map +1 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +3 -3
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/Avatar.css +2 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js +15 -7
- package/esm/components/Avatar/AvatarView/AvatarComponent/avatarComponent.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js +6 -3
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.js.map +1 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.d.ts +38 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js +177 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AnimationController.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarPositionController.d.ts +19 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarPositionController.js +56 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/AvatarPositionController.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/{FullbodyAvatar/MorhTargetController.js → controllers/MorphTargetController.js} +6 -4
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/controllers/MorphTargetController.js.map +1 -0
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js +2 -2
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Avatar/Avatar.css +2 -2
- package/src/components/Avatar/AvatarView/AvatarComponent/avatarComponent.tsx +115 -67
- package/src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/fullbodyAvatar.tsx +5 -3
- package/src/components/Avatar/AvatarView/AvatarComponent/components/{FullbodyAvatar → controllers}/AnimationController.ts +52 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/components/{PositionController.ts → controllers/AvatarPositionController.ts} +1 -1
- package/src/components/Avatar/AvatarView/AvatarComponent/components/{MorphTargetController.ts → controllers/MorphTargetController.ts} +1 -2
- package/src/components/Avatar/AvatarView/AvatarComponent/components/halfbodyAvatar.tsx +2 -2
- package/src/index.stories.tsx +16 -0
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.js.map +0 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.d.ts +0 -17
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js +0 -25
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js.map +0 -1
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +0 -26
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +0 -166
- package/dist/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +0 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.js.map +0 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.d.ts +0 -17
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js +0 -22
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js.map +0 -1
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.d.ts +0 -26
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js +0 -163
- package/esm/components/Avatar/AvatarView/AvatarComponent/components/fullbodyAvatar.js.map +0 -1
- /package/dist/components/Avatar/AvatarView/AvatarComponent/components/{FullbodyAvatar/MorhTargetController.d.ts → controllers/MorphTargetController.d.ts} +0 -0
- /package/esm/components/Avatar/AvatarView/AvatarComponent/components/{FullbodyAvatar/MorhTargetController.d.ts → controllers/MorphTargetController.d.ts} +0 -0
|
@@ -25,7 +25,9 @@ interface Props {
|
|
|
25
25
|
avatarDepth?: number;
|
|
26
26
|
stopProcessing: () => void;
|
|
27
27
|
resetVisemeQueue: () => void;
|
|
28
|
-
updateCurrentViseme: (
|
|
28
|
+
updateCurrentViseme: (
|
|
29
|
+
currentTime: number
|
|
30
|
+
) => { name: string; weight: number } | null;
|
|
29
31
|
setCameraZ: (value: number) => void;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -55,9 +57,15 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
55
57
|
action: animation || 'Idle1',
|
|
56
58
|
weight: 1,
|
|
57
59
|
});
|
|
58
|
-
const [morphTargetInfluences, setMorphTargetInfluences] = useState<
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
const [morphTargetInfluences, setMorphTargetInfluences] = useState<
|
|
61
|
+
Record<string, number>
|
|
62
|
+
>({});
|
|
63
|
+
const [morphTargetDictionary, setMorphTargetDictionary] = useState<
|
|
64
|
+
Record<string, number>
|
|
65
|
+
>({});
|
|
66
|
+
const [emotionMorphTargets, setEmotionMorphTargets] = useState<
|
|
67
|
+
Record<string, number>
|
|
68
|
+
>({});
|
|
61
69
|
const [isRPM, setIsRPM] = useState(false);
|
|
62
70
|
const [timeScale, setTimeScale] = useState(0.8);
|
|
63
71
|
|
|
@@ -71,73 +79,92 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
71
79
|
};
|
|
72
80
|
|
|
73
81
|
// Helper function to get default emotion state (all set to 0)
|
|
74
|
-
const getDefaultEmotions = () =>
|
|
75
|
-
Object.keys(emotionMap).reduce((acc, key) => ({...acc, [key]: 0}), {});
|
|
82
|
+
const getDefaultEmotions = () =>
|
|
83
|
+
Object.keys(emotionMap).reduce((acc, key) => ({ ...acc, [key]: 0 }), {});
|
|
76
84
|
|
|
77
85
|
// Handlers for different blend shape types
|
|
78
|
-
const handleRPMBlendShape = useCallback(
|
|
79
|
-
|
|
80
|
-
|
|
86
|
+
const handleRPMBlendShape = useCallback(
|
|
87
|
+
(outputContent: string) =>
|
|
88
|
+
MAPPING_BLEND_SHAPE_TO_EMOTION_RPM[
|
|
89
|
+
outputContent as keyof typeof MAPPING_BLEND_SHAPE_TO_EMOTION_RPM
|
|
90
|
+
],
|
|
91
|
+
[]
|
|
92
|
+
);
|
|
81
93
|
|
|
82
|
-
const handleCustomGLBBlendShape = useCallback(
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
const handleCustomGLBBlendShape = useCallback(
|
|
95
|
+
(outputContent: string) =>
|
|
96
|
+
MAPPING_BLEND_SHAPE_TO_EMOTION_CUSTOM_GLB[
|
|
97
|
+
outputContent as keyof typeof MAPPING_BLEND_SHAPE_TO_EMOTION_CUSTOM_GLB
|
|
98
|
+
],
|
|
99
|
+
[]
|
|
100
|
+
);
|
|
85
101
|
|
|
86
102
|
// Handler for setting emotion morph target influences, used for RPM and GLB blend shapes
|
|
87
|
-
const setEmotionMorphTargetInfluences = useCallback(
|
|
88
|
-
|
|
103
|
+
const setEmotionMorphTargetInfluences = useCallback(
|
|
104
|
+
(action: string, outputContent: string) => {
|
|
105
|
+
if (action.startsWith('Loading')) return;
|
|
89
106
|
|
|
90
|
-
|
|
107
|
+
const defaultEmotions = getDefaultEmotions();
|
|
91
108
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
109
|
+
// If output content is default, set default emotions
|
|
110
|
+
if (outputContent === 'default') {
|
|
111
|
+
setEmotionMorphTargets(defaultEmotions);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
97
114
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
// If RPM, convert emotion to blend shape
|
|
116
|
+
/*from the chat output, we get the emotion and we convert it to the blend shapes
|
|
117
|
+
* we map the emotion to the blend shape, example:
|
|
118
|
+
* Anger -> {browDownLeft: 1, browDownRight: 0}
|
|
119
|
+
* Joy -> {browUpLeft: 1, browUpRight: 0}
|
|
120
|
+
* Surprise -> {browUpLeft: 1, browUpRight: 0}
|
|
121
|
+
* Sadness -> {browDownLeft: 1, browDownRight: 0}
|
|
122
|
+
* Fear -> {browDownLeft: 1, browDownRight: 0}
|
|
123
|
+
*/
|
|
124
|
+
if (isRPM) {
|
|
125
|
+
const emotion = handleRPMBlendShape(outputContent);
|
|
126
|
+
setEmotionMorphTargets(_ => ({ ...defaultEmotions, ...emotion }));
|
|
127
|
+
} else {
|
|
128
|
+
// If GLB, convert italian emotions to english ones
|
|
129
|
+
const emotion = handleCustomGLBBlendShape(outputContent);
|
|
130
|
+
const emotionValues =
|
|
131
|
+
emotion === 'default' ? defaultEmotions : emotionMap[emotion];
|
|
132
|
+
setEmotionMorphTargets(_ => ({ ...defaultEmotions, ...emotionValues }));
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
[isRPM, handleRPMBlendShape, handleCustomGLBBlendShape]
|
|
136
|
+
);
|
|
117
137
|
|
|
118
138
|
// Callback handlers for various avatar state changes
|
|
119
|
-
const onBaseActionChange = useCallback(
|
|
139
|
+
const onBaseActionChange = useCallback(
|
|
140
|
+
(action: string, outputContent: string) => {
|
|
141
|
+
// Set emotion morph target influences
|
|
142
|
+
setEmotionMorphTargetInfluences(action, outputContent);
|
|
120
143
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}, [setEmotionMorphTargetInfluences]);
|
|
144
|
+
// Set current base action
|
|
145
|
+
setCurrentBaseAction({ action, weight: 1 });
|
|
146
|
+
},
|
|
147
|
+
[setEmotionMorphTargetInfluences]
|
|
148
|
+
);
|
|
127
149
|
|
|
128
|
-
const onMorphTargetInfluencesChange = useCallback(
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
150
|
+
const onMorphTargetInfluencesChange = useCallback(
|
|
151
|
+
(influences: Record<string, number>) => {
|
|
152
|
+
// Set morph target influences
|
|
153
|
+
setMorphTargetInfluences(prev => ({ ...prev, ...influences }));
|
|
154
|
+
},
|
|
155
|
+
[]
|
|
156
|
+
);
|
|
132
157
|
|
|
133
|
-
const onMorphTargetDictionaryChange = useCallback(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
const onMorphTargetDictionaryChange = useCallback(
|
|
159
|
+
(dictionary: Record<string, number>) => {
|
|
160
|
+
// Set morph target dictionary
|
|
161
|
+
setMorphTargetDictionary(dictionary);
|
|
162
|
+
},
|
|
163
|
+
[]
|
|
164
|
+
);
|
|
137
165
|
|
|
138
166
|
// Effect to handle animation changes based on loading state and chat emissions
|
|
139
167
|
useEffect(() => {
|
|
140
|
-
|
|
141
168
|
// If loading, set a random loading animation
|
|
142
169
|
if (loading) {
|
|
143
170
|
const randomNumber = Math.floor(Math.random() * 3) + 1;
|
|
@@ -145,16 +172,40 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
145
172
|
return;
|
|
146
173
|
}
|
|
147
174
|
|
|
148
|
-
//
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
175
|
+
// Check if chat emission contains animation control
|
|
176
|
+
const hasOutputTagEmotion = chatEmission?.includes(
|
|
177
|
+
'<output class="memori-emotion">'
|
|
178
|
+
);
|
|
179
|
+
const outputContentEmotion = hasOutputTagEmotion
|
|
180
|
+
? chatEmission
|
|
181
|
+
?.split('<output class="memori-emotion">')[1]
|
|
182
|
+
?.split('</output>')[0]
|
|
183
|
+
?.trim()
|
|
184
|
+
: null;
|
|
185
|
+
|
|
186
|
+
// Check if chat emission contains animation sequence
|
|
187
|
+
const hasOutputTagSequence = chatEmission?.includes(
|
|
188
|
+
'<output class="animation-sequence">'
|
|
189
|
+
);
|
|
190
|
+
const outputContentSequence = hasOutputTagSequence
|
|
191
|
+
? chatEmission
|
|
192
|
+
?.split('<output class="animation-sequence">')[1]
|
|
193
|
+
?.split('</output>')[0]
|
|
194
|
+
?.trim()
|
|
152
195
|
: null;
|
|
153
196
|
|
|
154
|
-
|
|
155
|
-
|
|
197
|
+
if (outputContentSequence && outputContentSequence.includes('->')) {
|
|
198
|
+
// It's a sequence
|
|
199
|
+
onBaseActionChange(outputContentSequence, outputContentSequence);
|
|
200
|
+
} else if (outputContentEmotion) {
|
|
201
|
+
|
|
202
|
+
console.log('[AvatarView] outputContentEmotion:', outputContentEmotion);
|
|
203
|
+
// It's an emotion
|
|
156
204
|
const randomNumber = Math.floor(Math.random() * 3) + 1;
|
|
157
|
-
onBaseActionChange(
|
|
205
|
+
onBaseActionChange(
|
|
206
|
+
`${outputContentEmotion}${randomNumber}`,
|
|
207
|
+
outputContentEmotion
|
|
208
|
+
);
|
|
158
209
|
} else {
|
|
159
210
|
const randomNumber = Math.floor(Math.random() * 5) + 1;
|
|
160
211
|
onBaseActionChange(`Idle${randomNumber === 3 ? 4 : randomNumber}`, '');
|
|
@@ -187,12 +238,9 @@ export const AvatarView: React.FC<Props & { halfBody: boolean }> = ({
|
|
|
187
238
|
modifyTimeScale={setTimeScale}
|
|
188
239
|
/>
|
|
189
240
|
)}
|
|
190
|
-
|
|
241
|
+
|
|
191
242
|
{halfBody ? (
|
|
192
|
-
<HalfBodyAvatar
|
|
193
|
-
{...commonAvatarProps}
|
|
194
|
-
headMovement={headMovement}
|
|
195
|
-
/>
|
|
243
|
+
<HalfBodyAvatar {...commonAvatarProps} headMovement={headMovement} />
|
|
196
244
|
) : (
|
|
197
245
|
<FullbodyAvatar
|
|
198
246
|
{...commonAvatarProps}
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
import { useAnimations, useGLTF } from '@react-three/drei';
|
|
9
9
|
import { useFrame } from '@react-three/fiber';
|
|
10
10
|
import { AnimationState, FullbodyAvatarProps } from './types';
|
|
11
|
-
import { AnimationController } from '
|
|
12
|
-
import { MorphTargetController } from '../MorphTargetController';
|
|
13
|
-
import { AvatarPositionController } from '../
|
|
11
|
+
import { AnimationController } from '../controllers/AnimationController';
|
|
12
|
+
import { MorphTargetController } from '../controllers/MorphTargetController';
|
|
13
|
+
import { AvatarPositionController } from '../controllers/AvatarPositionController';
|
|
14
14
|
import {
|
|
15
15
|
AVATAR_POSITION,
|
|
16
16
|
AVATAR_ROTATION,
|
|
@@ -152,6 +152,8 @@ export function FullbodyAvatar({
|
|
|
152
152
|
AnimationState.LOADING,
|
|
153
153
|
currentBaseAction.action
|
|
154
154
|
);
|
|
155
|
+
} else if (currentBaseAction.action.includes('->')) {
|
|
156
|
+
animationControllerRef.current.playSequence(currentBaseAction.action);
|
|
155
157
|
} else if (currentBaseAction.action.startsWith('Idle')) {
|
|
156
158
|
animationControllerRef.current.transitionTo(AnimationState.IDLE);
|
|
157
159
|
} else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnimationState, AnimationConfig } from '
|
|
1
|
+
import { AnimationState, AnimationConfig } from '../FullbodyAvatar/types';
|
|
2
2
|
import { AnimationAction, AnimationMixer, LoopOnce } from 'three';
|
|
3
3
|
import { DEFAULT_CONFIG, MAX_IDLE_LOOPS_DEFAULT } from '../../constants';
|
|
4
4
|
|
|
@@ -28,6 +28,10 @@ export class AnimationController {
|
|
|
28
28
|
private lastAnimationTime: number = 0;
|
|
29
29
|
// Flag to check if chat has already started
|
|
30
30
|
private isChatAlreadyStarted: boolean = false;
|
|
31
|
+
// Sequence of animations
|
|
32
|
+
private sequence: string[] | null = null;
|
|
33
|
+
// Index of current animation in sequence
|
|
34
|
+
private sequenceIndex: number = 0;
|
|
31
35
|
|
|
32
36
|
constructor(
|
|
33
37
|
mixer: AnimationMixer,
|
|
@@ -108,6 +112,33 @@ export class AnimationController {
|
|
|
108
112
|
return idleAction;
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Plays a sequence of animations
|
|
117
|
+
*/
|
|
118
|
+
playSequence(sequenceString: string) {
|
|
119
|
+
const animations = sequenceString.split('->').map(anim => anim.trim());
|
|
120
|
+
console.log('[AnimationController] playSequence:', animations);
|
|
121
|
+
|
|
122
|
+
this.sequence = animations;
|
|
123
|
+
this.sequenceIndex = 0;
|
|
124
|
+
|
|
125
|
+
const firstAnim = this.parseAnimationName(animations[0]);
|
|
126
|
+
this.transitionTo(AnimationState.EMOTION, firstAnim);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Animation Name Parsing
|
|
130
|
+
private parseAnimationName(animation: string): string {
|
|
131
|
+
const randomMatch = animation.match(/(\w+)\[(\d+),(\d+)\]/);
|
|
132
|
+
if (randomMatch) {
|
|
133
|
+
const [_, base, min, max] = randomMatch;
|
|
134
|
+
const random =
|
|
135
|
+
Math.floor(Math.random() * (Number(max) - Number(min) + 1)) +
|
|
136
|
+
Number(min);
|
|
137
|
+
return `${base}${random}`;
|
|
138
|
+
}
|
|
139
|
+
return animation;
|
|
140
|
+
}
|
|
141
|
+
|
|
111
142
|
/**
|
|
112
143
|
* Transitions to a new animation state
|
|
113
144
|
*/
|
|
@@ -197,6 +228,26 @@ export class AnimationController {
|
|
|
197
228
|
// Check for loop completion in idle animations
|
|
198
229
|
this.checkForLoop();
|
|
199
230
|
|
|
231
|
+
// Sequence progression,
|
|
232
|
+
// If sequence is playing, transition to the next animation in the sequence
|
|
233
|
+
// If sequence is finished, transition to idle
|
|
234
|
+
if (
|
|
235
|
+
this.sequence &&
|
|
236
|
+
this.currentState === AnimationState.EMOTION &&
|
|
237
|
+
this.currentAction.time >= this.currentAction.getClip().duration * 0.9
|
|
238
|
+
) {
|
|
239
|
+
this.sequenceIndex++;
|
|
240
|
+
|
|
241
|
+
if (this.sequenceIndex < this.sequence.length) {
|
|
242
|
+
const nextAnim = this.parseAnimationName(this.sequence[this.sequenceIndex]);
|
|
243
|
+
this.transitionTo(AnimationState.EMOTION, nextAnim);
|
|
244
|
+
} else {
|
|
245
|
+
this.sequence = null;
|
|
246
|
+
this.sequenceIndex = 0;
|
|
247
|
+
this.transitionTo(AnimationState.IDLE);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
200
251
|
// Check if emotion/loading animation is finished
|
|
201
252
|
if (
|
|
202
253
|
this.currentState !== AnimationState.IDLE &&
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Vector3, MathUtils } from 'three';
|
|
2
|
-
import { AVATAR_POSITION, AVATAR_POSITION_ZOOMED } from '
|
|
2
|
+
import { AVATAR_POSITION, AVATAR_POSITION_ZOOMED } from '../../constants';
|
|
3
3
|
|
|
4
4
|
export class AvatarPositionController {
|
|
5
5
|
private currentScale: Vector3;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SkinnedMesh } from 'three';
|
|
2
2
|
import { MathUtils } from 'three';
|
|
3
|
-
import { EMOTION_SMOOTHING, VISEME_SMOOTHING, BLINK_CONFIG } from '
|
|
3
|
+
import { EMOTION_SMOOTHING, VISEME_SMOOTHING, BLINK_CONFIG } from '../../constants';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Controller class for handling morph target animations including emotions, visemes and blinking
|
|
@@ -62,7 +62,6 @@ export class MorphTargetController {
|
|
|
62
62
|
targetEmotionValue * 3, // Amplify emotion by 3x
|
|
63
63
|
EMOTION_SMOOTHING
|
|
64
64
|
);
|
|
65
|
-
console.log(`[MorphTargetController] Emotion ${key}: current=${currentEmotionValue}, target=${targetEmotionValue}, new=${newEmotionValue}`);
|
|
66
65
|
this.currentEmotionValues[key] = newEmotionValue;
|
|
67
66
|
targetValue += newEmotionValue;
|
|
68
67
|
}
|
|
@@ -3,8 +3,8 @@ import { Object3D, SkinnedMesh } from 'three';
|
|
|
3
3
|
import { useGLTF } from '@react-three/drei';
|
|
4
4
|
import { useGraph, useFrame, useThree } from '@react-three/fiber';
|
|
5
5
|
import { correctMaterials, isSkinnedMesh } from '../../../../../helpers/utils';
|
|
6
|
-
import { MorphTargetController } from './MorphTargetController';
|
|
7
|
-
import { AvatarPositionController } from './
|
|
6
|
+
import { MorphTargetController } from './controllers/MorphTargetController';
|
|
7
|
+
import { AvatarPositionController } from './controllers/AvatarPositionController';
|
|
8
8
|
import {
|
|
9
9
|
AVATAR_POSITION,
|
|
10
10
|
SCALE_LERP_FACTOR,
|
package/src/index.stories.tsx
CHANGED
|
@@ -166,6 +166,22 @@ GiovannaGLBProva.args = {
|
|
|
166
166
|
layout: 'ZOOMED_FULL_BODY',
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
+
export const MoodChefAssistant = Template.bind({});
|
|
170
|
+
MoodChefAssistant.args = {
|
|
171
|
+
memoriName: 'Mood Chef Assistant',
|
|
172
|
+
ownerUserName: 'andrea.patini3',
|
|
173
|
+
memoriID: 'fb4f9251-e7ec-4002-b0e5-ffa6e75b2fd8',
|
|
174
|
+
ownerUserID: '58770358-a5db-4b49-b3a4-734fc468e745',
|
|
175
|
+
tenantID: 'aisuru-staging.aclambda.online',
|
|
176
|
+
engineURL: 'https://engine-staging-tmp.memori.ai',
|
|
177
|
+
apiURL: 'https://backend-staging.memori.ai',
|
|
178
|
+
baseURL: 'https://aisuru-staging.aclambda.online',
|
|
179
|
+
uiLang: 'EN',
|
|
180
|
+
spokenLang: 'IT',
|
|
181
|
+
layout: 'ZOOMED_FULL_BODY',
|
|
182
|
+
integrationID: '6e289cc1-df99-4879-8a3a-fe10baea7eac',
|
|
183
|
+
};
|
|
184
|
+
|
|
169
185
|
export const GiovannaProvaWithPreviousSession = Template.bind({});
|
|
170
186
|
GiovannaProvaWithPreviousSession.args = {
|
|
171
187
|
memoriName: 'Giovanna Test',
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"MorhTargetController.js","sourceRoot":"","sources":["../../../../../../../src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/MorhTargetController.ts"],"names":[],"mappings":"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"}
|
package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { Vector3, Euler } from 'three';
|
|
2
|
-
import { AnimationConfig } from './types';
|
|
3
|
-
export declare const AVATAR_POSITION: Vector3;
|
|
4
|
-
export declare const AVATAR_ROTATION: Euler;
|
|
5
|
-
export declare const AVATAR_POSITION_ZOOMED: Vector3;
|
|
6
|
-
export declare const ANIMATION_URLS: {
|
|
7
|
-
MALE: string;
|
|
8
|
-
FEMALE: string;
|
|
9
|
-
};
|
|
10
|
-
export declare const BLINK_CONFIG: {
|
|
11
|
-
minInterval: number;
|
|
12
|
-
maxInterval: number;
|
|
13
|
-
blinkDuration: number;
|
|
14
|
-
};
|
|
15
|
-
export declare const DEFAULT_CONFIG: AnimationConfig;
|
|
16
|
-
export declare const EMOTION_SMOOTHING = 0.3;
|
|
17
|
-
export declare const VISEME_SMOOTHING = 0.5;
|
package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.VISEME_SMOOTHING = exports.EMOTION_SMOOTHING = exports.DEFAULT_CONFIG = exports.BLINK_CONFIG = exports.ANIMATION_URLS = exports.AVATAR_POSITION_ZOOMED = exports.AVATAR_ROTATION = exports.AVATAR_POSITION = void 0;
|
|
4
|
-
const three_1 = require("three");
|
|
5
|
-
exports.AVATAR_POSITION = new three_1.Vector3(0, -1, 0);
|
|
6
|
-
exports.AVATAR_ROTATION = new three_1.Euler(0.175, 0, 0);
|
|
7
|
-
exports.AVATAR_POSITION_ZOOMED = new three_1.Vector3(0, -1.45, 0);
|
|
8
|
-
exports.ANIMATION_URLS = {
|
|
9
|
-
MALE: 'https://assets.memori.ai/api/v2/asset/2c5e88a4-cf62-408b-9ef0-518b099dfcb2.glb',
|
|
10
|
-
FEMALE: 'https://assets.memori.ai/api/v2/asset/2adc934b-24b2-45bd-94ad-ffec58d3cb32.glb',
|
|
11
|
-
};
|
|
12
|
-
exports.BLINK_CONFIG = {
|
|
13
|
-
minInterval: 1000,
|
|
14
|
-
maxInterval: 5000,
|
|
15
|
-
blinkDuration: 150,
|
|
16
|
-
};
|
|
17
|
-
exports.DEFAULT_CONFIG = {
|
|
18
|
-
fadeInDuration: 0.8,
|
|
19
|
-
fadeOutDuration: 0.8,
|
|
20
|
-
idleCount: 5,
|
|
21
|
-
timeScale: 1.0,
|
|
22
|
-
};
|
|
23
|
-
exports.EMOTION_SMOOTHING = 0.3;
|
|
24
|
-
exports.VISEME_SMOOTHING = 0.5;
|
|
25
|
-
//# sourceMappingURL=constants.js.map
|
package/dist/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../../../../../src/components/Avatar/AvatarView/AvatarComponent/components/FullbodyAvatar/constants.ts"],"names":[],"mappings":";;;AAAA,iCAAuC;AAG1B,QAAA,eAAe,GAAG,IAAI,eAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,QAAA,eAAe,GAAG,IAAI,aAAK,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACzC,QAAA,sBAAsB,GAAG,IAAI,eAAO,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAElD,QAAA,cAAc,GAAG;IAC5B,IAAI,EAAE,gFAAgF;IACtF,MAAM,EACJ,gFAAgF;CACnF,CAAC;AAEW,QAAA,YAAY,GAAG;IAC1B,WAAW,EAAE,IAAI;IACjB,WAAW,EAAE,IAAI;IACjB,aAAa,EAAE,GAAG;CACnB,CAAC;AAEW,QAAA,cAAc,GAAoB;IAC7C,cAAc,EAAE,GAAG;IACnB,eAAe,EAAE,GAAG;IACpB,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,GAAG;CACf,CAAC;AAEW,QAAA,iBAAiB,GAAG,GAAG,CAAC;AACxB,QAAA,gBAAgB,GAAG,GAAG,CAAC"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
interface FullbodyAvatarProps {
|
|
2
|
-
url: string;
|
|
3
|
-
sex: 'MALE' | 'FEMALE';
|
|
4
|
-
onLoaded?: () => void;
|
|
5
|
-
currentBaseAction: {
|
|
6
|
-
action: string;
|
|
7
|
-
weight: number;
|
|
8
|
-
};
|
|
9
|
-
timeScale: number;
|
|
10
|
-
isZoomed?: boolean;
|
|
11
|
-
eyeBlink?: boolean;
|
|
12
|
-
stopProcessing: () => void;
|
|
13
|
-
resetVisemeQueue: () => void;
|
|
14
|
-
updateCurrentViseme: (currentTime: number) => {
|
|
15
|
-
name: string;
|
|
16
|
-
weight: number;
|
|
17
|
-
} | null;
|
|
18
|
-
smoothMorphTarget?: boolean;
|
|
19
|
-
morphTargetSmoothing?: number;
|
|
20
|
-
morphTargetInfluences: Record<string, number>;
|
|
21
|
-
setMorphTargetDictionary: (morphTargetDictionary: Record<string, number>) => void;
|
|
22
|
-
setMorphTargetInfluences: (morphTargetInfluences: Record<string, number>) => void;
|
|
23
|
-
emotionMorphTargets: Record<string, number>;
|
|
24
|
-
}
|
|
25
|
-
export default function FullbodyAvatar({ url, sex, currentBaseAction, timeScale, isZoomed, eyeBlink, updateCurrentViseme, setMorphTargetDictionary, setMorphTargetInfluences, emotionMorphTargets, }: FullbodyAvatarProps): JSX.Element;
|
|
26
|
-
export {};
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
4
|
-
const react_1 = require("react");
|
|
5
|
-
const three_1 = require("three");
|
|
6
|
-
const drei_1 = require("@react-three/drei");
|
|
7
|
-
const fiber_1 = require("@react-three/fiber");
|
|
8
|
-
const AVATAR_POSITION = new three_1.Vector3(0, -1, 0);
|
|
9
|
-
const AVATAR_ROTATION = new three_1.Euler(0.175, 0, 0);
|
|
10
|
-
const AVATAR_POSITION_ZOOMED = new three_1.Vector3(0, -1.45, 0);
|
|
11
|
-
const ANIMATION_URLS = {
|
|
12
|
-
MALE: 'https://assets.memori.ai/api/v2/asset/2c5e88a4-cf62-408b-9ef0-518b099dfcb2.glb',
|
|
13
|
-
FEMALE: 'https://assets.memori.ai/api/v2/asset/8d1a5853-f05a-4a34-9f99-6eff64986081.glb',
|
|
14
|
-
};
|
|
15
|
-
const BLINK_CONFIG = {
|
|
16
|
-
minInterval: 1000,
|
|
17
|
-
maxInterval: 5000,
|
|
18
|
-
blinkDuration: 150,
|
|
19
|
-
};
|
|
20
|
-
const EMOTION_SMOOTHING = 0.3;
|
|
21
|
-
const VISME_SMOOTHING = 0.5;
|
|
22
|
-
function FullbodyAvatar({ url, sex, currentBaseAction, timeScale, isZoomed, eyeBlink, updateCurrentViseme, setMorphTargetDictionary, setMorphTargetInfluences, emotionMorphTargets, }) {
|
|
23
|
-
const { scene } = (0, drei_1.useGLTF)(url);
|
|
24
|
-
const { animations } = (0, drei_1.useGLTF)(ANIMATION_URLS[sex]);
|
|
25
|
-
const { actions } = (0, drei_1.useAnimations)(animations, scene);
|
|
26
|
-
const mixerRef = (0, react_1.useRef)();
|
|
27
|
-
const headMeshRef = (0, react_1.useRef)();
|
|
28
|
-
const currentActionRef = (0, react_1.useRef)(null);
|
|
29
|
-
const isTransitioningToIdleRef = (0, react_1.useRef)(false);
|
|
30
|
-
const lastBlinkTimeRef = (0, react_1.useRef)(0);
|
|
31
|
-
const nextBlinkTimeRef = (0, react_1.useRef)(0);
|
|
32
|
-
const isBlinkingRef = (0, react_1.useRef)(false);
|
|
33
|
-
const blinkStartTimeRef = (0, react_1.useRef)(0);
|
|
34
|
-
const currentEmotionRef = (0, react_1.useRef)({});
|
|
35
|
-
const previousEmotionKeysRef = (0, react_1.useRef)(new Set());
|
|
36
|
-
const headMesh = (0, react_1.useMemo)(() => {
|
|
37
|
-
let foundMesh;
|
|
38
|
-
scene.traverse((object) => {
|
|
39
|
-
if (object instanceof three_1.SkinnedMesh &&
|
|
40
|
-
(object.name === 'GBNL__Head' || object.name === 'Wolf3D_Avatar')) {
|
|
41
|
-
foundMesh = object;
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
return foundMesh;
|
|
45
|
-
}, [scene]);
|
|
46
|
-
(0, react_1.useEffect)(() => {
|
|
47
|
-
if (headMesh) {
|
|
48
|
-
headMeshRef.current = headMesh;
|
|
49
|
-
if (headMesh.morphTargetDictionary && headMesh.morphTargetInfluences) {
|
|
50
|
-
setMorphTargetDictionary(headMesh.morphTargetDictionary);
|
|
51
|
-
const initialInfluences = Object.keys(headMesh.morphTargetDictionary).reduce((acc, key) => ({ ...acc, [key]: 0 }), {});
|
|
52
|
-
setMorphTargetInfluences(initialInfluences);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
mixerRef.current = new three_1.AnimationMixer(scene);
|
|
56
|
-
}, [headMesh, scene, setMorphTargetDictionary, setMorphTargetInfluences]);
|
|
57
|
-
const handleAnimationChange = (0, react_1.useCallback)(() => {
|
|
58
|
-
if (!actions || !currentBaseAction.action)
|
|
59
|
-
return;
|
|
60
|
-
const newAction = actions[currentBaseAction.action];
|
|
61
|
-
if (!newAction) {
|
|
62
|
-
console.warn(`Animation "${currentBaseAction.action}" not found in actions.`);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
const fadeOutDuration = 0.8;
|
|
66
|
-
const fadeInDuration = 0.8;
|
|
67
|
-
if (currentActionRef.current) {
|
|
68
|
-
currentActionRef.current.fadeOut(fadeOutDuration);
|
|
69
|
-
}
|
|
70
|
-
newAction.reset().fadeIn(fadeInDuration).play();
|
|
71
|
-
currentActionRef.current = newAction;
|
|
72
|
-
newAction.timeScale = timeScale;
|
|
73
|
-
if (currentBaseAction.action.startsWith('Gioia') ||
|
|
74
|
-
currentBaseAction.action.startsWith('Rabbia') ||
|
|
75
|
-
currentBaseAction.action.startsWith('Sorpresa') ||
|
|
76
|
-
currentBaseAction.action.startsWith('Timore') ||
|
|
77
|
-
currentBaseAction.action.startsWith('Tristezza')) {
|
|
78
|
-
newAction.setLoop(three_1.LoopOnce, 1);
|
|
79
|
-
newAction.clampWhenFinished = true;
|
|
80
|
-
isTransitioningToIdleRef.current = true;
|
|
81
|
-
}
|
|
82
|
-
}, [actions, currentBaseAction, timeScale]);
|
|
83
|
-
(0, react_1.useEffect)(() => {
|
|
84
|
-
handleAnimationChange();
|
|
85
|
-
}, [handleAnimationChange]);
|
|
86
|
-
const updateFrame = (0, react_1.useCallback)((currentTime) => {
|
|
87
|
-
var _a;
|
|
88
|
-
if (!headMeshRef.current ||
|
|
89
|
-
!headMeshRef.current.morphTargetDictionary ||
|
|
90
|
-
!headMeshRef.current.morphTargetInfluences)
|
|
91
|
-
return;
|
|
92
|
-
let blinkValue = 0;
|
|
93
|
-
if (eyeBlink) {
|
|
94
|
-
if (currentTime >= nextBlinkTimeRef.current && !isBlinkingRef.current) {
|
|
95
|
-
isBlinkingRef.current = true;
|
|
96
|
-
blinkStartTimeRef.current = currentTime;
|
|
97
|
-
lastBlinkTimeRef.current = currentTime;
|
|
98
|
-
nextBlinkTimeRef.current =
|
|
99
|
-
currentTime +
|
|
100
|
-
Math.random() *
|
|
101
|
-
(BLINK_CONFIG.maxInterval - BLINK_CONFIG.minInterval) +
|
|
102
|
-
BLINK_CONFIG.minInterval;
|
|
103
|
-
}
|
|
104
|
-
if (isBlinkingRef.current) {
|
|
105
|
-
const blinkProgress = (currentTime - blinkStartTimeRef.current) /
|
|
106
|
-
BLINK_CONFIG.blinkDuration;
|
|
107
|
-
if (blinkProgress <= 0.5) {
|
|
108
|
-
blinkValue = blinkProgress * 2;
|
|
109
|
-
}
|
|
110
|
-
else if (blinkProgress <= 1) {
|
|
111
|
-
blinkValue = 2 - blinkProgress * 2;
|
|
112
|
-
}
|
|
113
|
-
else {
|
|
114
|
-
isBlinkingRef.current = false;
|
|
115
|
-
blinkValue = 0;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
const currentViseme = updateCurrentViseme(currentTime / 1000);
|
|
120
|
-
const currentEmotionKeys = new Set(Object.keys(emotionMorphTargets));
|
|
121
|
-
Object.entries(headMeshRef.current.morphTargetDictionary).forEach(([key, index]) => {
|
|
122
|
-
if (typeof index === 'number') {
|
|
123
|
-
let targetValue = 0;
|
|
124
|
-
if (currentEmotionKeys.has(key)) {
|
|
125
|
-
const targetEmotionValue = emotionMorphTargets[key];
|
|
126
|
-
const currentEmotionValue = currentEmotionRef.current[key] || 0;
|
|
127
|
-
const newEmotionValue = three_1.MathUtils.lerp(currentEmotionValue, targetEmotionValue * 2.5, EMOTION_SMOOTHING);
|
|
128
|
-
currentEmotionRef.current[key] = newEmotionValue;
|
|
129
|
-
targetValue += newEmotionValue;
|
|
130
|
-
}
|
|
131
|
-
if (currentViseme && key === currentViseme.name) {
|
|
132
|
-
targetValue += currentViseme.weight;
|
|
133
|
-
}
|
|
134
|
-
if (key === 'eyesClosed' && eyeBlink) {
|
|
135
|
-
targetValue += blinkValue;
|
|
136
|
-
}
|
|
137
|
-
targetValue = three_1.MathUtils.clamp(targetValue, 0, 1);
|
|
138
|
-
if (headMeshRef.current &&
|
|
139
|
-
headMeshRef.current.morphTargetInfluences) {
|
|
140
|
-
headMeshRef.current.morphTargetInfluences[index] = three_1.MathUtils.lerp(headMeshRef.current.morphTargetInfluences[index], targetValue, VISME_SMOOTHING);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
previousEmotionKeysRef.current = currentEmotionKeys;
|
|
145
|
-
if (isTransitioningToIdleRef.current && currentActionRef.current) {
|
|
146
|
-
if (currentActionRef.current.time >=
|
|
147
|
-
currentActionRef.current.getClip().duration) {
|
|
148
|
-
const idleNumber = Math.floor(Math.random() * 5) + 1;
|
|
149
|
-
const idleAction = actions[`Idle${idleNumber === 3 ? 4 : idleNumber}`];
|
|
150
|
-
if (idleAction) {
|
|
151
|
-
currentActionRef.current.fadeOut(0.5);
|
|
152
|
-
idleAction.reset().fadeIn(0.5).play();
|
|
153
|
-
currentActionRef.current = idleAction;
|
|
154
|
-
isTransitioningToIdleRef.current = false;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
(_a = mixerRef.current) === null || _a === void 0 ? void 0 : _a.update(0.01);
|
|
159
|
-
}, [actions, emotionMorphTargets, eyeBlink, updateCurrentViseme]);
|
|
160
|
-
(0, fiber_1.useFrame)(state => {
|
|
161
|
-
updateFrame(state.clock.elapsedTime * 1000);
|
|
162
|
-
});
|
|
163
|
-
return ((0, jsx_runtime_1.jsx)("group", { position: isZoomed ? AVATAR_POSITION_ZOOMED : AVATAR_POSITION, rotation: AVATAR_ROTATION, children: (0, jsx_runtime_1.jsx)("primitive", { object: scene }) }));
|
|
164
|
-
}
|
|
165
|
-
exports.default = FullbodyAvatar;
|
|
166
|
-
//# sourceMappingURL=fullbodyAvatar.js.map
|