# 🐋 趴趴鲸鱼娘 dsh-whale-lap 为 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 打造的二次元桌宠插件:一只**手绘 SVG** 的可爱鲸鱼娘,**趴在对话框(composer)上沿**陪你写代码——会眨眼、摇尾巴、头顶喷水、冒泡泡,工作起来还会掏出小电脑。 > 参考 GitHub 上的 [dsh-whale-musume(元气鲸鱼娘)](https://github.com/Sutera-Diffusus/dsh-whale-musume) 重制:与其用 90+ 张生成立绘不同,本插件全部形象为**手绘矢量 SVG + CSS/JS 动画**,体积小、真·灵动动态、零外部依赖、无遥测。 ## ✨ 特性 | 类别 | 内容 | | --- | --- | | 🎨 本体 | 手绘 SVG 鲸鱼娘(头枕双手、鲸尾上翘、头顶喷水孔),趴姿贴框 | | 🌀 灵动动效 | 呼吸起伏、尾巴摇摆、胸鳍扑扇、双马尾/侧发飘动、周期眨眼 + 双连眨、腮红脉动、头顶喷泉(约 9s 一次)、泡泡上飘、星星闪片 | | 💬 对话联动 | 检测到 DSH 工作时掏出小电脑 + 冒汗打代码;思考时歪头「o」嘴;成功时蹦跳庆祝;报错时掉眼泪安慰 | | 🎧 偷听打字 | 你在输入框打字时她会竖起耳朵(倾听嘴型 + 歪头),偶尔搭话 | | 🖱️ 互动 | 单击:脸红台词 + 爱心/星星飞出;三连击:星星眼 + 蹦跳庆祝;拖拽:被拎起来身体随方向倾斜,松手弹回对话框;右键/齿轮菜单 | | 😴 陪伴细节 | 安静 3 分钟自动打盹(闭眼 + Zzz + 慢呼吸),睡 40 秒自己醒来;每 50–110 秒主动闲聊;深夜安静时段(23:00–07:00)不闲聊、睡醒不吵你,安静 1 分钟就乖乖睡着 | | ⚙️ 菜单 | 贴回对话框 / 自由摆放 / 放大缩小 / 睡一会儿 / 躲起来(右下角 🐋 按钮可找回)/ 说句话 / 关于 | | 🧩 工程 | 纯前端 DOM 注入,不改 DSH 业务 DOM;`localStorage` 保存偏好(`whale-lap:*`);支持 `prefers-reduced-motion` | ## 🆕 更新日志 - **v1.1.0** - 🌙 深夜安静时段正式落地(此前仅 README 宣称):23:00–07:00 不主动闲聊、睡醒不打招呼、安静 1 分钟自动打盹; - 🔁 修复资源加载失败后永不重试的问题:`lib/client.js` 改为注入成功后才置位启动标记,失败按 1.2s 退避重试最多 6 次,CSS/JS 并行加载; - ⚡ 性能优化:三个 `setInterval` 合并为单 tick(按各自节奏调度);滚动/缩放重排改 rAF 节流;可见性判断优先用 `checkVisibility`(比 `getComputedStyle` 便宜得多); - ⌨️ 支持 Esc 关闭菜单;齿轮按钮/找回按钮补充 `aria-label`; - 🧪 冒烟测试新增深夜模式覆盖;demo 页新增「🌙 深夜模式」开关(写 `whale-lap:nightDemo`)。 - **v1.0.0** 首个版本:手绘 SVG 鲸鱼娘 + 全套动效 + DSH 状态联动 + 互动/菜单/打盹。 ## 🖼️ 先看效果(无需安装) 直接双击打开 [demo.html](./demo.html)——一个模拟 DSH 的离线预览页,鲸鱼娘会立刻趴到模拟输入框上,右上角按钮可模拟「工作 / 思考 / 成功 / 报错」。 ## 📦 安装(bundle 组合包,零侵入) ### 方式 A:GitHub 远程安装(推荐) ```powershell dsh plugin --profile web add github:Linzr-lly/dsh-whale-lap ``` ### 方式 B:本地目录 ```powershell # 在插件目录的上一级执行 dsh plugin --profile web add ./whale-girl-plugin ``` 安装后重启 `dsh web`,打开页面(默认 `http://127.0.0.1:3080`)并**强制刷新** `Ctrl + F5`,鲸鱼娘就会趴到对话框上沿。 ### 验证 - 点她:脸红 + 台词 + 爱心;连点三下:星星眼庆祝; - 按住拖动:被拎起来跟着光标摇摆,松手弹回对话框; - 让 DSH 跑一个工具:她掏出小电脑进入工作模式; - 在输入框打字:她歪头偷听。 ## 🎮 使用说明 | 操作 | 效果 | | --- | --- | | 单击 | 随机台词 + 爱心/星星粒子,短暂开心 | | 连点 3 下 | 星星眼 + 蹦跳 + 粒子庆祝 | | 按住拖动 | 「被拎起来」,身体随移动方向倾斜;松手弹回对话框(自由位置已记忆) | | 右键 / 齿轮 ⚙ | 菜单:贴回对话框、自由摆放、放大/缩小、睡一会儿、躲起来、说句话、关于 | | 输入框打字 | 倾听状态(歪头 + o 嘴),偶尔搭话 | | 长时间没动静 | 自动打盹(Zzz),睡醒元气满满 | ## 📁 项目结构 ```text whale-girl-plugin/ ├─ package.json # DSH 插件声明(dsh.bundle + dsh.client) ├─ cordis.patch.yml # 组合包 patch:插入 dsh-whale-lap ├─ lib/ │ ├─ index.js # 宿主半边:/api/dsh-whale-lap/assets 静态资源路由 │ └─ client.js # 浏览器半边:注入样式 + 表现层 ├─ assets/ │ ├─ whale-girl.svg # 手绘鲸鱼娘(唯一美术资产,动画全在 CSS) │ ├─ whale-lap.css # 全部动效(呼吸/摇尾/眨眼/喷水/泡泡/Zzz…) │ └─ whale-lap.js # 贴框定位、状态联动、拖拽、互动、台词 ├─ demo.html # 离线预览页(双击即看效果) ├─ test/ # 自动化验证(真实浏览器 CDP 验收) │ ├─ smoke.mjs # Node DOM-stub 冒烟测试 │ ├─ server.mjs # 本地静态服务器(预览/测试用) │ ├─ cdp-shot.mjs # CDP 截图 + 运行时状态读取 │ ├─ cdp-state.mjs # 状态联动验收(工作/报错/单击) │ ├─ cdp-night.mjs # 深夜安静时段验收 │ ├─ cdp-final.mjs # 动画/倾听/拖拽弹回验收 │ ├─ e2e-dsh.mjs # 真实 DSH 页面集成验收(需 dsh web 在 3080) │ └─ shot-cdp.png # 验收截图(趴在对话框上沿) └─ README.md ``` ## ✅ 自动化验证 ```powershell # 1) 冒烟测试(无浏览器,Node 18+) node test/smoke.mjs # 2) 真实浏览器验收(需要 Edge/Chrome) node test/server.mjs 8899 # 起本地静态服务器 msedge --headless --disable-gpu --no-sandbox --remote-debugging-port=9222 --user-data-dir=%TEMP%\wl-edge about:blank node test/cdp-shot.mjs # 截图 + 运行时状态 node test/cdp-state.mjs # 工作/报错/单击联动 node test/cdp-night.mjs # 深夜模式安静时段 node test/cdp-final.mjs # 动画/打字倾听/拖拽弹回 # 3) 真实 DSH 集成验收(需要先启动 dsh web,如 dsh --profile web --port 3080) node test/e2e-dsh.mjs # 在真实 DSH 页面确认鲸鱼娘 v1.1.0 唤醒并贴框 ``` 已通过的验收项:贴框坐标像素级精确(下沿压进对话框上沿 15px)、尾巴/泡泡/喷泉/眨眼动画生效、工作中掏出小电脑、报错掉眼泪、打字触发倾听、拖拽跟随并在松手后弹回对话框。 ## 🔧 工作原理 1. `cordis.patch.yml` 把 `dsh-whale-lap` 插入 profile; 2. 宿主侧 `lib/index.js` 注册只读静态路由 `/api/dsh-whale-lap/assets?f=`; 3. 浏览器侧 `lib/client.js` 经 `window.__ModuleLoader__` 加载,注入样式与表现层; 4. 表现层 `whale-lap.js` 取回 SVG **内联**进页面(内联后 CSS 动画才能作用于 SVG 元素),用 `[data-composer-card="true"]` / `[data-slot="conversation.composer.bar"]` 定位对话框,把她的身体下沿压进对话框上沿 15px,实现「趴在上面」; 5. 轮询 DSH 状态信号(`data-running` / `data-state="ongoing"` / `loading` / `success` / `error`)联动表情台词。 ## 🗑️ 卸载 ```powershell dsh plugin --profile web remove dsh-whale-lap ``` 或在浏览器 `localStorage` 中删除 `whale-lap:*` 键后刷新页面。 ## 🔒 数据与隐私 - 偏好(模式/大小/位置/隐藏)存于浏览器 `localStorage`,键名 `whale-lap:*`; - 不发送遥测、不访问外部网络、不读取 DSH 会话数据; - 全部资源本地加载,安装无需修改任何内置包文件。 ## 🐳 **鲸鱼娘陪你写代码,也陪你摸鱼。**