fix(expressions): use full expression names with .exp3.json suffix

Epsilon model registers expressions as 'Smile.exp3.json' not 'Smile'.
Added EXPR_MAP to map friendly names to full registered names.
Fixes expression buttons and idle cycling.
This commit is contained in:
2026-06-05 14:19:59 -04:00
parent 73fe77f9aa
commit 37c06db6be
+12 -2
View File
@@ -18,6 +18,16 @@ type ExpressionName = 'Normal' | 'Smile' | 'Sad' | 'Angry' | 'Surprised' | 'Blus
const EXPRESSIONS: ExpressionName[] = ['Normal', 'Smile', 'Sad', 'Angry', 'Surprised', 'Blushing']; const EXPRESSIONS: ExpressionName[] = ['Normal', 'Smile', 'Sad', 'Angry', 'Surprised', 'Blushing'];
const IDLE_EXPRESSIONS: ExpressionName[] = ['Normal', 'Smile', 'Blushing']; const IDLE_EXPRESSIONS: ExpressionName[] = ['Normal', 'Smile', 'Blushing'];
// The Epsilon model registers expressions with the .exp3.json suffix
const EXPR_MAP: Record<ExpressionName, string> = {
Normal: 'Normal.exp3.json',
Smile: 'Smile.exp3.json',
Sad: 'Sad.exp3.json',
Angry: 'Angry.exp3.json',
Surprised: 'Surprised.exp3.json',
Blushing: 'Blushing.exp3.json',
};
export default function KiraAvatar(props: Props) { export default function KiraAvatar(props: Props) {
const lipSyncRef = useRef<number>(0); const lipSyncRef = useRef<number>(0);
const idleExprRef = useRef<ReturnType<typeof setInterval> | null>(null); const idleExprRef = useRef<ReturnType<typeof setInterval> | null>(null);
@@ -29,7 +39,7 @@ export default function KiraAvatar(props: Props) {
idleExprRef.current = setInterval(() => { idleExprRef.current = setInterval(() => {
if (props.isSpeaking) return; if (props.isSpeaking) return;
const expr = IDLE_EXPRESSIONS[Math.floor(Math.random() * IDLE_EXPRESSIONS.length)]; const expr = IDLE_EXPRESSIONS[Math.floor(Math.random() * IDLE_EXPRESSIONS.length)];
try { props.kiraModel.expression(expr); } catch {} try { props.kiraModel.expression(EXPR_MAP[expr]); } catch {}
setCurrentExpression(expr); setCurrentExpression(expr);
}, 8000 + Math.random() * 7000); }, 8000 + Math.random() * 7000);
return () => clearInterval(idleExprRef.current ?? undefined); return () => clearInterval(idleExprRef.current ?? undefined);
@@ -106,7 +116,7 @@ export default function KiraAvatar(props: Props) {
<button <button
key={expr} key={expr}
onClick={() => { onClick={() => {
try { props.kiraModel?.expression(expr); setCurrentExpression(expr); props.onExpressionChange?.(expr); } catch {} try { props.kiraModel?.expression(EXPR_MAP[expr]); setCurrentExpression(expr); props.onExpressionChange?.(expr); } catch {}
}} }}
className={`text-[9px] px-2 py-0.5 rounded-full font-medium transition-all ${ className={`text-[9px] px-2 py-0.5 rounded-full font-medium transition-all ${
currentExpression === expr currentExpression === expr