DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
W

dsh-whale-maid

Whale Maid

适用于 DeepSeek Harness 的鲸鱼女孩桌面宠物:十二种精灵动画、工作状态联动、成长、成就和天气伙伴。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:lov0vo/dsh-whale-maid#d3f77231faa4370acb3491fb4a20d53908873543
README兼容性版本
预览:idle / joy / sleep / walk 四个姿态

兼容性与来源证明

Whale Maid 以 dsh-whale-maid 发布,当前版本为 2.3.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/10/27

版本

2.3.0stable
2026/10/27
2.1.1stable
2026/10/27
2.0.1stable
2026/10/26
查看其余 4 个版本收起版本
1.9.0stable
2026/10/26
1.4.0stable
2026/10/26
1.2.2stable
2026/10/26
1.1.0stable
2026/10/25

相关插件

正在加载相关插件…

最新版
2.3.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 1
周下载
0
最近提交
2026/10/27
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 ui-customization 分类下经过校验的插件。

Client Ui Skill Explorer@linxin666/dsh-client-ui-skill-explorerDSH 技能中心:按来源(bundled / project / user / custom / runtime)浏览已加载的技能,在 Web GUI 面板中启用或禁用、创建和删除技能。Client Ui Task Board@linxin666/dsh-client-ui-task-board面向 DSH Web GUI 的主机权威任务面板,支持实际会话执行、主机 cron 调度以及可选的跨平台空闲睡眠保护;以挂载方式提供,无需修改 DSH 源代码。Client Ui Git Graph@linxin666/dsh-client-ui-git-graph外部 dsh Web GUI 插件:空会话 Git 分支选择器和 Git 图,包含实际的主机端 Git 操作与防护,作为 dsh 配置文件包Client Ui Market@linxin666/dsh-client-ui-marketWorkshop 浏览卡片:浏览来自 dsh-market.com 的皮肤、宠物和社区插件,并在 GUI 中安装(资源安装到 DSH 主目录,插件通过可选的插件管理器安装)。

README

dsh-whale-maid

把 DeepSeek 插件市场页面右下角那只鲸鱼女仆完整提取出来,做成 DSH(DeepSeek Harness)的桌面宠物插件。

不是一张静态图片:10 组精灵图集 + JS 状态机,眨眼、欢呼、吃东西、玩耍、思考、入睡、醒来、左右漫步、拖动摇摆全部保留。

从 1.1.0 起,她还会跟着你的工作状态变姿势、记心情与好感、每天签到、解锁成就、在你久坐或深夜时主动说一句——这些是在原版提取之上新增的陪伴层,原有动作与交互一个没改。

预览:idle / joy / sleep / walk 四个姿态


功能

  • 十二状态精灵动画:idle(含随机眨眼)、joy、eat、play、welcome、drag(拖拽摇摆)、think(浮动 + 问号)、work(敲全息面板)、sad(垂头丧气)、sleep(打呼噜)、wake、walk(乒乓漫步)
  • 交互:单击问候并展开菜单、按住拖动换位置、喂小鱼干(每 5 条触发里程碑台词)、陪它玩耍、爱心飘出
  • 自动行为:空闲 15–35 秒思考一次、25–45 秒随机漫步一次、60 秒无交互后入睡、点击唤醒
  • 位置记忆:拖动后的位置写进 localStorage,重开仍在原处
  • 跟随主题:气泡、菜单按钮用 DSH 主题 token(--dsw-alias-*),深色/浅色主题都自适应
  • 设置面板:设置 → 鲸鱼女仆,可调显示形态、尺寸、动画速度、气泡停留时长、气泡打字机、气泡语言,以及问候/漫步/睡眠开关
  • 零运行时依赖:不装任何 npm 包,不发任何网络请求,不读写文件系统

2.3.0 新增:五种显示形态 + 键盘互动

  • 显示形态(五种):设置 → 鲸鱼女仆 → 显示形态 里切换。
    • 悬浮(默认):原来的自由摆放,可拖动、会自己散步。
    • 底栏:贴在输入框上方、靠右对齐,96px。
    • 侧边:挂在聊天栏右缘、略高于中线,72px。
    • 迷你:56px 小号版,菜单按钮同步缩小,仍可拖动。
    • 自动:有输入框时按「底栏」摆放,没有输入框(例如设置页)时回到悬浮。
  • 锚点消失会回落,不会消失:底栏/侧边每 800ms 以及窗口 resize、滚动时重新测量锚点;找不到锚点时回落到悬浮。参考插件在这种情况下直接把宠物 display:none,是它最常见的「宠物不见了」反馈。
  • 底栏/侧边不拖动、不散步:它们锚在宿主元素上,拖动会在下一个测量周期被拉回。点击、喂食、玩耍、分区反应照常。
  • 键盘互动:宠物是可 Tab 聚焦的按钮(带可见焦点环),聚焦后按数字键 1–9 依次摸「呆毛 / 耳朵 / 脸 / 头 / 腰 / 手 / 肚子 / 尾巴 / 脚」。此前这九个部位只能用鼠标点。
  • 尺寸按形态生效:显式设置的 size 仍然优先于形态默认值。

1.1.0 新增:陪伴层

  • 工作状态联动:观察宿主 DOM,判断「思考中 / 工具运行中 / 刚成功 / 刚失败」,自动切到 think 姿态并在宠物左侧冒出状态小标签(如「工具在跑…」「搞定啦」)。工作期会说话,收尾会欢呼或安慰;关掉对话视图后仍在跑的任务用宽限期兜住,不会一秒三变。
  • 成长系统:心情 / 饱食 / 好感 / 等级 / 陪伴时长 / 连续签到,全部只写本机 localStorage。心情随工作与互动涨落,饱食随时间下降。
  • 每日任务:三槽随机(散步、玩耍、摸头、投喂…),完成后在设置页领取奖励。
  • 成就墙:41 项成就(摸头 1/10/50、投喂、工具 1/10/50/200、代码、成功/失败、深夜、回归、陪伴天数、等级、签到、对话…),解锁即写成长日记。
  • 分区点击:点头顶 / 肚子 / 尾巴给不同反应与不同粒子;1.2 秒内三连击触发庆祝。
  • 主动关怀:久坐 25 分钟、卡住 8 分钟、深夜 23:00–5:59、饿肚子、离开后回来,各有专属台词;最小间隔 15 分钟,不啰嗦。
  • 主动闲聊:5–8 分钟一次,按话题(代码 / 报错 / 测试 / 部署 / 设计 / 文档 / 吃什么 / 困了…)挑不同的话。
  • 关键词反应:13 组关键词(谢谢、可爱、摸鱼、加油、好累、崩了、哈哈…)触发对应姿态、粒子与台词。
  • 状态小标签与粒子层:芯片式标签 + 爱心 / 星星 / 闪光 / 音符四类粒子,全部走独立图层,不抢气泡。

1.3.0 新增:天气陪伴 + 十二个动作全部会动

动作:drag / think / work / sad 原本只有一帧(靠 CSS 整图运动假装在动),现在各补成 3 帧——用原图按「缩放 1.00→1.02、上下 2px、旋转 ±1°」生成的伪帧,锚点固定在脚底中心,所以角色是在呼吸而不是在飘。十二个状态全部有逐帧动画,没有为动画新生成任何美术。

天气陪伴(工程部分):

  • 启动拉一次,之后每 30 分钟刷新,跨天(每分钟检查日期变化)额外刷新,窗口重新可见且缓存过期时也会补一次;
  • 只用 Open-Meteo 免费接口、无需 key:geocoding-api.open-meteo.com 把城市名转经纬度,api.open-meteo.com 取当前天气;
  • 缓存 + 离线降级:失败沿用上次结果;超过 6 小时不再播报天气台词(姿态也不换);
  • 失败重试指数退避:1 分钟 → 5 分钟 → 15 分钟,最多 3 次;
  • 设置面板「鲸鱼女仆」里有 天气陪伴 区块:显示「城市 · 天气 · 温度」,可改城市,有 刷新天气 按钮;
  • 纯 fetch 单向拉取,无账号、不上传任何本地数据(只把城市名/坐标发给你请求的那个公开接口)。

天气陪伴(体感部分):

  • 天气 → 姿态:晴 → joy、多云/雾 → think、雨/雪/雷 → sad(撑伞、缩脖子、发抖、流汗这四种专属姿态需要新美术,暂缓,见下);
  • 天气 → 台词:7 个中文台词库共 63 条(晴/多云/雨/雪/雷/雾/雨夜,各 9 条);
  • 天气 → 粒子:雨、雪复用现有粒子层(☔ / ❄),晴天撒阳光星屑,不新增气泡;
  • 深夜 + 下雨优先播 雨夜 台词;
  • 天气变化(例如晴转雨)会主动说一句,同一天同一天气只主动说一次。

城市:先试系统定位(8 秒超时),失败则用设置里的城市名(默认 北京)。两条路径都可用,城市随时可改。

1.3.0 暂缓项(都需要新美术,按约定本轮不生成):

项卡在哪一步
雨 → 撑伞需要 rain-umbrella 立绘
雪 → 缩脖子需要 snow-hunch 立绘
雷 → 害怕需要 thunder-scared 立绘
冷/热 → 发抖/流汗需要 cold-shiver / hot-sweat 立绘
19 个新姿态的静态立绘已生成 2/31(success、celebrate),其余待生成

以上暂时用现有姿态(sad / think / joy)代偿,等美术补齐后再替换。

1.4.0 新增:工程与体感(不依赖生图的那一批)

这一版把「四批计划」里所有不需要新美术的项做完了,外加存档导出/导入。

项做了什么
engines.dshpackage.json 声明 ">=0.2.1-rc.1",装到过旧的宿主上会提前报错,而不是在渲染时神秘失败
CI.github/workflows/ci.yml:Node 20/22/24 上 node build.mjs + 构建产物一致性检查 + node --test
无障碍宠物可 Tab 聚焦;Enter/Space 打招呼;Alt+↑↓←→ 每次移动 16px 并持久化位置;:focus-visible 有描边
心情分层由 2 档扩到 5 档(moodLow / moodLowMid / moodMid / moodHighMid / moodHigh),moodTier() 返回 0–4
成就41 → 55 条(等级、连续签到、台词、陪伴时长、天气、错误率等)
工作期光晕工作相位时在精灵下方加一层呼吸光晕(.dwm-glow),prefers-reduced-motion 下关闭
台词546 → 600 条(每语言),新增心情 5 档与更多工作/关怀分支
唤回入口宠物隐藏后右下角留一个 🐋 按钮,点一下回来(hidden 开关)
locale 服务locale/zh.json / locale/en.json 改为 gettext 风格(键=中文原文,43 条),设置面板文案可被翻译
结构快照测试test/snapshots/pet-tree.txt 记录浮层元素树;另有「源码里用到的每个 dwm- 类都必须有 CSS 规则」检查
存档导出/导入设置面板「存档」区块:导出 JSON / 导入 / 清空,覆盖全部 dsh-whale-maid:* 键

测试数 28 → 34,全部通过。client.js 约 3.1 MB。

1.2.2 修复

  • 点击后桌宠消失(1.2.1 回归):打字机气泡组件用到的 React hook 别名声明在组件内部、模块作用域不可见,渲染气泡时抛 ReferenceError 并导致整个浮层槽位被卸载。已把别名提升到模块作用域,并加了静态回归测试。
  • 气泡折行过窄:.dwm-pop 改为按内容宽度布局(上限 250px)。

1.2.1 修复

  • 走动卡住:散步被工作状态检测打断时,角色会停在走动帧上不再移动。现在中止散步会回到 idle。
  • 一次点击两个气泡:分区反应(头/肚子/尾巴)改走对话气泡,不再和点击问候同时出现;同一次点击只说一句话。
  • 打字机效果:气泡文字逐字显示(typewriter,默认开启,设置面板可关)。

1.2.0 新增:专属工作 / 沮丧姿态

1.1.0 里工作状态是「借图」实现的:工具在跑时借 play(举球),失败时借 drag(拖拽摇摆)。语义对不上,所以 1.2.0 补了两张专属姿态,其余十张原样保留:

  • work(敲全息面板):工具运行中(preparing / running)与「正在执行」相位显示。双手抬在胸前敲一块半透明浅蓝全息面板,头微低、视线落在面板上、眉心微蹙,带 float 呼吸浮动。
  • sad(垂头丧气):工具报错、任务失败、心情触底时显示。垂肩、双手在身前交叠、头略低并微微侧倾、上眼睑下垂、眉心内侧上挑、嘴角下撇,太阳穴旁一滴汗。
  • 映射变更:tool → work、failure → sad;成功相位继续用 joy(语义本来就对)。会话结束时不再播放 drag,改为播放 sad。
  • 降级行为不变:宠物未挂载时,信号层仍会通过 dwmPlaySequence 把姿态写进 dsh-whale-maid:state 事件,只是没人渲染。

这两张图的画风、配色、2.5 头身比例、线宽、脚底基线与原有十张完全对齐(角色高 225px、脚底贴 y=256、水平中心 x=128),可以直接换用你自己的角色图,见「换成你自己的角色」。

安装

DSH 桌面端的插件分两半:index.js(Host 半边,空实现,只为让 Loader 挂载包)和 client.js(浏览器半边,宠物本体)。安装即「让 profile 挂上这个 bundle」。

方式 A:用内置插件管理器(若你的 DSH 版本提供 plugin_manager 工具)

action: install_bundle
target: <本仓库的绝对路径>

方式 B:手工写进 profile(通用)

  1. 把整个仓库目录放到 C:\Users\Administrator\.dsh\plugins\dsh-whale-maid(目录名要与 package.json 的 name 一致)。
  2. 编辑 profile 的 package.json(C:\Users\Administrator\.dsh\profiles\desktop\package.json):
    • dependencies 里加 "dsh-whale-maid": "file:C:/Users/Administrator/.dsh/plugins/dsh-whale-maid"
    • dsh.profile.bundles 数组里加 "dsh-whale-maid"
  3. 让包出现在 profile 的 node_modules 里(复制目录,或在该 profile 下跑一次 pnpm install)。
  4. 重载窗口(Ctrl+R)。profile 的 dsh.profile.patchReload 为 live 时,改 client.js 后刷新即生效,不用重启应用。

二选一:dsh.profile.bundles 列表和 cordis.patch.yml 的 insert 是两条并行的挂载路径。同时用会让同一个 row id 被挂两次,出现两只宠物。手工安装时只选其中一种。

停用 / 卸载

  • 停用:从 dsh.profile.bundles 移除 dsh-whale-maid(或在该 bundle 的 patch 行上加 disabled: true),重载窗口。
  • 卸载:停用后删除 plugins\dsh-whale-maid 与 profile 的 node_modules\dsh-whale-maid,再清掉 package.json 里的依赖项。

使用

操作效果
单击随机说一句问候,展开「喂食 / 玩耍」菜单
按住拖动跟着指针走,身体按指针相对位置倾斜(最多 ±10°),松手落位并记忆
喂食(🐟)冒爱心,播放吃东西动画;feeds % 5 === 0 时触发里程碑台词
玩耍(🎮)冒爱心,播放抛接球动画
点空白 / Esc关闭菜单
长时间不操作60 秒后趴下睡觉;点击会先播「醒来」再「欢呼」
点不同部位9 个命中区各自的台词 + 粒子(心 / 闪光 / 音符),见下方「部位互动台词」
1.2 秒内连点三次三连击庆祝(星星 + 爱心 + 专属台词)

宠物会自己走动,所以位置不总是右下角——这是原始行为。

部位互动台词(可点击部位)

可点击区按立绘量过,共 9 个。命中矩形写在 src/zones.js 的 DWM_ZONES 里,坐标归一化到精灵帧(0–1),所以宠物放大缩小都点得准;列表从上到下先命中先返回,窄部位排在包住它的大块之前。一个矩形都没命中时回落到 belly。

区 id部位矩形数台词库(新 + 原)
horn呆毛1patHorn + patHead
ear鳍耳2(左右)patEar + patHead
face脸1patFace + patHead
head头 / 头发3(发饰带 + 两侧长发)patHeadPart + patHead
waist腰(腰带)1patWaist + patBelly
hand手2(左右)patHand + patBelly
belly围裙 / 腹1(默认区)patBellyPart + patBelly
feet脚1patFeet + patBelly
tail鲸尾1patTailPart + patTail

台词库分三处,互不覆盖:

  • 每个区自己的新库在 src/lines-parts.js(DWM_LINES_PARTS,9 个库,每库 14 条中文 + 6 条英文,合计 180 条);
  • 原有的 patHead / patBelly / patTail 仍留在 src/lines.js,一句没删;src/lines-parts.js 末尾把新库 concat 进 DWM_LINES,所以是追加,不是替换;
  • 区 → 库的映射是 src/zones.js 的 DWM_ZONE_BANK,值现在是数组,由 dwmPickLineFrom(banks, language) 把几个库并成一个池子随机抽,并避开上一次抽到的那条。

口径:鲸鱼女仆对主人说话,可以 teasing、可以暧昧,但不写露骨内容;每句最多一个 emoji,中文台词不带 emoji(与原版一致)。

配置

设置页:设置(Ctrl+,)→ 左侧「鲸鱼女仆」。改动即时生效,存在 localStorage['dsh-whale-maid:options']。

键类型默认说明
sizenumber | nullnull像素尺寸 24–320;null = 响应式(桌面 110px,窄屏 72px)
speednumber1动画与漫步速度倍率 0.2–3
bubbleDurationnumber4500气泡停留毫秒数 1000–10000
typewriterbooleantrue气泡文字逐字显示(false = 整句直接出现)
citystring'北京'定位失败时用于查天气的城市名(1.3.0)
mode'float' | 'bar' | 'side' | 'mini' | 'auto''float'显示形态(2.3.0);底栏 96px、侧边 72px、迷你 56px,显式 size 优先
language'auto' | 'zh' | 'en''auto'气泡文案语言,auto 跟随界面
greetingbooleantrue首次打开是否主动打招呼
walkbooleantrue是否允许随机漫步
sleepbooleantrue是否允许空闲入睡
greetingsstring[] | nullnull自定义问候语池,null 用内置文案

陪伴开关(1.1.0)

设置页:设置(Ctrl+,)→ 左侧「鲸鱼女仆」。存在 localStorage['dsh-whale-maid:companion']。

键类型默认说明
workLinkbooleantrue是否跟随工作状态换姿态(关掉后她只做原版的 idle 生活)
workHoldnumber6000切走对话视图后的宽限毫秒数,避免后台任务被误判结束
workSpeech'chatty' | 'quiet' | 'off''chatty'工作期说话频率:话痨 15–40s / 安静 90–240s / 不说
idleChatbooleantrue是否 5–8 分钟主动闲聊一次
carebooleantrue主动关怀(久坐 / 卡住 / 深夜 / 饿了 / 回来)
chipbooleantrue是否显示宠物左侧的状态小标签
zonesbooleantrue是否启用分区点击反应
achievementsbooleantrue是否记录成就与成长日记
lateNightbooleantrue深夜(23:00–5:59)是否安静一点

这些开关只影响陪伴层。关掉全部开关后,宠物的行为与 1.0.0 完全一致。

公开 API

1.4.0 追加四个方法:

  • exportSave() → 返回存档 JSON 字符串({ schema: "dsh-whale-maid/save", version: 1, data: {...} })
  • importSave(text) → { ok: true } 或 { ok: false, reason: "not-json" | "wrong-schema" | "wrong-version" }
  • clearSave() → 清空本插件全部存档键
  • moodTier() → 当前心情档位 0–4

渲染进程里可用 window.dshWhaleMaid:

dshWhaleMaid.getOptions()                  // 当前配置
dshWhaleMaid.setOptions({ speed: 1.5 })    // 合并写入并广播
dshWhaleMaid.say('自定义台词')              // 让宠物说一句
dshWhaleMaid.resetPosition()               // 回到右下角
dshWhaleMaid.feeds()                       // 已投喂数量
dshWhaleMaid.forget()                      // 清空全部存储(位置/投喂/配置/成长/陪伴开关)

1.1.0 追加(原有方法签名一个未改):

dshWhaleMaid.companion()                   // 陪伴开关快照
dshWhaleMaid.setCompanion({ chip: false }) // 改开关
dshWhaleMaid.growth()                      // 等级/心情/饱食/好感/任务/成就/日记快照
dshWhaleMaid.signin()                      // 今日签到(已签返回 null)
dshWhaleMaid.claimQuest(0)                 // 领取第 1 个已完成任务
dshWhaleMaid.resetGrowth()                 // 清空成长数据
dshWhaleMaid.work()                        // 工作状态探测器当前判断
dshWhaleMaid.scanNow()                     // 立刻重扫一次 DOM(排查用)
dshWhaleMaid.diagnose()                    // 上面全部 + 当前姿态/帧,一次性 dump
dshWhaleMaid.zoneAt(0.85, 0.7)             // 归一化坐标落在哪个区('tail')
dshWhaleMaid.probe('今天写了好多代码')      // 这句话会被判成什么话题 / 命中哪个关键词
dshWhaleMaid.chip('工具在跑…', 'work', 3000)// 手动弹一个状态小标签
dshWhaleMaid.fx('star', 6)                 // 手动撒粒子:heart / star / sparkle / note
dshWhaleMaid.pose('joy', 1500)             // 强制某个姿态(hold=true 则一直保持)

1.3.0 追加:

dshWhaleMaid.weather()                     // 缓存的天气记录(无则 null)
dshWhaleMaid.refreshWeather()              // 立刻重新拉一次(同面板按钮)
dshWhaleMaid.setCity('上海')                // 改备用城市并立即刷新

2.3.0 追加:

dshWhaleMaid.modes()                       // 形态清单 + 锚点选择器 + 纯函数几何计算(可在无 DOM 环境断言)

姿态资源(27 姿态对照)

参考插件按「姿态名」组织立绘,本插件按「状态」组织精灵表。为了让两边能对上,下表把 27 个姿态逐一映射到本插件的图片来源。

姿态图片来源说明
idle精灵表 idle.png3 帧待机
waitingsrc/sprites/poses/waiting.png独立立绘
thinking精灵表 think.png3 帧(伪帧)+ 浮动
tool精灵表 work.png3 帧(伪帧)+ 浮动
successposes/success.png独立立绘(早前借 joy)
failure精灵表 sad.png3 帧(伪帧)
curious / teasing / afk / blush / angry / starposes/<名字>.png独立立绘
eat精灵表 eat.png3 帧
celebrateposes/celebrate.png独立立绘(早前借 joy)
sleep精灵表 sleep.png2 帧
greet精灵表 welcome.png2 帧
night / wink / bold / abstract / sweepposes/<名字>.png独立立绘
workSlack / workRam / coolShades / workPat / balanceLowposes/<名字>.png独立立绘
hidden——参考插件里是 null,本插件用 hidden 开关 + 🐋 唤回按钮实现

src/sprites/poses/ 里的 19 张已生成、抠图、归一化到与精灵帧完全相同的规格(角色高 225px、脚底贴 y=256、x=128 居中),并由 src/pose-map.js 的「场合 → 姿态」映射表接进状态机(详见下文「场合 → 姿态映射」)。每个文件现在是 768×256 的三格横排,循环播放方式见「立绘的 3 帧循环」。

动作表

状态精灵图帧数fps播放方式触发
idleidle.png32blink(随机眨眼)默认待机
joyjoy.png25loop点击、动作收尾
eateat.png38loop喂食
playplay.png34loop玩耍
welcomewelcome.png23loop首次问候
dragdrag.png35loop + tilt拖动中(1.3.0 起 3 帧伪帧)
thinkthink.png32loop + float空闲思考(1.3.0 起 3 帧伪帧)
workwork.png32loop + float工具运行中(1.2.0 加姿态,1.3.0 起 3 帧)
sadsad.png32loop工具报错 / 任务失败(1.2.0 加姿态,1.3.0 起 3 帧)
wink眨眼12loop
sleepsleep.png21loop空闲 60s
wakewake.png23once睡眠中被点击
walkwalk.png36ping-pong随机漫步

立绘的 3 帧循环

src/sprites/poses/ 里的 19 张姿势立绘不再是单张静止图:每个文件现在是 768×256 的横排三格,每格 256×256,与原精灵帧同规格。

  • 三帧由原来那张单图生成,用的是 drag / think / work / sad 已经用过的伪帧配方:缩放 1.00 → 1.02、纵向偏移 0 → −2px、旋转 −1° → +1°,锚点固定在脚底中心,所以脚不会飘。
  • 生成脚本过去是包外的 _tmp/whale-gen/pseudo_poses.py(不随包发布);2.1.0 起这 19 张已改成逐帧真重绘,那条伪帧配方只留作历史。现在的管线在仓库里:tools/art/,见 tools/art/README.md。
  • 播放不靠 JS 定时器:@keyframes dwm-pose-cycle 以 background-size: 300% 100% 把 background-position 依次走到 0% → 50% → 100%,每轮 0.9 s,再与原有的 dwm-portrait-float 浮动叠加。prefers-reduced-motion 下整段动画关掉,并钉在第 0 帧。
  • 渲染器 dwmPortraitShow(src/runtime.js)现在建的是带背景图的 div[data-dwm-portrait],不再是 <img>;该层 pointer-events: none、z-index: 60,不会吃掉点击或拖动。

目录结构

dsh-whale-maid/
├── index.js              Host 半边:空 apply,只为让 Loader 挂载并暴露 dsh.client
├── client.js             浏览器产物(约 313 KiB,由 build.mjs 生成,勿手改)
├── cordis.patch.yml      手工安装用的 insert 行
├── package.json          清单:exports / files / dsh.bundle / dsh.client
├── build.mjs             构建脚本:校验 PNG 尺寸 → 复制到 assets/ → 拼 client.js
├── tools/
│   ├── art/                  美术管线(生图 → 抠图 → 拼表 → 修帧序 → 质检),见 tools/art/README.md
│   └── asset-qc.mjs          资源质检,`npm run qc` 调它
├── src/
│   ├── care.js               13 KB
│   ├── fx.js                 3 KB
│   ├── growth.js             25 KB
│   ├── lines-mood.js         3 KB
│   ├── lines-more.js         37 KB
│   ├── lines-parts.js        9 KB
│   ├── lines-weather.js      5 KB
│   ├── lines.js              21 KB
│   ├── locale-table.js       10 KB
│   ├── panel.js              19 KB
│   ├── pet.css               23 KB
│   ├── pet.js                42 KB
│   ├── plugin.js             8 KB
│   ├── portable.js           4 KB
│   ├── pose-map.js           3 KB
│   ├── preview.js            3 KB
│   ├── runtime.js            15 KB
│   ├── settings.js           7 KB
│   ├── signals.js            15 KB
│   ├── weather-ui.js         4 KB
│   ├── weather.js            18 KB
│   ├── zones.js              7 KB
├── assets/preview.png    README 预览图(由精灵图合成,非界面截图)
├── CHANGELOG.md
├── LICENSE               MIT(仅代码)
└── README.md

重新构建

node build.mjs

产物写入 client.js。构建时会校验每张精灵图的像素尺寸是否等于 帧数 × 256,尺寸不符直接失败——防止放错图导致画面错位。

build.mjs 按固定顺序把 src/ 下的脚本拼进同一个闭包(runtime → lines → lines-more → lines-mood → lines-weather → lines-parts → growth → fx → portable → pose-map → preview → pet → settings → panel → weather → weather-ui → locale-table → signals → care → zones → plugin),所以它们之间可以直接互相调用函数声明,但不能写 import / export(构建会直接报错)。

测试

node --test test/companion.test.mjs

测试不是 mock 组件,而是把真实的 client.js 载进一个 stub DOM(window / document / localStorage / MutationObserver / requestAnimationFrame + React stub),跑真实的 apply(ctx),再通过公开 API 驱动。覆盖:三个 slot 注册、样式注入与清理、1.0.0 API 默认值不变、陪伴开关持久化、成长快照形状、签到幂等、任务领取门禁、工作状态机(含宽限期与错误基线)、forget 清键、所有 effect 的 disposer 不抛。

资源质检

npm run qc          # 等价于 node tools/asset-qc.mjs,零依赖,CI 在 node build.mjs 之后跑

六项检查,任一失败即退出码 1:帧表——每张精灵图是否等于 build.mjs 里 SHEETS 声明的 帧数 × 256,少文件或多出未声明的图都算错;立绘——poses/*.png 是否都是 768×256,pose-map.js 要用的姿态有没有图或可用的回退动作;墨迹——每帧是否贴底(y≥254)且水平居中(128±12),帧高差 ≤2px(手绘原稿 ≤4px);绿幕——有没有残留的 chroma-key 绿像素(每帧上限 4);独立性——相邻帧剪影 IoU 是否过高(同一张图冒充动画,>0.985)或过低(画串了,<0.30);一致性——assets/ 是否与 src/sprites/ 逐字节相同,防止改了图忘记重新构建。

重新生成美术

src/sprites/ 里的帧不是手绘的:由 tools/art/ 下的一套脚本从绿幕生图抠出来、归一化、拼表。管线顺序、归一化契约、质量闸门和授权说明都在 tools/art/README.md。

最短路径(python 换成你的解释器,Windows 上可能不在 PATH 里):

# 1. 改 tools/art/jobs.example.json(或另写一份),先看计划:不联网、不写盘
python tools/art/gen.py tools/art/jobs.example.json --dry-run
# 2. 真跑:提交 → 轮询 → 抠图 → 拼表
python tools/art/gen.py tools/art/jobs.example.json
# 3. 修帧序与点击配准表,再质检
python tools/art/fix_anim.py --dry-run && python tools/art/fix_anim.py
python tools/art/qc_look.py && python tools/art/audit_assets.py
# 4. 重新构建
node build.mjs

只有 gen.py 需要联网与密钥(DSH_CREDENTIALS 或 --credentials);不想调生图模型的话,自己画好 256×256 的帧交给 compose_frames.py 和 fix_anim.py 就行。注意 fix_anim.py 会改写 src/zones.js 里的 DWM_HIT_REG 块,跑完看一眼 git diff。

与 dsh-whale-musume 的关系

1.1.0 的陪伴层是参考 Sutera-Diffusus/dsh-whale-musume 的功能行为做的,仅此而已:

项目情况
参考了什么功能清单与交互范式:忙闲联动、心情/好感/饱食、每日任务、签到、成就、分区点击、主动关怀、话题闲聊
没参考什么它的代码、立绘、台词、数值表。台词全部为本仓库原创撰写,立绘仍是原站那 10 组精灵图
没有照搬的能力五种形态切换(悬浮/侧栏/底栏/迷你)、拖拽惯性物理、TTS 播报、天气陪伴、三个小游戏、跨端存档迁移——见下方「未纳入的功能」
素材授权参考插件是 MIT,但其立绘不适用;本仓库不引入它的任何素材,故不受其影响

未纳入的功能(及原因)

功能为什么不加
五种形态切换(悬浮/侧栏/底栏/迷你/自动)要改 shell.overlay 的定位模型与现有拖拽落位逻辑,属于改既有行为,超出「只增不改」的边界
拖拽惯性物理、边缘抓住同上,会重写现有 pointer 三件套
TTS 播报依赖第三方 dsh-xiaomi-tts 插件,装了才有声音;无依赖原则下不做
天气陪伴(Open-Meteo)需要联网请求,与「零网络」冲突
三个小游戏需要新美术与计分 UI,工作量与素材风险都大
跨端存档迁移与「只写本机 localStorage」的隐私口径冲突
唤回入口(关掉后留 🐋 按钮)需要新增浮层常驻按钮,属于新 UI 面,留待后续

2.2.0:一致性修复

针对「动作和设计稿不一致 / 热区点不到 / 播放时尺寸跳 / 幅度过大 / CI 一直红」做的五项修复。

问题原因处理
姿势立绘服装不一致三张表在各自姿势参考下重绘,袜子被画成深蓝 / 近白 / 裸腿9 帧全部从设计帧重新生成,袜子颜色写成硬约束
播放时尺寸跳同表各帧高度不一(最大差 8px)按表内最高帧统一,只做 ≤20% 缩放;≤2px 的差保持原样
热区点不到配准表缺 wink#1/wink#2,且数值量自旧伪帧按当前 13 张动作表 + 19 张姿势表逐帧重算(88 行),改用 alpha 质心配准
未命中乱归因兜底固定成 belly改为几何最近的矩形
动作幅度过大drag 5fps 且叠 tilt、立绘 0.9s 一轮drag 2fps 去 tilt、play 3fps、wink 1.5fps、立绘 1.4s
CI 一直失败仓库里的 bundle 带 CRLF,Linux 重建是 LFbuild.mjs 读源时统一换行 + 产物校验无 CR

动作表与姿势表的逐帧几何(高度、底边、质心、绿边像素)由 _tmp/whale-gen/ 下的脚本核对;配色核对脚本 qc_look.py 以「绝对矩形 + 用 8 张原始表标定容差」的方式筛查,它是筛查工具不是判据:坐姿、侧视这类姿势会让腿部矩形落在裙子上,最终以目视为准。

2.1.0:全部真帧

13 张动作精灵表全部为 3 帧真实重绘(sleep / joy / eat / play / welcome / wake / walk 保留原版帧数),19 张姿势立绘也全部换成 3 帧独立绘制。此前 drag / think / work / sad 是「单帧 + 程序化微动」、19 个姿势是「同一张图缩放/位移/旋转」的伪帧,现已全部替换。

帧独立性可用 tools/art/verify_frames.py 复核:相邻帧轮廓 IoU 越高越像伪帧,真实重绘一般在 0.5–0.95。

与网页原版的差异

差异原因
精灵图走宿主只读路由 /api/dsh-whale-maid/assets,不内联进 client.js渲染进程是 sandbox,nodeIntegration: false,读不了磁盘;原站靠站点静态目录,插件里改由宿主半边 index.js 注册路由提供,client.js 因此只有约 313 KiB
样式变量桥接到 --dsw-alias-*原站用站点自己的 CSS 变量;插件内改用 DSH 主题 token,并保留原值作兜底
所有选择器加 .dwm-root 前缀宿主 shell 有 button[attr] 这类特异性 0,1,1 的规则,会压过单类选择器,导致菜单按钮变形
高光层用当前帧做 mask-image原站浅色页面下 #ffffff42 高光几乎不可见,深色主题下会变成一个浅色圆角方块
新增设置页分区原站没有可调项;这里把尺寸/速度/语言暴露出来
新增陪伴层(1.1.0)原站只有基础桌宠行为;陪伴层是新增,全部可关,关掉后与原版一致

形象来源与授权

角色美术不属于本仓库,也不在 MIT 许可范围内。

  • 角色:DSH 1024Store whale girl(中文俗称「鲸鱼女仆」)
  • 出处页面:https://deepseek1024.com/plugins/imsai-sh/awesome-deepseek-harness-plugins —— 该页面右下角的桌宠
  • 原始资源路径:/pet/whale-girl/{idle,joy,eat,play,welcome,drag,think,sleep,wake,walk}.png,单帧 256×256,横向排列
  • 权利归属:角色形象与精灵图的著作权归原站点及其原作者所有。本仓库作者对上述素材不主张任何权利。
  • 授权状态:原始资源未附带任何开源许可或使用条款声明。因此本仓库不构成任何形式的授权,也不代表已获得权利人的许可。
  • 使用限制:
    • 仅限个人学习、研究与自用;
    • 请勿将 src/sprites/*.png 或 assets/preview.png 用于商业用途、二次分发、周边制作或再授权;
    • 转载、引用本项目时请保留本节来源说明。
  • 移除承诺:若权利人提出异议,请开 issue,我会立即删除 src/sprites/ 下的全部素材。删除后插件代码仍可运行,只需换成你自己的同名精灵图。

代码许可

index.js、build.mjs、src/*.js、src/pet.css、client.js 等代码部分以 MIT 发布,见 LICENSE。MIT 仅覆盖代码,不覆盖 src/sprites/ 与 assets/preview.png 中的角色美术。

换成你自己的角色

  1. 准备 12 张横向精灵图(idle / joy / eat / play / welcome / drag / think / work / sad / sleep / wake / walk),单帧 256×256,文件名与 src/sprites/ 现有文件一致;
  2. 帧数不同的话,同步修改 build.mjs 的 SHEETS 表与 src/pet.js 的 ANIM 表(frames 字段);
  3. 运行 node build.mjs 重新生成 client.js。

已知限制

  • locale 表是静态生成的:locale/*.json 由源码里的 label(中文, English) 对生成,改了文案要重新生成一次,否则翻译表会和界面不同步。

  • 姿态按场合轮换:src/pose-map.js 把 36 条场景规则映射到姿势立绘,未命中时回落到 12 张精灵表的动作态,所以并不是每个场景都会换立绘。

  • 天气陪伴需要联网(Open-Meteo)。请求失败时沿用上次结果,超过 6 小时就不再提天气;完全离线时宠物其余功能不受影响。

  • 天气台词只有中文(英文界面会回退到中文,不会留空)。

  • 天气专属姿态(撑伞/缩脖子/发抖/流汗)与 19 个新姿态立绘暂缓,当前用现有姿态代偿。

  • 宠物渲染在 shell.overlay 层(z-index: 20,自成层叠上下文),DSH 的弹窗与吐司会盖住它,这是宿主层级决定的。

  • 拖到屏幕边缘时会被夹回视口内(留 12px 边距),窗口缩小时也会被夹取。

  • client.js 约 313 KiB;精灵图与姿势图(3.4 MB)通过 /api/dsh-whale-maid/assets 由宿主提供,不再内联进包。

  • 系统开启「减少动态效果」时,帧动画与摇摆会自动停用,只保留静态姿态。

  • 工作状态联动依赖宿主 DOM 契约(1.1.0)。探测器读的是 [data-chat-running]、[data-tool][data-state]、[data-variant="think"] 这些属性;宿主改版后可能失效。失效时的表现是「她不再跟着工作换姿态」,其余功能不受影响——用 dshWhaleMaid.scanNow() 一看就知道是不是探测不到。探测器只读 DOM,不发请求、不碰 host 总线。

  • 探测间隔 1.5 秒(MutationObserver 去抖),所以姿态切换有最多 1.5 秒延迟,这是刻意的:轮询太密会让长会话掉帧。

  • 成长数据只存在本机 localStorage,换机器/清缓存就没了,也没有云端同步。

  • 台词是按话题随机挑的,不读对话内容原文——只做关键词与话题的粗分类,不做语义理解。

  • 分区命中矩形是按 idle 第 0 帧量的,但每个姿势都重画了角色,位置会有几个像素的漂移:src/zones.js 里带一张 33 行的配准表(状态#帧 → [缩放, dx, dy]),点击时先把坐标映射回参考帧再判定,所以换姿势后仍然准。极端姿势(例如 drag 侧身)的边缘部位仍可能落到隔壁区。

  • 松手压扁是 320 ms 的一次性动画,连续快速松手不会重新播放。

推送排障(GitHub TLS)

本机到 github.com 的 HTTP/2 连接会被中间设备重置,git push 会随机失败并报:

fatal: unable to access 'https://github.com/lov0vo/dsh-whale-maid.git/':
TLS connect error: error:0A000126:SSL routines::unexpected eof while reading

这不是仓库问题,而且失败时提交可能已经落地,所以不能只看 git push 的返回值。仓库已做两件事:

  1. 仓库级配置(已写入 .git/config,克隆后需重设一次):http.version=HTTP/1.1、http.postBuffer=524288000、http.lowSpeedLimit=1000、http.lowSpeedTime=60。
  2. 新增 scripts/push.mjs:构建 → 测试 → 同步两处安装目录 → 提交 → 带退避重试地推送 main 与 tag → 用 ls-remote 回读校验远端 SHA 与 tag,校验不通过直接非零退出。
node scripts/push.mjs -m "fix: something"   # 提交并推送(含构建与测试)
node scripts/push.mjs --no-build            # 只推送已提交的内容
npm run push -m "…"                          # 同上,走 package.json scripts

推送后用 git ls-remote origin main 与 git ls-remote --tags origin 复核,两者都应与本地一致。

许可

代码:MIT · 角色美术:见上文形象来源与授权

1.9.0 变更(2026-10-26)

资源改为 HTTP 路由

精灵表与姿势立绘不再内联进 client.js。构建时 build.mjs 把它们复制到 assets/,插件宿主半边 index.js 注册只读路由 /api/dsh-whale-maid/assets:

  • 只响应 GET / HEAD,其余返回 405;
  • 有路径穿越防护(safeResolve)、MIME 表、Content-Length、Cache-Control: public, max-age=3600、弱 ETag + 304;
  • 路由注册失败只记 warn,不会让插件行挂掉(此时宠物会没有贴图)。

client.js 因此从 4.89 MB 降到 264 KB,图片总量 3.4 MB 放在 assets/,随包发布。

界面文案走翻译系统

locale/zh.json 与 locale/en.json 现在是 81 个扁平键(settings.* 19 个、panel.* 60 个、meta.* 2 个)。运行时由 src/locale-table.js 的 dwmT(key, zh, en) 查表;缺键时回落到传入的中英文,所以新增语言只需加一个 JSON 表。

气泡优先级

dwmSpeak(message, tone, priority) 支持 normal < state < important。状态提示用 state,关怀与里程碑用 important,普通闲聊用 normal——高优先级未过期时不会被低优先级顶掉。

工作状态判定

轮询 3 s 一次,切回标签页立即重扫。「运行标记消失但文档隐藏、或设置页已挂载」判为保持而不是结束,workHold 仍是最终兜底,避免切到设置页就把进行中的回合误判为结束。

场合 → 姿势

src/pose-map.js 定义了 36 条场景规则(会话、工作、互动、心情、关怀、天气、节日),每条映射到一个姿势立绘;另有 15 条回落表指定「该姿势没有图时播哪个动作态」。已接入工作相位(thinking / tool / long / success / failure)与关怀时刻(久坐 / 卡住 / 回来 / 深夜 / 饥饿 / 心情)。当前 12 个上下文里有 5 个命中真立绘(success / afk / curious / night / star),其余回落原动作态,既有转场行为不变。

发布

node scripts/release.mjs patch|minor|major 会依次完成版本号、构建、测试、同步两处安装目录、git commit、git tag。