動畫時序照 Codex 校正,並修掉 look 列被畫小造成的縮水
摘要:
待機動畫放慢成 Codex 的速度、非 idle 狀態播 3 次後沉澱,並自動補正 spritesheet 裡整列 look 格子被畫小的缺陷。
根本原因:
1. idle 直接用合約上的幀時長無限循環,一輪只有 1.1 秒,看起來一直在動。Codex 的 codex-pet-assets 裡有一個放慢倍率 6,idle 實際是一輪 6.6 秒,其他狀態則是播 3 次後接上慢速 idle 並從那裡循環。
2. 內附的小念 spritesheet 第 10 列(看向 180 度到 337.5 度)整列被畫成 idle 的 78%,寬高同時縮小。游標移到人物身上或左邊時會切到那一列,人物就突然矮一截。第 9 列尾端只有高度變矮、寬度不變,那是低頭姿勢,不能一起改。
3. 追視參考點取在頭部高度(0.3),與 Codex 的方框中心不同,使得更多游標位置被判成「在下方」,更容易踩到第 10 列。
影響:
待機時一直晃;游標一靠近或移到左側,人物就明顯縮水又彈回來。
修法:
- 動畫改成序列模型(frames = [{row, col, ms}] + loopStart),對應 Codex 的 f(state):
IDLE_SLOWDOWN = 6、STATE_REPEATS = 3、播完 3 次後循環慢速 idle。
- 每個 hook 事件都重播一次動畫(pulse),對應 Codex 每次狀態更新都會重跑動畫效果;
否則狀態播完 3 次後就再也看不出 Claude Code 在忙。
- 載入寵物時量測 16 個 look 格子,以整列中位數判斷是否整列被縮小(門檻 0.9),
是的話以腳底為支點放大回 idle 身高;單格差異不動,避免把低頭姿勢拉直。
- 追視參考點改為人物方框中心、死區改為 1 px,與 Codex 相同。
- 拖曳用的 running-left / running-right 維持持續循環,不套用沉澱規則。
刻意不同於 Codex 的地方:
Codex 的追視會覆蓋所有狀態,本程式只在 idle 時追視。否則工作中的動畫會被靜態擺姿蓋掉,
寵物就失去反映 Claude Code 狀態的作用。
驗證:
- 抽出序列邏輯單獨執行:idle 一輪 6600 ms(幀長 1680/660/660/840/840/1920);
running / waiting / review 皆為 24 幀、第 18 幀起循環列 0;拖曳維持循環;一次性動作播完即止。
- 以 PIL 重現量測與繪製:小念第 9 列中位數比 0.995 不補正,第 10 列 0.783 補正倍率 1.2774,
補正後畫面身高 128.7-132.1 px(idle 為 130.4),且無任何一格超出畫布;
xiao-nian-realistic 兩列都是 0.99,判定不需補正而未受影響。
- 以 ELECTRON_RUN_AS_NODE 讀打包後 app.asar 內的 renderer.js 與 main.js,確認六項改動都在出貨的檔案裡。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,8 @@
|
||||
## 特色
|
||||
|
||||
- **完整實作 Codex V2 pet contract** — 8 欄 × 11 列、192×208 cell 的 spritesheet,9 個標準動作列 + 16 個看向方向,**每一幀的時長都照 Codex 規格**,動起來跟在 Codex app 裡一模一樣。
|
||||
- **16 方向追視** — 游標在哪,她就看哪(000 = 正上方、順時針 22.5° 一格)。游標靠太近或靜止 6 秒就回到 idle 呼吸動畫。
|
||||
- **16 方向追視** — 游標在哪,她就看哪(000 = 正上方、順時針 22.5° 一格)。追視時是靜態擺姿、完全不動,與 Codex 相同;游標靜止 6 秒才改播慢速 idle。
|
||||
- **自動修正圖檔缺陷** — Codex 的 hatch 產生器有時會把整列 look 格子畫得比 idle 小(內附的小念第 10 列就小了 22%,游標一往下移人物就縮水)。以整列中位數偵測、用腳底當支點放大回正確身高;單格的姿勢差異不動。Codex 本身沒有做這件事。
|
||||
- **與 Codex 同尺寸** — 100% 就是 Codex 桌面寵物的大小(126 × 137),高度用 Codex 的 `ceil(寬 × 208/192)` 算,兩邊並排看起來一樣大。
|
||||
- **真正的桌面寵物** — 透明、無邊框、永遠置頂;透明區域**點穿**,只有壓在人物像素上滑鼠才會被吃掉,不擋你操作底下的視窗。
|
||||
- **不搶焦點** — 視窗設為 non-focusable,點她不會讓終端機失焦。
|
||||
@@ -123,6 +124,8 @@ npm run autostart:install # (可選)開機自動啟動
|
||||
|
||||
規則:
|
||||
|
||||
- **待機時幾乎不動** — idle 每幀時長是合約值的 **6 倍**(一輪 6.6 秒,不是 1.1 秒),與 Codex 的 `codex-pet-assets` 一致。
|
||||
- **非 idle 狀態播 3 次就沉澱** 成慢速 idle,也和 Codex 相同;但每收到一個 hook 事件就重播一次,所以工作中她會隨著每次工具呼叫動一下,安靜下來才靜下來。
|
||||
- **一次性動作**(waving / jumping / failed)播完自動回到該 session 的基礎狀態。
|
||||
- **基礎狀態**依 session 彙整:`waiting(3) > running(2) > review(1) > idle(0)`,取最高者顯示。
|
||||
- 30 分鐘沒有任何事件的 session 會被視為結束而忽略(避免沒送 `SessionEnd` 的終端機卡住狀態)。
|
||||
@@ -228,6 +231,7 @@ Claude Code ──hook(stdin JSON)──▶ hook/claude-pet-hook.js ──PO
|
||||
|
||||
- **點穿**:視窗預設 `setIgnoreMouseEvents(true, { forward: true })`,renderer 在 mousemove 時讀 canvas 該點 alpha(或是否在氣泡上)來即時切換,所以透明處永遠點得到底下的視窗。
|
||||
- **拖曳**:由主程序用 `screen.getCursorScreenPoint()` 每 16 ms 更新視窗位置,游標離開視窗也不會掉;方向由水平位移決定。
|
||||
- **動畫時序完全照 Codex**:`IDLE_SLOWDOWN = 6`、`STATE_REPEATS = 3`、追視死區 1 px、追視參考點為人物方框中心——這幾個值都是從 Codex app 的 `resources/app.asar` 裡的 `codex-pet-assets` 讀出來的(`_ = 6`、`[...n,...n,...n]`、`N = 1`)。唯一刻意不同的是:Codex 的追視會覆蓋所有狀態,本程式只在 idle 時追視,否則工作中的動畫會被蓋掉、看不出 Claude Code 在忙。
|
||||
- **顯示尺寸與 sprite 來源尺寸分開**:`CELL_W/CELL_H`(192 × 208)只用來從 spritesheet 取格子,畫到畫面上的是 `PET_W/PET_H`(126 × 137,Codex 的 mascot 尺寸)。視窗寬度另有 `MIN_WIN_W = 240` 的下限,免得寵物變小後氣泡被截掉。
|
||||
- **Spritesheet 以 data URL 傳給 renderer**,避免 `file://` 跨來源污染 canvas 導致 `getImageData` 失敗。
|
||||
- **hook 合併規則**:以指令中是否含 `claude-pet-hook` 辨識自己的項目,重裝只替換自己的、不動別人的。
|
||||
|
||||
Reference in New Issue
Block a user