dsh-whale-maid
The 1024Store whale girl as a DSH (DeepSeek Harness) desktop pet: full ten-state sprite animation, drag, feed, play, and a settings section.
- Stars
- 1
- Language
- JavaScript
- Created
- Oct 25, 2026
- Updated
- Oct 26, 2026
Introduction
dsh-whale-maid
把 DeepSeek 插件市场页面右下角那只鲸鱼女仆完整提取出来,做成 DSH(DeepSeek Harness)的桌面宠物插件。
不是一张静态图片:10 组精灵图集 + JS 状态机,眨眼、欢呼、吃东西、玩耍、思考、入睡、醒来、左右漫步、拖动摇摆全部保留。
从 1.1.0 起,她还会跟着你的工作状态变姿势、记心情与好感、每天签到、解锁成就、在你久坐或深夜时主动说一句——这些是在原版提取之上新增的陪伴层,原有动作与交互一个没改。

功能
- 十二状态精灵动画:
idle(含随机眨眼)、joy、eat、play、welcome、drag(拖拽摇摆)、think(浮动 + 问号)、work(敲全息面板)、sad(垂头丧气)、sleep(打呼噜)、wake、walk(乒乓漫步) - 交互:单击问候并展开菜单、按住拖动换位置、喂小鱼干(每 5 条触发里程碑台词)、陪它玩耍、爱心飘出
- 自动行为:空闲 15–35 秒思考一次、25–45 秒随机漫步一次、60 秒无交互后入睡、点击唤醒
- 位置记忆:拖动后的位置写进
localStorage,重开仍在原处 - 跟随主题:气泡、菜单按钮用 DSH 主题 token(
--dsw-alias-*),深色/浅色主题都自适应 - 设置面板:
设置 → 鲸鱼女仆,可调尺寸、动画速度、气泡停留时长、气泡打字机、气泡语言,以及问候/漫步/睡眠开关 - 零运行时依赖:不装任何 npm 包,不发任何网络请求,不读写文件系统
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.dsh | package.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(通用)
- 把整个仓库目录放到
C:\Users\Administrator\.dsh\plugins\dsh-whale-maid(目录名要与package.json的name一致)。 - 编辑 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"
- 让包出现在 profile 的
node_modules里(复制目录,或在该 profile 下跑一次pnpm install)。 - 重载窗口(
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 秒后趴下睡觉;点击会先播「醒来」再「欢呼」 |
| 点头顶 / 肚子 / 尾巴 | 分区反应:不同台词 + 不同粒子(心 / 闪光 / 音符) |
| 1.2 秒内连点三次 | 三连击庆祝(星星 + 爱心 + 专属台词) |
宠物会自己走动,所以位置不总是右下角——这是原始行为。
配置
设置页:设置(Ctrl+,)→ 左侧「鲸鱼女仆」。改动即时生效,存在 localStorage['dsh-whale-maid:options']。
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
size | number | null | null | 像素尺寸 24–320;null = 响应式(桌面 110px,窄屏 72px) |
speed | number | 1 | 动画与漫步速度倍率 0.2–3 |
bubbleDuration | number | 4500 | 气泡停留毫秒数 1000–10000 |
typewriter | boolean | true | 气泡文字逐字显示(false = 整句直接出现) |
city | string | '北京' | 定位失败时用于查天气的城市名(1.3.0) |
language | 'auto' | 'zh' | 'en' | 'auto' | 气泡文案语言,auto 跟随界面 |
greeting | boolean | true | 首次打开是否主动打招呼 |
walk | boolean | true | 是否允许随机漫步 |
sleep | boolean | true | 是否允许空闲入睡 |
greetings | string[] | null | null | 自定义问候语池,null 用内置文案 |
陪伴开关(1.1.0)
设置页:设置(Ctrl+,)→ 左侧「鲸鱼女仆」。存在 localStorage['dsh-whale-maid:companion']。
| 键 | 类型 | 默认 | 说明 |
|---|---|---|---|
workLink | boolean | true | 是否跟随工作状态换姿态(关掉后她只做原版的 idle 生活) |
workHold | number | 6000 | 切走对话视图后的宽限毫秒数,避免后台任务被误判结束 |
workSpeech | 'chatty' | 'quiet' | 'off' | 'chatty' | 工作期说话频率:话痨 15–40s / 安静 90–240s / 不说 |
idleChat | boolean | true | 是否 5–8 分钟主动闲聊一次 |
care | boolean | true | 主动关怀(久坐 / 卡住 / 深夜 / 饿了 / 回来) |
chip | boolean | true | 是否显示宠物左侧的状态小标签 |
zones | boolean | true | 是否启用分区点击反应 |
achievements | boolean | true | 是否记录成就与成长日记 |
lateNight | boolean | true | 深夜(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('上海') // 改备用城市并立即刷新
姿态资源(27 姿态对照)
参考插件按「姿态名」组织立绘,本插件按「状态」组织精灵表。为了让两边能对上,下表把 27 个姿态逐一映射到本插件的图片来源。
| 姿态 | 图片来源 | 说明 |
|---|---|---|
idle | 精灵表 idle.png | 3 帧待机 |
waiting | src/sprites/poses/waiting.png | 独立立绘 |
thinking | 精灵表 think.png | 3 帧(伪帧)+ 浮动 |
tool | 精灵表 work.png | 3 帧(伪帧)+ 浮动 |
success | poses/success.png | 独立立绘(早前借 joy) |
failure | 精灵表 sad.png | 3 帧(伪帧) |
curious / teasing / afk / blush / angry / star | poses/<名字>.png | 独立立绘 |
eat | 精灵表 eat.png | 3 帧 |
celebrate | poses/celebrate.png | 独立立绘(早前借 joy) |
sleep | 精灵表 sleep.png | 2 帧 |
greet | 精灵表 welcome.png | 2 帧 |
night / wink / bold / abstract / sweep | poses/<名字>.png | 独立立绘 |
workSlack / workRam / coolShades / workPat / balanceLow | poses/<名字>.png | 独立立绘 |
hidden | —— | 参考插件里是 null,本插件用 hidden 开关 + 🐋 唤回按钮实现 |
src/sprites/poses/里的 19 张是素材库存:它们已被生成、抠图、归一化到与精灵帧完全相同的规格(256×256、角色高 225px、脚底贴y=256、x=128居中),但尚未接进状态机——把某个姿态真正用起来需要一个「场合 → 姿态」的映射表,那属于功能决策,等确认口径后再接。
动作表
| 状态 | 精灵图 | 帧数 | fps | 播放方式 | 触发 |
|---|---|---|---|---|---|
idle | idle.png | 3 | 2 | blink(随机眨眼) | 默认待机 |
joy | joy.png | 2 | 5 | loop | 点击、动作收尾 |
eat | eat.png | 3 | 8 | loop | 喂食 |
play | play.png | 3 | 4 | loop | 玩耍 |
welcome | welcome.png | 2 | 3 | loop | 首次问候 |
drag | drag.png | 3 | 5 | loop + tilt | 拖动中(1.3.0 起 3 帧伪帧) |
think | think.png | 3 | 2 | loop + float | 空闲思考(1.3.0 起 3 帧伪帧) |
work | work.png | 3 | 2 | loop + float | 工具运行中(1.2.0 加姿态,1.3.0 起 3 帧) |
sad | sad.png | 3 | 2 | loop | 工具报错 / 任务失败(1.2.0 加姿态,1.3.0 起 3 帧) |
wink | 眨眼 | 1 | 2 | loop | |
sleep | sleep.png | 2 | 1 | loop | 空闲 60s |
wake | wake.png | 2 | 3 | once | 睡眠中被点击 |
walk | walk.png | 3 | 6 | ping-pong | 随机漫步 |
目录结构
dsh-whale-maid/
├── index.js Host 半边:空 apply,只为让 Loader 挂载并暴露 dsh.client
├── client.js 浏览器产物(约 2.0 MB,由 build.mjs 生成,勿手改)
├── cordis.patch.yml 手工安装用的 insert 行
├── package.json 清单:exports / files / dsh.bundle / dsh.client
├── build.mjs 构建脚本:校验 PNG 尺寸 → base64 内联 → 拼 client.js
├── src/
│ ├── pet.js 宠物组件:ANIM 表、切帧、遮罩高光、拖拽、漫步、投喂、玩耍、气泡
│ ├── pet.css 原站样式 + 主题变量桥接(全部规则作用域在 .dwm-root 下)
│ ├── settings.js 设置页「鲸鱼女仆」分区
│ ├── plugin.js apply(ctx):注入样式、注册 slot、挂公开 API
│ ├── runtime.js 共享运行时状态、存储键、事件名、随机与时间工具
│ ├── lines.js 台词库(中/英各约 260 句)、关键词表、话题分类
│ ├── growth.js 成长:心情/饱食/好感/等级/签到/每日任务/41 项成就/日记
│ ├── signals.js 工作状态探测器:读宿主 DOM → 姿态 + 状态标签 + 工作期台词
│ ├── care.js 主动关怀与闲聊心跳
│ ├── zones.js 分区点击与三连击
│ ├── fx.js 状态小标签与粒子层(两个独立组件)
│ ├── panel.js 设置页「鲸鱼女仆」分区
│ └── sprites/*.png 10 组精灵图集(每帧 256×256,横向排列)
├── test/companion.test.mjs node:test 单测:18 例,真实 client.js + stub DOM
├── locale/{en,zh}.json 插件名/描述的本地化
├── icon.svg 插件图标
├── assets/preview.png README 预览图(由精灵图合成,非界面截图)
├── CHANGELOG.md
├── LICENSE MIT(仅代码)
└── README.md
重新构建
node build.mjs
产物写入 client.js。构建时会校验每张精灵图的像素尺寸是否等于 帧数 × 256,尺寸不符直接失败——防止放错图导致画面错位。
build.mjs 按固定顺序把 src/ 下的十个脚本拼进同一个闭包(runtime → lines → growth → fx → pet → settings → panel → 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 不抛。
与 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 面,留待后续 |
与网页原版的差异
| 差异 | 原因 |
|---|---|
精灵图 base64 内联进 client.js | 渲染进程是 sandbox,nodeIntegration: false,读不了磁盘;DSH 也不为插件提供静态资源路由 |
样式变量桥接到 --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 中的角色美术。
换成你自己的角色
- 准备 12 张横向精灵图(
idle/joy/eat/play/welcome/drag/think/work/sad/sleep/wake/walk),单帧 256×256,文件名与src/sprites/现有文件一致; - 帧数不同的话,同步修改
build.mjs的SHEETS表与src/pet.js的ANIM表(frames字段); - 运行
node build.mjs重新生成client.js。
已知限制,- locale 表是静态生成的:locale/*.json 由源码里的 label(中文, English) 对生成,改了文案要重新生成一次,否则翻译表会和界面不同步。,- 姿态素材未接线:src/sprites/poses/ 里的 19 张立绘是库存,当前状态机只用到 12 张精灵表;接线需要先定「场合 → 姿态」映射。
-
天气陪伴需要联网(Open-Meteo)。请求失败时沿用上次结果,超过 6 小时就不再提天气;完全离线时宠物其余功能不受影响。
-
天气台词只有中文(英文界面会回退到中文,不会留空)。
-
天气专属姿态(撑伞/缩脖子/发抖/流汗)与 19 个新姿态立绘暂缓,当前用现有姿态代偿。
-
宠物渲染在
shell.overlay层(z-index: 20,自成层叠上下文),DSH 的弹窗与吐司会盖住它,这是宿主层级决定的。 -
拖到屏幕边缘时会被夹回视口内(留 12px 边距),窗口缩小时也会被夹取。
-
client.js约 2.36 MB,其中 1.66 MB 是十二张精灵图;这是「无静态资源路由」的必然代价。 -
系统开启「减少动态效果」时,帧动画与摇摆会自动停用,只保留静态姿态。
-
工作状态联动依赖宿主 DOM 契约(1.1.0)。探测器读的是
[data-chat-running]、[data-tool][data-state]、[data-variant="think"]这些属性;宿主改版后可能失效。失效时的表现是「她不再跟着工作换姿态」,其余功能不受影响——用dshWhaleMaid.scanNow()一看就知道是不是探测不到。探测器只读 DOM,不发请求、不碰 host 总线。 -
探测间隔 1.5 秒(
MutationObserver去抖),所以姿态切换有最多 1.5 秒延迟,这是刻意的:轮询太密会让长会话掉帧。 -
成长数据只存在本机
localStorage,换机器/清缓存就没了,也没有云端同步。 -
台词是按话题随机挑的,不读对话内容原文——只做关键词与话题的粗分类,不做语义理解。
许可
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。