Bundle
dsh-client-ui-pet
DeepSeek Harness web UI pet plugin: Codex-style companion pets with hand-drawn SVG pets (DeepSeek whale girl included), activity-reactive behaviors, light raising stats, a full customization panel, and a developer pet-definition API.
- Source
- LucasleeCN
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 days ago
Readme
# dsh-client-ui-pet
DeepSeek Harness 官方 Web UI 的客户端宠物插件:在界面右下角注入一只**可拖拽的桌宠**,
参考 Codex Pets 的陪伴式交互与状态叠加层设计。宠物会跟随会话状态切换动作(思考 / 工作 /
完成 / 报错 / 睡觉…),支持点击抚摸、喂食、玩耍等轻养成互动,并提供一个完整的
**宠物设置面板**和 **window.dshPet 开发者 API**。
当前内置 1 只宠物——由用户提供的状态图生成的 JPG 宠物(WebP 内嵌,免主机重启):
| id | 宠物 | 说明 |
| --- | --- | --- |
| `deepseek-whale` | **鲸鱼娘(原图)** | 由 `assets/deepseek-whale/` 下 8 个状态 PNG 抠背景、压缩为 WebP 后内嵌生成 |
> 手绘 SVG 内置宠(鲸鱼娘 / 橘猫 / 柴犬 / 史莱姆)已按用户要求移除;
> 如需恢复,取裁剪前的历史 `client.js`,或通过开发者工作室重新导入任意 SVG / raster 定义。
## 功能
### Codex 式状态陪伴
宠物通过 MutationObserver 感知 Harness Web UI 的真实活动信号:
- 在 `[data-composer-seat]` / `textarea` 中输入 → `typing`(注视键盘)
- 出现 `button[aria-label="停止生成"]` / `[data-state="running"]` → `thinking`(思考)
- 出现 `[data-streaming]` → `working`(忙碌)
- 运行结束 → `done`(完成庆祝,心情 +2、亲密度 +1)
- 出现 `[data-error]` → `error`(担心,心情 -3)
- 空闲超过设定时间 → `sleep`(睡觉 + Zzz 粒子);任何活动或互动会唤醒
### 轻养成
- 心情(0-100):随时间缓慢衰减,互动会恢复;低于 30 宠物会主动求关注。
- 亲密度(0-100):只增不减,记录你们共同工作的羁绊。
- 互动统计:抚摸 / 喂食 / 玩耍次数。
- 数据按宠物独立保存到浏览器 `localStorage`。
### 用户自定义界面
设置面板(宠物工具栏齿轮按钮)包含 5 个页签:
1. **宠物**:图库选择内置 / 自定义宠物;一键四角定位、复位、隐藏。
2. **外观**:昵称、体型滑杆、每个宠物声明自己的调色板(`<input type="color">` 换色)。
3. **行为**:状态跟随 / 气泡台词 / 粒子特效 / 自动睡觉开关,入睡时间可选 1/3/5/10 分钟;
每个状态都有手动预览按钮。
4. **养成**:心情与亲密度进度条、互动统计、重置数据。
5. **工作室**:粘贴 JSON 校验并导入自定义宠物、导出当前宠物定义、管理已导入列表。
宠物本身可以**直接拖拽**;同时提供四角定位按钮,满足 WCAG 2.2 对拖拽操作
必须有单指针替代方案的要求。宠物可聚焦,Enter / Space 抚摸,工具栏按钮均为 44px 触控目标,
`prefers-reduced-motion` 下自动关闭全部动画。
### JPG 主图宠物(raster 模式)
不想要手绘 SVG?把一张 JPG/PNG/WebP 交给插件即可作为宠物:引擎会在图片外套上
状态动画(呼吸 / 点头 / 弹跳 / 拖拽 / 睡觉…),气泡、粒子、互动、养成与设置面板全部复用。
JPG 宠物不支持换色(保留原图配色),其余外观选项照常可用。
```jsonc
{
"id": "my-jpg-pet",
"name": "我的 JPG 宠物",
"mode": "raster", // 启用图片模式
"image": "/plugins/dsh-client-ui-pet/assets/my-pet/idle.webp",
// 可选:为不同状态指定不同图片;缺省的状态回退到 image
"images": { "sleep": "/plugins/dsh-client-ui-pet/assets/my-pet/sleep.webp" },
"states": { "idle": { "hold": true } },
"behaviors": []
}
```
`image` / `images` 只接受三种来源(其余会被校验拒绝):`data:image/...;base64`、
`http(s)://`、或 `/` 开头的同源路径。把图片放在本包 `assets/<宠物>/` 目录下,
Host 半侧会自动把它们发布到 `/plugins/dsh-client-ui-pet/assets/<宠物>/<文件>`
(Host 半侧代码更新后需要重启一次 Harness Web 才会生效)。
**免重启内嵌路线**(当前 `deepseek-whale` 用的就是它):
```powershell
python scripts\make-raster-pet.py assets\<宠物id> --name "宠物名" --embed
node scripts\embed-pet.mjs assets\<宠物id>\<宠物id>.embed.definition.json
```
第一条命令抠背景 / 缩放 / 压缩为 WebP 并内联成 `data:image/webp;base64`;
第二条把定义嵌入 `lib/client.js` 的内置宠物列表。同步 `client.js` 后刷新页面即可。
### 开发者完全自定义:dshPetDefinition
动作、行为、表现全部由定义数据驱动。定义是一个 JSON 对象:
```jsonc
{
"id": "pudding-ghost", // /^[a-z0-9][a-z0-9_-]{1,39}$/i
"name": "布丁幽灵",
"version": "1.0.0",
"author": "you",
"description": "示例宠物",
"size": { "min": 64, "max": 240, "default": 112 },
"colors": [
{ "key": "primary", "label": "身体", "default": "#c084fc" }
],
// 内联 SVG 标记。颜色用 var(--dsh-pet-c-<key>, 默认色) 引用,
// 这样设置面板的换色器会自动生效。
"svg": "<g class=\"p-body\">…</g>",
// 只作用于本 SVG 的 CSS:关键帧 + 状态选择器。
// 引擎会把 data-state 同步到 .dsh-pet-root 分组和 svg 元素上。
"style": ".dsh-pet-root[data-state=\"idle\"] .p-body { animation: pet-bob 3s infinite; } …",
"states": {
"idle": { "label": "空闲", "hold": true },
"happy": { "label": "开心", "durationMs": 1800 }
},
"behaviors": [
{
"trigger": "activity:done", // 或数组;见下方触发器表
"state": "happy",
"bubbles": ["完成啦!"],
"effect": "sparkles", // 内置:hearts/sparkles/food/note/zzz/drop/star
"mood": 2, // 心情变化
"affinity": 1, // 亲密度变化
"hold": false, // true = 事件持续期间保持状态
"cooldownMs": 0
}
],
"interactions": {
"pet": { "state": "happy", "effect": "hearts", "mood": 5, "affinity": 1 },
"feed": { "state": "happy", "effect": "food", "mood": 12, "affinity": 2 },
"play": { "state": "happy", "effect": "sparkles", "mood": 8, "affinity": 2 }
},
"bubbles": { "idle": ["我在这里~"] }
}
```
约定与扩展点:
- `states` 必须包含 `idle`;`durationMs=0` + `hold:true` 表示常驻状态。
- `style` 里的选择器使用 `.dsh-pet-root[data-state="<状态>"] .部分类名` 为不同状态绑定关键帧。
- 表情切换:在 `svg` 中放置 `<g class="dsh-pet-expr" data-expr-default>` 和
`<g class="dsh-pet-expr" data-expr="happy">`,在 `style` 中按状态切换 `display`。
- `effects` 可扩展自定义粒子(`{ id: { svg, durationMs } }`)。
- 开发者定义的 SVG / CSS 会经过消毒(移除脚本、事件属性和 `javascript:`)。
内置触发器:`activity:typing`、`activity:thinking`、`activity:working`、
`activity:done`、`activity:error`、`sleep`、`wake`、`birth`、`mood:low`、
`interaction:pet`、`interaction:feed`、`interaction:play`;
另外可随时通过 `window.dshPet.trigger("your:custom-trigger")` 触发自定义行为。
### 开发者 API
```js
window.dshPet.version // 插件版本
window.dshPet.listPets() // [{ id, name, version, builtin }]
window.dshPet.registerPet(def, opts) // 注册自定义宠物(opts.persist=false 仅本次会话)
window.dshPet.unregisterPet(id) // 删除自定义宠物
window.dshPet.getDefinition(id?) // 深拷贝当前/指定宠物定义
window.dshPet.selectPet(id)
window.dshPet.setState("happy", { hold: true, bubbles: false, text: "…", effect: "hearts" })
window.dshPet.trigger("interaction:pet")
window.dshPet.importPet(json, opts) // 接受 JSON 字符串或对象
window.dshPet.exportCurrentPet() // 返回格式化 JSON 字符串
window.dshPet.current() // { id, state }
window.dshPet.getState() // 当前状态名
window.dshPet.on("state", handler) // "state" | "trigger" | "select" | "register" | "unregister"
```
## 安装
该插件是标准 `dsh.client` 双面包:Host 半侧为空 Loader 入口,Browser 半侧注入全部 UI。
### 方法 A:profile bundle(推荐)
编辑 `<DSH_HOME>/profiles/web/package.json`:
```json
{
"dependencies": {
"dsh-client-ui-pet": "file:D:/Softwares/CodeSoftWares/Agents/dsh-client-ui-pet"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-client-ui-pet"
]
}
}
}
```
安装依赖后重启 DeepSeek Harness Web(已打开的页面刷新即可)。
### 方法 B:手动插入 Loader 行
1. 将插件目录复制到 `<DSH_HOME>/profiles/web/node_modules/dsh-client-ui-pet`。
2. 编辑 `<DSH_HOME>/profiles/web/cordis.patch.yml`:
```yaml
- insert:
- id: ui-pet
name: 'dsh-client-ui-pet'
config:
enabled: true
```
3. 刷新 Harness Web 页面(或重启 Web)。
验证:右下角出现 DeepSeek 鲸鱼娘,点击可抚摸,悬停出现工具栏,齿轮打开设置面板。
## 目录结构
```text
dsh-client-ui-pet/
├─ package.json
├─ cordis.patch.yml
├─ LICENSE
├─ README.md
├─ lib/
│ ├─ index.js # Host 半侧(assets 静态资源路由)
│ └─ client.js # Browser 半侧(引擎 + 内置鲸鱼娘 + 面板 + API)
├─ assets/
│ ├─ README.txt # 图片放置说明
│ └─ deepseek-whale/ # 鲸鱼娘(原图)素材 + 生成的 WebP + 定义 JSON
├─ scripts/
│ ├─ make-raster-pet.py # JPG/PNG → 抠背景 → WebP → 定义 JSON
│ ├─ embed-pet.mjs # 把 --embed 定义写入 client.js 内置列表
│ ├─ prune-builtins.mjs # 移除手绘 SVG 内置宠(保留 raster 槽)
│ ├─ verify-live.mjs # CDP 真机探针(8787)
│ └─ verify-raster-live.mjs # CDP raster 注入探针
├─ test/
│ └─ client.test.mjs # node:vm 假 DOM 自动化测试(17 个用例)
├─ preview/
│ ├─ index.html # 独立预览页(可模拟 Harness 活动信号)
│ ├─ raster-demo.html # JPG 宠物渲染验证页(?pet=<id>&embed=1)
│ ├─ server.mjs # 本地静态服务器(npm run preview)
│ ├─ preview.png # 手绘版预览截图
│ └─ deepseek-whale.png # 鲸鱼娘(原图)预览截图
├─ examples/
│ └─ pudding-ghost.json # 自定义宠物定义示例(可直接导入工作室)
└─ .github/workflows/
├─ check.yml
└─ release.yml
```
## 开发
```powershell
npm run check # 语法检查 + 自动化测试
npm run preview # 打开 http://127.0.0.1:4173/preview/ 独立预览
```
预览页可模拟「停止生成」按钮、`[data-streaming]`、`[data-state="running"]`、
`[data-error]` 与 composer 输入,用来观察宠物状态切换;URL hash 可直接切状态,如
`/preview/#happy`。
## 隐私
纯浏览器端插件:不读取 API Key,不修改模型输入,不上传任何数据。
设置、养成数据和导入的自定义宠物只保存在本机浏览器 `localStorage`。
## License
MIT
Install
dsh plugin --profile web add github:LucasleeCN/dsh-client-ui-pet
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-client-ui-pet from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.