## 设计 — 前端动画状态机

Section 3/4：VRMPet.vue 重构

### 核心原则

emotion = 持续状态
驱动动画 + blendshape
对所有 petState 生效
idle 时自动清除
action = 一次性手势
播完回退
不改变当前情绪状态
可在任意 petState 触发
petState = fallback
没有 emotion 时才用
提供 speaking 口型
提供 error 表情

### 动画优先级

action（一次性） > emotion（持续） > petState（fallback）

action 播放期间抢占动画，播完后 emotion 接管。没有 emotion 时 petState fallback 生效。

### emo→动画 映射（新增 thinking/idle/listening 覆盖）

emotion | 动画（持续） | intensity 阈值
--- | --- | ---
joy | celebrate.vrma | ≥ 0.4
sad | sad.vrma | ≥ 0.4
surprised | surprised_react.vrma | ≥ 0.4
angry | angry.vrma | ≥ 0.4
neutral / <0.4 | 回退到 petState fallback | —

### action→动画 映射

action | 动画（一次性） | 播放时长
--- | --- | ---
wave | wave_big.vrma | ~3s
nod | nod.vrma | ~2s
surprised_react | surprised_react.vrma | ~3s
celebrate | celebrate.vrma | ~2s

### 全新工作流

`chat:behavior` 到达 →
1. 设置 blendshape target（emotion → VRM blendshape, intensity → 权重）
2. 如果有 action → 立即播放一次性动画，播完后自动回退到第3步
3. 如果 intensity ≥ 0.4 → 切换到 emotion 对应的持续动画
4. 如果 intensity < 0.4 → 回退到当前 petState fallback 动画
`pet:state:change` 到达 →
1. speaking 状态：驱动 mouth blendshape（aa sin波）
2. idle 状态：清除 blendshape target + 清除 emotion → 回退到 waiting
3. error 状态：设置 sad blendshape + embarrassed 动画
4. 其他状态：如果没有活跃 emotion，设置状态 fallback 动画