From 6da47758679708632f9c629364ba2e1f8e2bdfa0 Mon Sep 17 00:00:00 2001 From: JianMiau Date: Fri, 21 Aug 2026 15:18:30 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E9=99=A4=20hover=20=E6=B5=AE=E5=87=BA?= =?UTF-8?q?=E7=9A=84=E9=81=B8=E5=96=AE=E9=88=95=EF=BC=8C=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8D=87=E5=88=B0=202.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 摘要: 拿掉游標靠近時人物縮小讓位、上方浮出圓形選單鈕的整套 hover 版面,選單只留右鍵與系統匣。 根本原因: 上一版照 Codex 的 petControlsAppearance 做了 proximity 版面,但那顆控制鈕的作用就是開選單, 而本程式的右鍵與系統匣已經有同樣的選單,多一顆按鈕沒有增加任何功能, 反而讓游標經過時人物會縮小位移。 影響: 滑鼠靠近時人物無謂地縮小、下移,並蓋出一顆重複功能的按鈕。 修法: - renderer:移除 HOVER_SCALE / HOVER_OFFSET_Y / PROXIMITY_ENTER / PROXIMITY_EXIT 常數, 以及 updateProximity / setNear / overControls / distanceToRect 與 near 狀態、 applyScale 裡的控制鈕定位、menu-btn 的事件繫結;mousemove 的點穿判定回到人物與氣泡兩者。 - index.html 移除 #controls;style.css 移除 body.near 的縮放位移與 #controls 樣式。 - package.json 版本 0.1.0 → 2.0.0。 - README 的日常使用、行為對照表、與 Codex 的對照三處同步更新, 對照表標明此項未採用及原因。 保留不變: 右鍵與系統匣選單、idle 放慢 6 倍、狀態優先序與到期、look 列縮放補正、 first-awake 問候、拖曳 4 px 方向閾值、reduced motion。 驗證: - 三個 js 檔語法檢查通過,全專案 grep 確認 controls / menu-btn / HOVER_ / PROXIMITY_ / body.near / setNear 等皆無殘留。 - 實機啟動:/health 正常,events.log 顯示 look rows rescaled 8 cells 仍正常觸發; 把游標移到人物上截圖,人物維持原尺寸原位置、無按鈕浮出(測後游標已復位)。 - 以 ELECTRON_RUN_AS_NODE 讀打包後 app.asar:版本 2.0.0、html 無 menu-btn、 css 無 body.near、js 無 proximity 邏輯,且右鍵選單、idle 放慢、look 補正、 狀態優先序都還在;exe 版本資訊為 2.0.0。 Co-Authored-By: Claude Fable 5 --- README.md | 4 +--- package.json | 2 +- renderer/index.html | 1 - renderer/renderer.js | 46 +------------------------------------------ renderer/style.css | 47 -------------------------------------------- 5 files changed, 3 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 6c5c6e2..9a33cc8 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,6 @@ npm run autostart:install # (可選)開機自動啟動 | 左鍵點一下 | 揮手(若有非固定的氣泡,先關閉氣泡) | | 左鍵拖曳 | 搬家;往左播 running-left、往右播 running-right;放開後位置寫入設定檔 | | 右鍵 / 系統匣左鍵 | 開啟選單 | -| 滑鼠靠近(40 px 內) | 她縮到 0.9、往下讓出位置,上方出現選單鈕;離開 56 px 外才復原(Codex 的 hover 版面) | | 滑鼠靠近 | 盯著游標看(選單開啟「跟著游標看」後才有) | **選單功能** @@ -125,7 +124,6 @@ npm run autostart:install # (可選)開機自動啟動 | `SessionEnd` | | 移除該 session | 最後一個結束時 👋 掰掰 | | (無事件) | 游標移動(追視開啟時) | 16 方向 `look`,覆蓋所有狀態 | | | (無事件) | 拖曳 | 單次位移 ≥ 4 px 才決定 `running-left` / `running-right` | | -| (無事件) | 游標靠近 40 px 內 | 動畫不變;人物縮 0.9、顯示選單鈕 | | 規則: @@ -259,7 +257,7 @@ Claude Code ──hook(stdin JSON)──▶ hook/claude-pet-hook.js ──PO | `review` | turn 完成且未讀,直到使用者回到該 thread | 直到該 session 下一個動作 | | `waving` | 只在 first-awake(每隻寵物一次,8 秒) | 相同(記在設定檔 `greetedPetIds`) | | `jumping` | 只在 `respondToHover`,而整個 app 沒人開啟它 | 只在選單「動作測試」 | -| hover | 40 px 內進入、56 px 外退出;人物縮 0.9、下移 14 px、上方 24 px 控制鈕、200 ms | 相同;控制鈕是選單 | +| hover | 40 px 內進入、56 px 外退出;人物縮 0.9、下移 14 px、上方 24 px 控制鈕、200 ms | 未採用——控制鈕的功能就是選單,右鍵已經有了 | | 追視 | 看 quick chat 文字游標/computer-use 游標,死區 1 px,覆蓋所有狀態 | 沒有對應來源;改為**選配**看滑鼠,預設關 | | 拖曳方向 | 單次取樣水平位移 ≥ 4 px | 相同 | | 拖曳放開 | 彈簧回彈(spring 220 / damping 26) | 無(直接停在放開處) | diff --git a/package.json b/package.json index 8128dcc..817d4fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-pet", - "version": "0.1.0", + "version": "2.0.0", "description": "Codex Pets 相容的 Claude Code 桌面寵物(spriteVersionNumber 2:9 個動作列 + 16 方向追視)", "main": "main.js", "private": true, diff --git a/renderer/index.html b/renderer/index.html index e076041..f9a858d 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -9,7 +9,6 @@
-
diff --git a/renderer/renderer.js b/renderer/renderer.js index 761fc32..3e5cac8 100644 --- a/renderer/renderer.js +++ b/renderer/renderer.js @@ -54,18 +54,12 @@ const EXPIRY = { failed: 3600e3, waiting: 1440 * 60e3, review: 10080 * 60e3 }; const RUNNING_SILENCE = 30 * 60e3; const IDLE_PRUNE = 30 * 60e3; // idle 的 session 閒置多久後從清單移除(純清理,不影響顯示) -// hover 版面,數值與 Codex 的 petControlsAppearance 相同 -const HOVER_SCALE = 0.9; // H_:游標靠近時人物縮到 0.9 -const HOVER_OFFSET_Y = 10 + 8 / 2; // hoverOffsetY + hoverControlGap / 2:人物往下移,讓出上方放控制鈕 -const PROXIMITY_ENTER = 40; // proximityEnterDistance:游標離人物多近算「靠近」 -const PROXIMITY_EXIT = 56; // proximityExitDistance:離多遠才算離開(遲滯,避免邊界抖動) const GREETING_MS = 8000; // first-awake 問候通知的存活時間(Pi = 8 s) const canvas = document.getElementById("sprite"); const ctx = canvas.getContext("2d", { willReadFrequently: true }); const bubble = document.getElementById("bubble"); const bubbleText = document.getElementById("bubble-text"); -const controls = document.getElementById("controls"); let sheet = null; let petInfo = null; @@ -130,7 +124,6 @@ function startAnim(anim, now) { let bubbleTimer = null; let bubbleSticky = false; let ignoringMouse = true; -let near = false; // 游標是否在人物附近(Codex 的 proximity) let pressed = null; let lastReported = ""; @@ -166,10 +159,6 @@ function applyScale(s) { canvas.height = Math.round(PET_H * s); canvas.style.width = `${canvas.width}px`; canvas.style.height = `${canvas.height}px`; - // 控制鈕底邊 = 縮小後人物的頂端再往上 8 px(hoverControlGap)。 - // 人物以中心縮到 0.9 再往下移 HOVER_OFFSET_Y,頂端會下移 h*(1-0.9)/2 + HOVER_OFFSET_Y。 - const shiftedTop = canvas.height * (1 - HOVER_SCALE) / 2 + HOVER_OFFSET_Y; - controls.style.bottom = `${8 + canvas.height - shiftedTop + 8}px`; } // 量一格的人物輪廓(用來偵測圖檔裡整列被畫小的缺陷) @@ -563,31 +552,6 @@ function overSprite(x, y) { } } -function overControls(x, y) { - if (!near) return false; - const r = controls.getBoundingClientRect(); - return x >= r.left && x <= r.right && y >= r.top && y <= r.bottom; -} - -function distanceToRect(x, y, r) { - const dx = Math.max(r.left - x, 0, x - r.right); - const dy = Math.max(r.top - y, 0, y - r.bottom); - return Math.hypot(dx, dy); -} - -// Codex 的 hover:游標進到離人物 40 px 內就切到 hover 版面——人物縮到 0.9、往下移 14 px、 -// 上方出現 24 px 的控制鈕(200 ms 過渡);離開超過 56 px 才退出。動畫狀態本身不變。 -function updateProximity(x, y) { - const d = distanceToRect(x, y, canvas.getBoundingClientRect()); - setNear(near ? d <= PROXIMITY_EXIT : d <= PROXIMITY_ENTER); -} - -function setNear(on) { - if (on === near) return; - near = on; - document.body.classList.toggle("near", on); -} - function setIgnore(ignore) { if (ignore === ignoringMouse) return; ignoringMouse = ignore; @@ -605,18 +569,15 @@ window.addEventListener("mousemove", (e) => { } return; } - updateProximity(e.clientX, e.clientY); - setIgnore(!(overSprite(e.clientX, e.clientY) || overBubble(e.clientX, e.clientY) || overControls(e.clientX, e.clientY))); + setIgnore(!(overSprite(e.clientX, e.clientY) || overBubble(e.clientX, e.clientY))); }); document.addEventListener("mouseout", (e) => { if (e.relatedTarget || pressed) return; - setNear(false); setIgnore(true); }); window.addEventListener("mousedown", (e) => { - if (e.target instanceof Element && e.target.closest("#controls")) return; if (e.button === 0) { pressed = { x: e.clientX, y: e.clientY, sx: e.screenX, sy: e.screenY, moved: false }; } else if (e.button === 2) { @@ -667,11 +628,6 @@ window.pet.on("pet:settings", (st) => { }); window.pet.on("pet:event", handleEvent); -document.getElementById("menu-btn").addEventListener("click", (e) => { - e.stopPropagation(); - window.pet.send("pet:context-menu"); -}); - // 系統的「減少動態效果」切換時,讓目前的動畫重新開始(Codex 的 effect 也把 reducedMotion 列為相依) reducedMotionQuery.addEventListener("change", () => { if (player.anim) startAnim(player.anim, performance.now()); }); diff --git a/renderer/style.css b/renderer/style.css index 783f556..55a8cc3 100644 --- a/renderer/style.css +++ b/renderer/style.css @@ -56,53 +56,6 @@ html, body { #sprite { display: block; - /* Codex 的 hover 版面:以中心縮到 0.9 並往下移,200 ms 過渡(transitionDurationMs) */ - transform-origin: 50% 50%; - transition: transform 200ms ease; -} - -body.near #sprite { - transform: translateY(14px) scale(0.9); -} - -/* 靠近時氣泡讓開控制鈕 */ -body.near #bubble:not(.hidden) { - transform: translateY(-22px); -} - -/* 控制鈕:24 px(hoverControlSize),靠近時才出現 */ -#controls { - position: absolute; - left: 50%; - transform: translateX(-50%); - display: flex; - gap: 8px; - opacity: 0; - pointer-events: none; - transition: opacity 200ms ease; -} - -body.near #controls { - opacity: 1; - pointer-events: auto; -} - -#controls button { - width: 24px; - height: 24px; - padding: 0; - border: none; - border-radius: 50%; - background: rgba(255, 255, 255, 0.97); - color: #222; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28); - font-size: 13px; - line-height: 24px; - cursor: pointer; -} - -#controls button:hover { - background: #fff; } #sprite.grab {