游標離開人物時立刻中斷跳躍,不再播完三次

摘要:
hover 跳躍改為「游標一離開就停」,而不是不管游標在哪都把 3 次播完。

根本原因:
把 hover 跳躍實作成一次性 overlay,播放長度固定為 STATE_REPEATS 輪,
setHovered(false) 只更新 hovered 旗標、不動 overlay,所以游標即使馬上移開,
跳躍仍會自顧自播完約 2.5 秒才回到基礎狀態。
這其實也偏離 Codex:Codex 的顯示狀態是 `hovered ? "jumping" : state`,
游標一離開就翻回原狀態並重跑動畫,本來就不會把跳躍播完。

影響:
只是游標經過或很快移開時,寵物還會繼續跳完,反應顯得遲滯、不跟手。

修法:
- play() 之後把該 overlay 標記 fromHover。
- setHovered(false) 時若目前 overlay 是 hover 觸發的就直接清掉,
  下一個 tick 會依 resolveAnim 回到當下的基礎狀態。
  只清 fromHover 的,初次問候揮手等其他一次性動作不受影響。
- README 的日常使用、行為對照表、與 Codex 的對照三處同步更新,
  對照表新增「hover 離開」一列。

保持不變:
進入時最多跳 3 次、游標持續停留不重複觸發(使用者已確認要這個行為)。

驗證:
以 DOM stub 載入完整 renderer.js 執行 13 項測試全過,涵蓋:
進入觸發 jumping 且序列為 15 幀、標記 fromHover、離開後 overlay 立刻為 null、
resolveAnim 立刻回 idle、工作中離開回到 running 而非 idle、
問候揮手不會被離開中斷、既有 overlay 期間不觸發跳躍、
持續停留不重複觸發、拖曳中不觸發。
另以 ELECTRON_RUN_AS_NODE 讀打包後 app.asar 確認版本 2.0.3 與六項改動都在出貨檔案裡,
exe FileVersion 為 2.0.3。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-21 16:58:57 +08:00
co-authored by Claude Fable 5
parent 7e2f689f26
commit d78f99fcc7
4 changed files with 18 additions and 8 deletions
+4 -3
View File
@@ -87,7 +87,7 @@ npm run autostart:install # (可選)開機自動啟動
| 左鍵點一下 | 揮手(若有非固定的氣泡,先關閉氣泡) |
| 左鍵拖曳 | 搬家;往左播 running-left、往右播 running-right;放開後位置寫入設定檔 |
| 右鍵 / 系統匣左鍵 | 開啟選單 |
| 滑鼠移到她身上 | 跳躍 3 次回到原本狀態(Codex 的 hover 行為) |
| 滑鼠移到她身上 | 跳躍最多 3 次;游標一離開就立刻停止、回到原本狀態(Codex 的 hover 行為) |
| 滑鼠靠近 | 盯著游標看(選單開啟「跟著游標看」後才有) |
**選單功能**
@@ -125,7 +125,7 @@ npm run autostart:install # (可選)開機自動啟動
| `SessionEnd` | | 移除該 session | 最後一個結束時 👋 掰掰 |
| (無事件) | 游標移動(追視開啟時、且目前為 idle) | 16 方向 `look` | |
| (無事件) | 拖曳 | 單次位移 ≥ 4 px 才決定 `running-left` / `running-right` | |
| (無事件) | 游標進入人物方框 | `jumping` × 3 → 回原狀態 | |
| (無事件) | 游標進入人物方框 | `jumping` 最多 × 3;離開即中斷 | |
規則:
@@ -258,7 +258,8 @@ Claude Code ──hookstdin JSON)──▶ hook/claude-pet-hook.js ──PO
| `waiting` | 授權、`requestUserInput`、計畫待確認 | 相同;`idle_prompt` 不算 |
| `review` | turn 完成且未讀,直到使用者回到該 thread | 直到該 session 下一個動作 |
| `waving` | 只在 first-awake(每隻寵物一次,8 秒) | 相同(記在設定檔 `greetedPetIds` |
| `jumping` | 定義在 `respondToHover ? "jumping" : state`,但整個 app 沒人開啟那個 prop | **選擇打開**:游標進入人物方框就播 3 次 |
| `jumping` | 定義在 `respondToHover ? "jumping" : state`,但整個 app 沒人開啟那個 prop | **選擇打開**:游標進入人物方框就播,最多 3 次 |
| hover 離開 | 顯示狀態立刻翻回 `state`,動畫重跑,不會把跳躍播完 | 相同(游標離開就中斷跳躍) |
| hover 版面 | 40 px 內進入、56 px 外退出;人物縮 0.9、下移 14 px、上方 24 px 控制鈕、200 ms | 未採用——控制鈕的功能就是選單,右鍵已經有了 |
| hover 判定 | 用矩形(`pet-area-hover-changed` 由 rect 算) | 相同(逐像素會因每格輪廓不同而抖動) |
| 追視來源 | quick chat 的文字游標/computer-use 游標 | 沒有對應來源;改為**選配**看滑鼠,預設關 |
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "claude-pet",
"version": "2.0.2",
"version": "2.0.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "claude-pet",
"version": "2.0.2",
"version": "2.0.3",
"devDependencies": {
"electron": "^43.4.1",
"electron-builder": "^26.0.12"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "claude-pet",
"version": "2.0.2",
"version": "2.0.3",
"description": "Codex Pets 相容的 Claude Code 桌面寵物(spriteVersionNumber 29 個動作列 + 16 方向追視)",
"main": "main.js",
"private": true,
+11 -2
View File
@@ -575,8 +575,17 @@ function overPetArea(x, y) {
function setHovered(on) {
if (on === hovered) return;
hovered = on;
// 只在「進入」時觸發一次;一次性動作或拖曳進行中不打斷
if (on && !overlay && !drag) play("jumping", STATE_REPEATS);
if (on) {
// 只在「進入」時觸發一次;一次性動作或拖曳進行中不打斷
if (!overlay && !drag) {
play("jumping", STATE_REPEATS);
overlay.fromHover = true;
}
return;
}
// 游標離開就立刻收掉,不等三次跳完。Codex 也是這樣:它的顯示狀態是
// `hovered ? "jumping" : state`,一離開就翻回原狀態、動畫重跑,不會播完。
if (overlay?.fromHover) overlay = null;
}
function setIgnore(ignore) {