dsh-pet 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.en.md +100 -0
  2. package/README.md +101 -97
  3. package/assets/thumb//344/270/234/345/274/240/350/245/277/346/234/233.webm +0 -0
  4. package/assets/thumb//344/270/255/347/247/213/350/265/217/346/234/210/345/220/203/346/234/210/351/245/274.webm +0 -0
  5. package/assets/thumb//344/274/230/351/233/205/345/245/263/344/273/206/350/210/236.webm +0 -0
  6. package/assets/thumb//345/201/267/345/220/203/351/233/266/351/243/237/350/242/253/346/212/223/344/275/217.webm +0 -0
  7. package/assets/thumb//345/206/231/344/273/243/347/240/201.webm +0 -0
  8. package/assets/thumb//345/212/250/347/211/251/347/216/257/347/273/225.webm +0 -0
  9. package/assets/thumb//345/216/237/345/234/260/344/270/223/345/277/203/347/216/251/351/255/224/346/226/271.webm +0 -0
  10. package/assets/thumb//345/216/237/345/234/260/345/260/217/346/206/251/346/262/211/347/234/240.webm +0 -0
  11. package/assets/thumb//345/216/237/345/234/260/345/267/246/350/275/254/345/245/224/350/267/221.webm +0 -0
  12. package/assets/thumb//345/216/237/345/234/260/346/225/262/345/207/273/346/241/214/351/235/242/344/272/222/345/212/250.webm +0 -0
  13. package/assets/thumb//345/216/237/345/234/260/346/274/202/346/265/256/350/270/217/346/255/245.webm +0 -0
  14. package/assets/thumb//345/216/237/345/234/260/350/267/263/350/267/203/346/212/223/347/242/216/345/244/264/351/241/266/347/211/251/345/223/201.webm +0 -0
  15. package/assets/thumb//345/216/237/345/234/260/350/271/262/344/270/213/347/216/251/347/216/251/345/205/267/346/261/275/350/275/246.webm +0 -0
  16. package/assets/thumb//345/216/237/345/234/260/351/207/215/345/212/233/344/270/213/350/271/262/345/216/213/347/274/251.webm +0 -0
  17. package/assets/thumb//345/217/257/347/210/261/345/256/205/350/210/236.webm +0 -0
  18. package/assets/thumb//345/220/203Token.webm +0 -0
  19. package/assets/thumb//345/220/203/345/206/260/346/267/207/346/267/213/350/236/215/345/214/226.webm +0 -0
  20. package/assets/thumb//345/220/203/345/215/210/351/244/220.webm +0 -0
  21. package/assets/thumb//345/220/203/346/227/251/351/244/220.webm +0 -0
  22. package/assets/thumb//345/220/203/346/231/232/351/244/220.webm +0 -0
  23. package/assets/thumb//345/220/203/347/231/275/351/245/255.webm +0 -0
  24. package/assets/thumb//345/220/271/346/260/224/347/220/203.webm +0 -0
  25. package/assets/thumb//345/223/210/346/254/240/350/277/236/345/244/251.webm +0 -0
  26. package/assets/thumb//345/240/206/351/233/252/344/272/272.webm +0 -0
  27. package/assets/thumb//345/244/247/345/217/243/345/220/203/351/233/266/351/243/237.webm +0 -0
  28. package/assets/thumb//345/245/263/344/273/206/345/261/210/350/206/235/347/244/274/344/273/252.webm +0 -0
  29. package/assets/thumb//345/260/217/345/271/205/345/272/246/345/216/237/345/234/260 360 /345/272/246/346/227/213/350/275/254/345/261/225/347/244/272.webm +0 -0
  30. package/assets/thumb//345/260/217/346/217/220/347/220/264/346/274/224/345/245/217.webm +0 -0
  31. package/assets/thumb//345/276/205/346/234/272/345/221/274/345/220/270/344/274/221/351/227/262.webm +0 -0
  32. package/assets/thumb//346/202/240/351/227/262/345/223/274/346/255/214.webm +0 -0
  33. package/assets/thumb//346/211/223/347/236/214/347/235/241/350/242/253/346/203/212/351/206/222.webm +0 -0
  34. package/assets/thumb//346/221/207/346/211/207/347/272/263/345/207/211.webm +0 -0
  35. package/assets/thumb//346/224/276/351/243/216/347/255/235.webm +0 -0
  36. package/assets/thumb//346/225/264/344/275/223/346/215/242/350/243/205/350/257/225/350/211/262.webm +0 -0
  37. package/assets/thumb//346/267/261/345/272/246/346/200/235/350/200/203/347/242/216/347/242/216/345/277/265.webm +0 -0
  38. package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224 - /345/202/262/345/250/207/347/224/237/346/260/224/357/274/210/344/276/247/350/272/253/345/261/225/347/244/272/357/274/211.webm +0 -0
  39. package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224 - /345/256/263/347/276/236/346/203/212/350/256/266.webm +0 -0
  40. package/assets/thumb//347/202/271/345/207/273/345/233/236/345/272/224 - /345/274/200/345/277/203/350/267/203/345/212/250.webm +0 -0
  41. package/assets/thumb//347/205/247/351/225/234/345/255/220.webm +0 -0
  42. package/assets/thumb//347/216/251/346/260/264/346/236/252.webm +0 -0
  43. package/assets/thumb//347/216/251/346/270/270/346/210/217/346/260/224/346/200/245/350/264/245/345/235/217.webm +0 -0
  44. package/assets/thumb//347/224/250/351/262/270/351/261/274/345/260/276/345/267/264/346/213/215/346/211/223/345/234/260/351/235/242.webm +0 -0
  45. package/assets/thumb//350/223/235/351/262/270/347/216/260/344/270/226.webm +0 -0
  46. package/assets/thumb//350/236/203/350/237/271/350/265/260/350/267/257.webm +0 -0
  47. package/assets/thumb//350/242/253/345/220/223/344/270/200/350/267/263/357/274/210/347/202/270/346/257/233/357/274/211.webm +0 -0
  48. package/assets/thumb//350/242/253/350/220/275/345/217/266/346/267/271/346/262/241.webm +0 -0
  49. package/assets/thumb//350/242/253/351/274/240/346/240/207/346/213/226/346/213/275/346/202/254/347/251/272/345/217/215/351/246/210.webm +0 -0
  50. package/assets/thumb//350/266/205/345/244/247/344/274/270/346/207/222/350/205/260.webm +0 -0
  51. package/assets/thumb//350/275/273/345/277/253/346/221/207/346/221/206/350/210/236.webm +0 -0
  52. package/assets/thumb//350/275/273/345/277/253/350/256/260/345/275/225.webm +0 -0
  53. package/assets/thumb//351/262/270/351/261/274/345/220/220/346/263/241/346/263/241/347/211/271/346/225/210.webm +0 -0
  54. package/lib/client.js +121 -37
  55. package/package.json +1 -1
  56. package/README.zh.md +0 -97
package/README.en.md ADDED
@@ -0,0 +1,100 @@
1
+ # dsh-pet 🐾
2
+
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-pet?label=npm&color=blue"></a>
5
+ <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm monthly downloads" src="https://img.shields.io/npm/dm/dsh-pet?label=monthly&color=brightgreen"></a>
6
+ <a href="https://www.npmjs.com/package/dsh-pet"><img alt="total downloads" src="https://img.shields.io/npm/dt/dsh-pet?label=total&color=success"></a>
7
+ <a href="https://github.com/PC2005-cloud/dsh-pet"><img alt="stars" src="https://img.shields.io/github/stars/PC2005-cloud/dsh-pet?style=social"></a>
8
+ <a href="https://github.com/PC2005-cloud/dsh-pet/blob/master/LICENSE"><img alt="license" src="https://img.shields.io/github/license/PC2005-cloud/dsh-pet?color=orange"></a>
9
+ <a href="https://awesome-dsh-plugin.com"><img alt="awesome dsh plugin" src="https://awesome-dsh-plugin.com/badge.svg"></a>
10
+ <img alt="platform" src="https://img.shields.io/badge/platform-DeepSeek%20Harness%20Web-8A2BE2">
11
+ <img alt="assets" src="https://img.shields.io/badge/assets-51%20animations-ff69b4">
12
+ </p>
13
+
14
+ > A floating desktop pet for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web UI: idle breathing, random actions (including dozing off), occasional turns, screen wandering, click reactions, and draggable.
15
+
16
+ ---
17
+
18
+ ## 🚀 Quick Start (Install the Plugin)
19
+
20
+ ```sh
21
+ dsh plugin --profile web add dsh-pet
22
+ ```
23
+
24
+ Restart `dsh web` and the pet appears in the bottom-right corner — 51 transparent animations, ready to use out of the box, no generation pipeline required.
25
+
26
+ > 💡 Want to craft your own one-of-a-kind pet? Clone [PC2005-cloud/dsh-pet](https://github.com/PC2005-cloud/dsh-pet) and use the bundled asset pipeline (AI prompts → green-screen video → transparent animation, generated with Doubao) to generate one from scratch — fully reproducible.
27
+
28
+ ## ✨ Features
29
+
30
+ - **A pure pet, nothing else**: no business features — no weather, no monitoring, no agent-state sensing; just a companion. Zero core changes, zero model cost (no LLM/API calls at runtime)
31
+ - **51 hand-drawn style transparent animations**: idle breathing, dozing off, playing with a Rubik's cube, humming, hair-raising, blowing bubbles, playing with a water gun, playing violin, the whale emerging, eating rice, looking in the mirror, three dances, writing code, seasonal actions (kite flying, snowman building, ice cream eating, fireworks…) — all seamlessly chained
32
+ - **Never-ending animation chain**: when each animation finishes, the next one is picked instantly by probability (30% idle / 10% turn / 40% action / 20% move)
33
+ - **Screen wandering**: walks toward its facing direction, checks the space ahead and never walks off screen
34
+ - **Click / drag**: click triggers a random reaction animation (happy / shy / tsundere); drag it anywhere
35
+ - **Left/right facing**: all animations are CSS-mirrored, the pet can face left or right
36
+ - **Ground alignment**: animations share a unified foot line, the pet always stands on the "ground"
37
+ - **Smooth transitions**: double-buffered video cross-fade, zero blank frames between switches
38
+ - **Accessibility-friendly**: supports `prefers-reduced-motion`
39
+
40
+ ## ⚙️ Configuration
41
+
42
+ | Key | Description | Current status |
43
+ |---|---|---|
44
+ | `size` | Stage width (px); pet height ≈ width×9/16×74% | Default 462 (≈260px tall), **not yet delivered to the browser** (DSH client config pipeline limitation; falls back to code default) |
45
+ | `position` | Default corner position | Defaults to bottom-right, same as above (not yet delivered) |
46
+ | `fullRoot` | Original 2160×1215 master asset directory | Defaults to `$DSH_HOME/pet-assets`; takes effect after manually downloading the master assets |
47
+
48
+ > Note: the plugin works out of the box; all config above is optional. Browser-side configuration of `size`/`position` is planned.
49
+
50
+ ## 🗑️ Uninstall
51
+
52
+ ```sh
53
+ dsh plugin --profile web remove dsh-pet
54
+ ```
55
+
56
+ ## 🖥️ Running Screenshots
57
+
58
+ What the pet looks like running inside the DSH Web UI:
59
+
60
+ <p>
61
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-1.png" width="380" alt="dsh-pet running in DSH Web UI 1" title="dsh-pet running in DSH Web UI 1">
62
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-2.png" width="380" alt="dsh-pet running in DSH Web UI 2" title="dsh-pet running in DSH Web UI 2">
63
+ </p>
64
+
65
+ ## 🎬 Animation Previews
66
+
67
+ > The animations have transparent backgrounds; in these GIF previews the transparent areas show the page background color, while the actual playback (webm) is transparent.
68
+
69
+ <p>
70
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%BE%85%E6%9C%BA%E5%91%BC%E5%90%B8%E4%BC%91%E9%97%B2.gif" width="160" alt="Idle breathing & chill" title="Idle breathing & chill">
71
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E4%B8%9C%E5%BC%A0%E8%A5%BF%E6%9C%9B.gif" width="160" alt="Looking around" title="Looking around">
72
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E6%BC%82%E6%B5%AE%E8%B8%8F%E6%AD%A5.gif" width="160" alt="Floating in place" title="Floating in place">
73
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E5%B0%8F%E6%86%A9%E6%B2%89%E7%9C%A0.gif" width="160" alt="Napping" title="Napping">
74
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E7%82%B9%E5%87%BB%E5%9B%9E%E5%BA%94%20-%20%E5%BC%80%E5%BF%83%E8%B7%83%E5%8A%A8.gif" width="160" alt="Click response - happy bounce" title="Click response - happy bounce">
75
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E8%A2%AB%E9%BC%A0%E6%A0%87%E6%8B%96%E6%8B%BD%E6%82%AC%E7%A9%BA%E5%8F%8D%E9%A6%88.gif" width="160" alt="Dragged by the mouse" title="Dragged by the mouse">
76
+ </p>
77
+
78
+ All 51 animations live in the repo under `dsh-pet/assets/thumb/`.
79
+
80
+ ## 📚 A Complete Project (More Than a Plugin)
81
+
82
+ This is a **complete three-piece project** — anyone can clone the repo and generate their own desktop pet from scratch:
83
+
84
+ ```
85
+ ① Prompts (recipe) → ② Asset pipeline (engine) → ③ Plugin (product)
86
+ AI animation prompts source video → transparent the pet running in DSH
87
+ ```
88
+
89
+ - Repository: [PC2005-cloud/dsh-pet](https://github.com/PC2005-cloud/dsh-pet)
90
+ - Design & implementation docs: [DESIGN.md](https://github.com/PC2005-cloud/dsh-pet/blob/master/DESIGN.md)
91
+
92
+ ## 🔎 Discover More DSH Plugins
93
+
94
+ - Community plugin catalog: [awesome-dsh-plugin.com](https://awesome-dsh-plugin.com)
95
+ - DSH official repository: [deepseek-ai/DeepSeek-Harness](https://github.com/deepseek-ai/deepseek-harness)
96
+
97
+ ## 📄 License
98
+
99
+ - Code: MIT
100
+ - Assets (animations/prompts): see the repository notes
package/README.md CHANGED
@@ -1,97 +1,101 @@
1
- # dsh-pet 🐾
2
-
3
- <p align="center">
4
- <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-pet?label=npm&color=blue"></a>
5
- <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm downloads" src="https://img.shields.io/npm/dm/dsh-pet?color=brightgreen"></a>
6
- <a href="https://github.com/PC2005-cloud/dsh-pet"><img alt="stars" src="https://img.shields.io/github/stars/PC2005-cloud/dsh-pet?style=social"></a>
7
- <a href="https://github.com/PC2005-cloud/dsh-pet/blob/master/LICENSE"><img alt="license" src="https://img.shields.io/github/license/PC2005-cloud/dsh-pet?color=orange"></a>
8
- <a href="https://awesome-dsh-plugin.com"><img alt="awesome dsh plugin" src="https://awesome-dsh-plugin.com/badge.svg"></a>
9
- <img alt="platform" src="https://img.shields.io/badge/platform-DeepSeek%20Harness%20Web-8A2BE2">
10
- <img alt="assets" src="https://img.shields.io/badge/assets-25%20animations-ff69b4">
11
- </p>
12
-
13
- > A floating desktop pet for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web UI.
14
- > 一只住在 DeepSeek Harness Web 界面里的桌面宠物:待机呼吸、随机动作、屏幕漫游、点击反应、可拖拽。
15
-
16
- ---
17
-
18
- ## ✨ 功能特性
19
-
20
- - **28 个手绘风透明动画**:待机呼吸、打瞌睡、玩魔方、哼歌、炸毛、吐泡泡、玩水枪、小提琴演奏……全部无缝衔接
21
- - **永不停止的动画链**:每段动画播完立即按概率选下一个(30% 待机 / 10% 转向 / 40% 动作 / 20% 移动)
22
- - **屏幕漫游**:朝 facing 方向行走,自动检查空间、不走出屏幕
23
- - **点击 / 拖拽**:点击有随机回应动画(开心 / 害羞 / 傲娇),可拖到任意位置
24
- - **左右朝向**:所有动画 CSS 镜像,人物可朝左 / 朝右
25
- - **落地对齐**:动画统一脚底线,宠物始终站在"地面"上
26
- - **流畅切换**:双缓冲 video 交叉淡入,切换零空白帧
27
- - **无障碍友好**:支持 `prefers-reduced-motion`
28
-
29
- ## 📦 安装
30
-
31
- ```sh
32
- dsh plugin --profile web add dsh-pet
33
- ```
34
-
35
- 重启 `dsh web`,宠物出现在界面右下角。
36
-
37
- ## ⚙️ 配置
38
-
39
- | 配置项 | 说明 | 当前状态 |
40
- |---|---|---|
41
- | `size` | 宠物显示高度(px) | 默认 260,**暂未下发到浏览器**(DSH 客户端配置管线限制,走代码默认值) |
42
- | `position` | 默认角落位置 | 默认右下角,同上暂未下发 |
43
- | `fullRoot` | 原始 1200×1200 母版资源目录 | 默认 `$DSH_HOME/pet-assets`,需手动下载母版后生效 |
44
-
45
- > 说明:插件安装即用,上述配置均为可选;`size`/`position` 的浏览器侧配置化正在规划中。
46
-
47
- ## 🗑️ 卸载
48
-
49
- ```sh
50
- dsh plugin --profile web remove dsh-pet
51
- ```
52
-
53
- ## 🖥️ 运行效果
54
-
55
- 宠物实际运行在 DSH Web 界面中的样子:
56
-
57
- <p>
58
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-1.png" width="380" alt="dsh-pet running in DSH Web UI 1" title="dsh-pet running in DSH Web UI 1">
59
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-2.png" width="380" alt="dsh-pet running in DSH Web UI 2" title="dsh-pet running in DSH Web UI 2">
60
- </p>
61
-
62
- ## 🎬 效果预览
63
-
64
- > 动画为透明背景;GIF 预览中透明部分显示为页面底色,实际播放为透明。
65
-
66
- <p>
67
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%BE%85%E6%9C%BA%E5%91%BC%E5%90%B8%E4%BC%91%E9%97%B2.gif" width="160" alt="待机呼吸休闲" title="待机呼吸休闲">
68
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E4%B8%9C%E5%BC%A0%E8%A5%BF%E6%9C%9B.gif" width="160" alt="东张西望" title="东张西望">
69
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E6%BC%82%E6%B5%AE%E8%B8%8F%E6%AD%A5.gif" width="160" alt="原地漂浮踏步" title="原地漂浮踏步">
70
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E5%B0%8F%E6%86%A9%E6%B2%89%E7%9C%A0.gif" width="160" alt="原地小憩沉眠" title="原地小憩沉眠">
71
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E7%82%B9%E5%87%BB%E5%9B%9E%E5%BA%94%20-%20%E5%BC%80%E5%BF%83%E8%B7%83%E5%8A%A8.gif" width="160" alt="点击回应 - 开心跃动" title="点击回应 - 开心跃动">
72
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E8%A2%AB%E9%BC%A0%E6%A0%87%E6%8B%96%E6%8B%BD%E6%82%AC%E7%A9%BA%E5%8F%8D%E9%A6%88.gif" width="160" alt="被鼠标拖拽悬空反馈" title="被鼠标拖拽悬空反馈">
73
- </p>
74
-
75
- 全部 28 个动画见仓库:`dsh-pet/assets/thumb/`。
76
-
77
- ## 📚 完整项目(不止是插件)
78
-
79
- 这是**完整的三件套项目**,任何人 clone 仓库都可以从零生成自己的桌面宠物:
80
-
81
- ```
82
- ① 提示词(配方) → ② 素材生成链(引擎) → ③ 插件(成品)
83
- AI 生成动画的配方 源视频 → 透明动画的管线 运行在 DSH 里的宠物
84
- ```
85
-
86
- - 仓库:[PC2005-cloud/dsh-pet](https://github.com/PC2005-cloud/dsh-pet)
87
- - 设计与实现文档:[DESIGN.md](https://github.com/PC2005-cloud/dsh-pet/blob/master/DESIGN.md)
88
-
89
- ## 🔎 发现更多 DSH 插件
90
-
91
- - 社区插件目录:[awesome-dsh-plugin.com](https://awesome-dsh-plugin.com)
92
- - DSH 官方仓库:[deepseek-ai/DeepSeek-Harness](https://github.com/deepseek-ai/deepseek-harness)
93
-
94
- ## 📄 许可
95
-
96
- - 代码:MIT
97
- - 素材(动画/提示词):见仓库说明
1
+ # dsh-pet 🐾
2
+
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-pet?label=npm&color=blue"></a>
5
+ <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm monthly downloads" src="https://img.shields.io/npm/dm/dsh-pet?label=%E6%9C%88%E4%B8%8B%E8%BD%BD&color=brightgreen"></a>
6
+ <a href="https://www.npmjs.com/package/dsh-pet"><img alt="total downloads" src="https://img.shields.io/npm/dt/dsh-pet?label=%E6%80%BB%E4%B8%8B%E8%BD%BD&color=success"></a>
7
+ <a href="https://github.com/PC2005-cloud/dsh-pet"><img alt="stars" src="https://img.shields.io/github/stars/PC2005-cloud/dsh-pet?style=social"></a>
8
+ <a href="https://github.com/PC2005-cloud/dsh-pet/blob/master/LICENSE"><img alt="license" src="https://img.shields.io/github/license/PC2005-cloud/dsh-pet?color=orange"></a>
9
+ <a href="https://awesome-dsh-plugin.com"><img alt="awesome dsh plugin" src="https://awesome-dsh-plugin.com/badge.svg"></a>
10
+ <img alt="platform" src="https://img.shields.io/badge/platform-DeepSeek%20Harness%20Web-8A2BE2">
11
+ <img alt="assets" src="https://img.shields.io/badge/assets-51%20animations-ff69b4">
12
+ </p>
13
+
14
+ > A floating desktop pet for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web UI.
15
+ > 一只住在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web 界面里的桌面宠物:待机呼吸、随机动作(含打瞌睡)、偶尔转向、屏幕漫游、点击反应、可拖拽。
16
+
17
+ ---
18
+
19
+ ## 🚀 快速开始(安装插件)
20
+
21
+ ```sh
22
+ dsh plugin --profile web add dsh-pet
23
+ ```
24
+
25
+ 重启 `dsh web`,宠物出现在界面右下角——51 个透明动画开箱即用,无需任何生成流程。
26
+
27
+ > 💡 想自己造一只专属宠物?克隆 [PC2005-cloud/dsh-pet](https://github.com/PC2005-cloud/dsh-pet) 仓库,用内置素材链(AI 提示词 → 绿幕视频 → 透明动画,素材由豆包生成)从零生成,全流程可复现。
28
+
29
+ ## 功能特性
30
+
31
+ - **纯粹的桌宠**:不掺业务功能——没有天气查询、系统监控、Agent 状态感知,就一件事:陪你。零核心改动、零模型成本(运行时零 LLM/API 调用)
32
+ - **51 个手绘风透明动画**:待机呼吸、打瞌睡、玩魔方、哼歌、炸毛、吐泡泡、玩水枪、小提琴演奏、蓝鲸现世、吃白饭、照镜子、三支舞、写代码、四季动作(放风筝、堆雪人、吃冰淇淋、放烟花……)全部无缝衔接
33
+ - **永不停止的动画链**:每段动画播完立即按概率选下一个(30% 待机 / 10% 转向 / 40% 动作 / 20% 移动)
34
+ - **屏幕漫游**:朝 facing 方向行走,自动检查空间、不走出屏幕
35
+ - **点击 / 拖拽**:点击有随机回应动画(开心 / 害羞 / 傲娇),可拖到任意位置
36
+ - **左右朝向**:所有动画 CSS 镜像,人物可朝左 / 朝右
37
+ - **落地对齐**:动画统一脚底线,宠物始终站在"地面"上
38
+ - **流畅切换**:双缓冲 video 交叉淡入,切换零空白帧
39
+ - **无障碍友好**:支持 `prefers-reduced-motion`
40
+
41
+ ## ⚙️ 配置
42
+
43
+ | 配置项 | 说明 | 当前状态 |
44
+ |---|---|---|
45
+ | `size` | 舞台宽度(px),宠物高度 = 宽度×9/16×74% | 默认 462(≈高度 260px),**暂未下发到浏览器**(DSH 客户端配置管线限制,走代码默认值) |
46
+ | `position` | 默认角落位置 | 默认右下角,同上暂未下发 |
47
+ | `fullRoot` | 原始 2160×1215 母版资源目录 | 默认 `$DSH_HOME/pet-assets`,需手动下载母版后生效 |
48
+
49
+ > 说明:插件安装即用,上述配置均为可选;`size`/`position` 的浏览器侧配置化正在规划中。
50
+
51
+ ## 🗑️ 卸载
52
+
53
+ ```sh
54
+ dsh plugin --profile web remove dsh-pet
55
+ ```
56
+
57
+ ## 🖥️ 运行效果
58
+
59
+ 宠物实际运行在 DSH Web 界面中的样子:
60
+
61
+ <p>
62
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-1.png" width="380" alt="dsh-pet running in DSH Web UI 1" title="dsh-pet running in DSH Web UI 1">
63
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-2.png" width="380" alt="dsh-pet running in DSH Web UI 2" title="dsh-pet running in DSH Web UI 2">
64
+ </p>
65
+
66
+ ## 🎬 效果预览
67
+
68
+ > 动画为透明背景;GIF 预览中透明部分显示为页面底色,实际播放为透明。
69
+
70
+ <p>
71
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%BE%85%E6%9C%BA%E5%91%BC%E5%90%B8%E4%BC%91%E9%97%B2.gif" width="160" alt="待机呼吸休闲" title="待机呼吸休闲">
72
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E4%B8%9C%E5%BC%A0%E8%A5%BF%E6%9C%9B.gif" width="160" alt="东张西望" title="东张西望">
73
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E6%BC%82%E6%B5%AE%E8%B8%8F%E6%AD%A5.gif" width="160" alt="原地漂浮踏步" title="原地漂浮踏步">
74
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E5%B0%8F%E6%86%A9%E6%B2%89%E7%9C%A0.gif" width="160" alt="原地小憩沉眠" title="原地小憩沉眠">
75
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E7%82%B9%E5%87%BB%E5%9B%9E%E5%BA%94%20-%20%E5%BC%80%E5%BF%83%E8%B7%83%E5%8A%A8.gif" width="160" alt="点击回应 - 开心跃动" title="点击回应 - 开心跃动">
76
+ <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E8%A2%AB%E9%BC%A0%E6%A0%87%E6%8B%96%E6%8B%BD%E6%82%AC%E7%A9%BA%E5%8F%8D%E9%A6%88.gif" width="160" alt="被鼠标拖拽悬空反馈" title="被鼠标拖拽悬空反馈">
77
+ </p>
78
+
79
+ 全部 51 个动画见仓库:`dsh-pet/assets/thumb/`。
80
+
81
+ ## 📚 完整项目(不止是插件)
82
+
83
+ 这是**完整的三件套项目**,任何人 clone 仓库都可以从零生成自己的桌面宠物:
84
+
85
+ ```
86
+ 提示词(配方) → ② 素材生成链(引擎) → ③ 插件(成品)
87
+ AI 生成动画的配方 源视频 → 透明动画的管线 运行在 DSH 里的宠物
88
+ ```
89
+
90
+ - 仓库:[PC2005-cloud/dsh-pet](https://github.com/PC2005-cloud/dsh-pet)
91
+ - 设计与实现文档:[DESIGN.md](https://github.com/PC2005-cloud/dsh-pet/blob/master/DESIGN.md)
92
+
93
+ ## 🔎 发现更多 DSH 插件
94
+
95
+ - 社区插件目录:[awesome-dsh-plugin.com](https://awesome-dsh-plugin.com)
96
+ - DSH 官方仓库:[deepseek-ai/DeepSeek-Harness](https://github.com/deepseek-ai/deepseek-harness)
97
+
98
+ ## 📄 许可
99
+
100
+ - 代码:MIT
101
+ - 素材(动画/提示词):见仓库说明
package/lib/client.js CHANGED
@@ -54,15 +54,16 @@ window.__ModuleLoader__.load({
54
54
  '.dsh-pet-root[data-corner="bottom-right"]{right:24px;bottom:0}',
55
55
  // 左下角位置
56
56
  '.dsh-pet-root[data-corner="bottom-left"]{left:24px;bottom:0}',
57
- // 舞台:正方形(尺寸由 --dsh-pet-size 控制,默认 260px),本身不响应鼠标
58
- '.dsh-pet-stage{position:relative;width:var(--dsh-pet-size,260px);height:var(--dsh-pet-size,260px);pointer-events:none}',
59
- // 视频:铺满舞台、保持比例、可交互(pointer-events:auto 重新开启)、抓取光标
60
- // opacity:0 初始隐藏,transition 180ms 淡入淡出
61
- '.dsh-pet-video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:auto;cursor:grab;opacity:0;transition:opacity .18s ease;transform-origin:center}',
57
+ // 舞台:16:9(--dsh-pet-size 为宽度,默认 462px=高度260;高度自动 = 宽度×9/16),本身不响应鼠标
58
+ '.dsh-pet-stage{position:relative;width:var(--dsh-pet-size,462px);height:calc(var(--dsh-pet-size,462px)*9/16);pointer-events:none}',
59
+ // 视频:铺满舞台、保持比例,**pointer-events:none 完全穿透**——
60
+ // 交互统一由覆盖 HIT_BOX 区域的 .dsh-pet-hit 层负责,透明区域点击直达下层 UI。
61
+ '.dsh-pet-video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;opacity:0;transition:opacity .18s ease;transform-origin:center}',
62
62
  // 显示中的视频(is-front 类)
63
63
  '.dsh-pet-video.is-front{opacity:1}',
64
- // 按住时显示"抓取中"光标
65
- '.dsh-pet-video:active{cursor:grabbing}',
64
+ // 命中层:覆盖人物区域(HIT_BOX),是唯一可交互区域;光标跟随 + 拖拽抓取
65
+ '.dsh-pet-hit{position:absolute;pointer-events:auto;cursor:default;z-index:1}',
66
+ '.dsh-pet-hit.dragging{cursor:grabbing}',
66
67
  // 朝向镜像说明:不用 CSS 全局规则(data-facing)控制镜像——facing 翻转会
67
68
  // 同步镜像所有 video(含仍在显示的旧视频),造成"旧帧被镜像"的闪烁。
68
69
  // 镜像改为在 switchTo 的 onReady 里按实际朝向给每个 video 设置 inline
@@ -84,12 +85,19 @@ window.__ModuleLoader__.load({
84
85
  // ============================================================================
85
86
  // 动画目录(animation catalog)—— 所有动画名和参数的"事实来源"
86
87
  // ============================================================================
87
- // 对齐说明:thumb 视频是 360×360 画布,人物的"脚底"在 y=330 处。
88
- // (360-330)/360 = 30/360 = 0.0833,与 1200 母版 (1200-1100)/1200 比例一致,
88
+ // 对齐说明:thumb 视频是 640×360(16:9)画布,人物的"脚底"在 y=330 处。
89
+ // (360-330)/360 = 30/360 = 0.0833,与 2160x1215 母版 (1215-1115)/1215 比例一致,
89
90
  // 所以用这个比例做落地对齐,缩放后依然准确。
90
91
  const CANVAS_H = 360; // thumb 画布高度
91
92
  const FEET_Y = 330; // thumb 画布上"脚底"的 y 坐标(人物站在 y=330 线上)
92
93
 
94
+ // ---- 点击/拖拽命中矩形(thumb 640×360 像素坐标)----
95
+ // normalize 已把全部动画的人物统一缩放居中。41 个动画站立帧 bbox 并集
96
+ // 为 x:138~461, y:42~339,但并集被少数伸左手的动画撑宽,视觉上左边
97
+ // 多出很多、右边多 ~25px。多数动画实际约 x:214~425(中心≈320),
98
+ // 取对称整数范围 x:200~440(中心 320),y:50~335 贴近头顶/脚底。
99
+ const HIT_BOX = { x0: 200, y0: 50, x1: 440, y1: 335 };
100
+
93
101
  // 主体待机动画(唯一常驻、循环播放)
94
102
  const IDLE = '待机呼吸休闲';
95
103
  // 转向动画(东张西望本身内容就是"从偏左看到偏右",播完翻转 facing)
@@ -117,6 +125,29 @@ window.__ModuleLoader__.load({
117
125
  '打瞌睡被惊醒', // 原独立闲置动画,已并入
118
126
  '玩水枪',
119
127
  '小提琴演奏',
128
+ '蓝鲸现世',
129
+ '吃白饭',
130
+ '照镜子',
131
+ '优雅女仆舞',
132
+ '轻快摇摆舞',
133
+ '可爱宅舞',
134
+ '整体换装试色',
135
+ '大口吃零食',
136
+ '吹气球',
137
+ '动物环绕',
138
+ '深度思考碎碎念',
139
+ '轻快记录',
140
+ '写代码',
141
+ '吃Token',
142
+ '吃早餐',
143
+ '吃午餐',
144
+ '吃晚餐',
145
+ '放风筝',
146
+ '摇扇纳凉',
147
+ '吃冰淇淋融化',
148
+ '被落叶淹没',
149
+ '中秋赏月吃月饼',
150
+ '堆雪人',
120
151
  ];
121
152
  // 点击回应动画池(3 选 1)
122
153
  const CLICKS = ['点击回应 - 开心跃动', '点击回应 - 害羞惊讶', '点击回应 - 傲娇生气(侧身展示)'];
@@ -153,8 +184,11 @@ window.__ModuleLoader__.load({
153
184
  */
154
185
  function Pet({ config }) {
155
186
  // ---- 从 config 读取参数(当前走默认值) ----
156
- const size = (config && config.size) || 260; // 显示尺寸(px)
187
+ const size = (config && config.size) || 462; // 显示尺寸(px,宽度;默认=高度260
157
188
  const corner = (config && config.position) || 'bottom-right'; // 默认角落
189
+ // 舞台 16:9:宽=size、高=size×9/16;中心偏移(定位/拖拽共用)
190
+ const halfW = size / 2;
191
+ const halfH = size * 9 / 16 / 2;
158
192
 
159
193
  // ---- React 状态 ----
160
194
  const [anim, setAnim] = useState(IDLE); // 当前动画名
@@ -273,21 +307,36 @@ window.__ModuleLoader__.load({
273
307
  // 点击/拖拽打断的动画播完后先回待机(作为缓冲),待机播完再进随机链。
274
308
  const pickNext = () => {
275
309
  const roll = Math.random();
310
+ let kind = '';
311
+ let next = '';
276
312
  if (roll < 0.3) {
277
313
  // 30% 待机:待机呼吸休闲(也是一次性,播完再选)
314
+ kind = 'IDLE';
315
+ next = IDLE;
278
316
  setAnim(IDLE);
279
317
  } else if (roll < 0.4) {
280
318
  // 10% 转向:东张西望,播完 handleEnded 里翻转 facing
319
+ kind = 'TURN';
320
+ next = TURN;
281
321
  setAnim(TURN);
282
322
  } else if (roll < 0.8) {
283
323
  // 40% 随机动作(等概率 + 去重)
284
- setAnim(pick(ACTS, animRef.current));
324
+ kind = 'ACTS';
325
+ next = pick(ACTS, animRef.current);
326
+ setAnim(next);
285
327
  } else {
286
328
  // 20% 尝试移动:tryMove 先检查空间,不够就回退随机动作
287
329
  if (!tryMove()) {
288
- setAnim(pick(ACTS, animRef.current));
330
+ kind = 'ACTS';
331
+ next = pick(ACTS, animRef.current);
332
+ setAnim(next);
333
+ } else {
334
+ kind = 'MOVES';
335
+ next = '移动(池内随机)';
289
336
  }
290
337
  }
338
+ // 【测试用】打印随机数 + 动画种类 + 选中动画,方便核对概率分布;正式版可删除
339
+ console.log('[dsh-pet] roll=' + roll.toFixed(4) + ' → [' + kind + '] ' + next);
291
340
  setOnce(true); // 链式模型全部一次性
292
341
  setSeq((s) => s + 1); // 保证即使 anim 没变也重新播放
293
342
  };
@@ -327,16 +376,16 @@ window.__ModuleLoader__.load({
327
376
  const cp = customPosRef.current;
328
377
  if (cp) return cp.rx * window.innerWidth;
329
378
  const rootEl = rootRef.current;
330
- if (rootEl) return rootEl.getBoundingClientRect().left + size / 2;
331
- return window.innerWidth - 24 - size / 2;
379
+ if (rootEl) return rootEl.getBoundingClientRect().left + halfW;
380
+ return window.innerWidth - 24 - halfW;
332
381
  };
333
382
  // 当前宠物中心 y(视口坐标)
334
383
  const currentCenterY = () => {
335
384
  const cp = customPosRef.current;
336
385
  if (cp) return cp.ry * window.innerHeight;
337
386
  const rootEl = rootRef.current;
338
- if (rootEl) return rootEl.getBoundingClientRect().top + size / 2;
339
- return window.innerHeight - 20 - size / 2;
387
+ if (rootEl) return rootEl.getBoundingClientRect().top + halfH;
388
+ return window.innerHeight - 20 - halfH;
340
389
  };
341
390
 
342
391
  /**
@@ -381,8 +430,8 @@ window.__ModuleLoader__.load({
381
430
  const px = ratioX * W;
382
431
  const py = startYRatio * H;
383
432
  // 直接改 DOM style(不触发 React 重渲染,保证 60fps 平滑)
384
- rootEl.style.left = (px - size / 2) + 'px';
385
- rootEl.style.top = (py - size / 2) + 'px';
433
+ rootEl.style.left = (px - halfW) + 'px';
434
+ rootEl.style.top = (py - halfH) + 'px';
386
435
  rootEl.style.right = 'auto';
387
436
  rootEl.style.bottom = 'auto';
388
437
  }
@@ -414,8 +463,8 @@ window.__ModuleLoader__.load({
414
463
  const distance = randomBetween(MOVE_MIN_PX, MOVE_MAX_PX);
415
464
  const target = cx + dir * distance;
416
465
  // 【播放前检查一次距离】目标点必须在屏幕安全边距内,否则不移动
417
- const leftBound = MOVE_MARGIN + size / 2;
418
- const rightBound = W - MOVE_MARGIN - size / 2;
466
+ const leftBound = MOVE_MARGIN + halfW;
467
+ const rightBound = W - MOVE_MARGIN - halfW;
419
468
  if (target < leftBound || target > rightBound) return false; // 空间不够
420
469
  // 记录计划(存"比例"而非绝对坐标,resize 后仍正确):
421
470
  // 起点比例、目标比例、Y 比例、方向、总距离比例
@@ -453,11 +502,25 @@ window.__ModuleLoader__.load({
453
502
  // (播放拖拽动画并跟手);松手时若没拖过,click 事件正常触发点击回应。
454
503
  const DRAG_THRESHOLD = 5; // 拖拽判定阈值(px)
455
504
 
505
+ // ---- 命中层(.dsh-pet-hit)覆盖 HIT_BOX 区域 ----
506
+ // 交互范围由 CSS 命中层限定:视频 pointer-events:none(完全穿透),
507
+ // 命中层 pointer-events:auto 只覆盖人物区域。所以这里的事件天然都在
508
+ // 人物范围内,无需再做坐标命中检查;命中层之外点击直达下层 UI。
456
509
  // 按下:只记录,不立即切动画
457
510
  const handlePointerDown = (e) => {
511
+ e.currentTarget.classList.add('dragging'); // 拖拽中抓取光标
458
512
  stopMove(); // 用户交互打断正在进行的移动
459
513
  e.currentTarget.setPointerCapture(e.pointerId); // 捕获指针(拖出元素也能收到 move)
460
- dragRef.current = { active: true, dragging: false, sx: e.clientX, sy: e.clientY };
514
+ // 记录"鼠标点相对舞台中心的偏移"(舞台宽 size、高 size×9/16):
515
+ // 拖动时保持该偏移,从人物任意位置抓起都不会瞬移到鼠标下。
516
+ const rootEl = rootRef.current;
517
+ let offX = 0, offY = 0;
518
+ if (rootEl) {
519
+ const rr = rootEl.getBoundingClientRect();
520
+ offX = e.clientX - (rr.left + rr.width / 2);
521
+ offY = e.clientY - (rr.top + rr.height / 2);
522
+ }
523
+ dragRef.current = { active: true, dragging: false, sx: e.clientX, sy: e.clientY, offX, offY };
461
524
  };
462
525
  // 移动:超过阈值才进入拖拽模式
463
526
  const handlePointerMove = (e) => {
@@ -475,10 +538,14 @@ window.__ModuleLoader__.load({
475
538
  setAnim(DRAG);
476
539
  }
477
540
  // 跟手:直接改 root 的 style(不触发 React 重渲染 → 60fps 平滑)
541
+ // 舞台中心 = 鼠标点 - 按下时记录的偏移;left/top 是 root 左上角,
542
+ // 舞台宽 size、高 size×9/16,所以中心再减一半尺寸。
478
543
  const rootEl = rootRef.current;
479
544
  if (rootEl) {
480
- rootEl.style.left = (e.clientX - size / 2) + 'px';
481
- rootEl.style.top = (e.clientY - size / 2) + 'px';
545
+ const halfW = size / 2;
546
+ const halfH = size * 9 / 16 / 2;
547
+ rootEl.style.left = (e.clientX - d.offX - halfW) + 'px';
548
+ rootEl.style.top = (e.clientY - d.offY - halfH) + 'px';
482
549
  rootEl.style.right = 'auto';
483
550
  rootEl.style.bottom = 'auto';
484
551
  }
@@ -491,15 +558,18 @@ window.__ModuleLoader__.load({
491
558
  const wasDragging = d.dragging;
492
559
  d.active = false;
493
560
  d.dragging = false;
561
+ e.currentTarget.classList.remove('dragging'); // 结束抓取光标
494
562
  if (wasDragging) {
495
563
  // 抑制拖拽结束后的"幽灵点击"(浏览器在拖完也会发 click)
496
564
  justDraggedRef.current = true;
497
565
  setTimeout(() => { justDraggedRef.current = false; }, 100);
498
566
  setDragging(false);
499
- // 停在松手处(存相对窗口比例,窗口变化时位置跟随)
567
+ // 停在松手处(以舞台中心为基准,而非鼠标点——从角落抓起时
568
+ // 松手也保持偏移,宠物不会跳回鼠标位置);存相对窗口比例,
569
+ // 窗口变化时位置跟随。
500
570
  setCustomPos({
501
- rx: e.clientX / window.innerWidth,
502
- ry: e.clientY / window.innerHeight,
571
+ rx: (e.clientX - d.offX) / window.innerWidth,
572
+ ry: (e.clientY - d.offY) / window.innerHeight,
503
573
  });
504
574
  const stageEl = stageRef.current;
505
575
  if (stageEl) stageEl.style.transform = 'translateY(' + bottomPad + 'px)'; // 恢复落地对齐
@@ -510,7 +580,7 @@ window.__ModuleLoader__.load({
510
580
  };
511
581
 
512
582
  // ---- 点击回应(仅真点击触发,拖拽后的 click 被忽略) ----
513
- const handleClick = () => {
583
+ const handleClick = (e) => {
514
584
  const d = dragRef.current;
515
585
  if (d.active || d.dragging || justDraggedRef.current) return; // 拖拽中/刚拖完:忽略
516
586
  if (once && animRef.current !== IDLE) return; // 正在播一次性动画:不打断
@@ -522,10 +592,10 @@ window.__ModuleLoader__.load({
522
592
  // ============================================================================
523
593
  // 渲染
524
594
  // ============================================================================
525
- // 落地对齐:视频是 360 画布、脚在 y=330,脚底距画布底 30px
526
- // bottomPad = size × (360-330)/360,把舞台向下平移这么多,
527
- // "脚"正好落在视口底线上(宠物看起来站在地上而不是悬空)。
528
- const bottomPad = (size * (CANVAS_H - FEET_Y)) / CANVAS_H;
595
+ // 落地对齐:视频是 640×360 画布、脚在 y=330,脚底距画布底 30px(8.33%)。
596
+ // 舞台是 16:9(高 = size×9/16),脚底距舞台底 = 舞台高 × 8.33%;
597
+ // bottomPad 就是把这个距离下移,让"脚"正好落在视口底线上。
598
+ const bottomPad = (size * 9 / 16 * (CANVAS_H - FEET_Y)) / CANVAS_H;
529
599
  // 舞台样式:拖拽中无偏移;平时 translateY(bottomPad) 落地
530
600
  const stageStyle = dragging
531
601
  ? { transform: 'none' }
@@ -537,20 +607,33 @@ window.__ModuleLoader__.load({
537
607
  // 同时钳制到窗口内,防止窗口缩小到宠物放不下时跑出屏幕。
538
608
  const rootStyle = customPos
539
609
  ? (() => {
540
- const half = size / 2;
541
610
  const rx = customPos.rx;
542
611
  const ry = customPos.ry;
543
- const left = Math.min(Math.max(rx * window.innerWidth - half, 0), window.innerWidth - size);
544
- const top = Math.min(Math.max(ry * window.innerHeight - half, 0), window.innerHeight - size);
612
+ const left = Math.min(Math.max(rx * window.innerWidth - halfW, 0), window.innerWidth - size);
613
+ const top = Math.min(Math.max(ry * window.innerHeight - halfH, 0), window.innerHeight - size * 9 / 16);
545
614
  return { left: left + 'px', top: top + 'px', right: 'auto', bottom: 'auto' };
546
615
  })()
547
616
  : {};
548
617
 
549
- // 两个 video 共用的 props(事件绑定 + 播放属性)
618
+ // 两个 video 共用的 props(纯播放属性,交互交给命中层)
550
619
  const commonVideoProps = {
551
620
  muted: true,
552
621
  playsInline: true,
553
622
  autoPlay: true,
623
+ title: 'dsh-pet',
624
+ };
625
+ // 命中层 props:覆盖 HIT_BOX 区域,承载全部交互事件与抓取光标。
626
+ // 命中层内必然命中人物,光标固定 grab(拖拽中 .dragging 类显示 grabbing)。
627
+ const hitProps = {
628
+ className: 'dsh-pet-hit',
629
+ style: {
630
+ left: (HIT_BOX.x0 / 640 * 100) + '%',
631
+ top: (HIT_BOX.y0 / 360 * 100) + '%',
632
+ width: ((HIT_BOX.x1 - HIT_BOX.x0) / 640 * 100) + '%',
633
+ height: ((HIT_BOX.y1 - HIT_BOX.y0) / 360 * 100) + '%',
634
+ },
635
+ onMouseEnter: (e) => { if (!dragRef.current.active) e.currentTarget.style.cursor = 'grab'; },
636
+ onMouseLeave: (e) => { if (!dragRef.current.active) e.currentTarget.style.cursor = 'default'; },
554
637
  onClick: handleClick,
555
638
  onPointerDown: handlePointerDown,
556
639
  onPointerMove: handlePointerMove,
@@ -559,8 +642,8 @@ window.__ModuleLoader__.load({
559
642
  title: 'dsh-pet',
560
643
  };
561
644
 
562
- // 渲染树:root > stage > [video A, video B]
563
- // A 初始带 is-front(显示),B 隐藏待命
645
+ // 渲染树:root > stage > [video A, video B, 命中层]
646
+ // A 初始带 is-front(显示),B 隐藏待命;命中层在最上层承载交互
564
647
  return h('div', {
565
648
  ref: rootRef,
566
649
  className: 'dsh-pet-root',
@@ -574,6 +657,7 @@ window.__ModuleLoader__.load({
574
657
  children: [
575
658
  h('video', Object.assign({}, commonVideoProps, { ref: videoARef, className: 'dsh-pet-video is-front' })),
576
659
  h('video', Object.assign({}, commonVideoProps, { ref: videoBRef, className: 'dsh-pet-video' })),
660
+ h('div', hitProps),
577
661
  ],
578
662
  }),
579
663
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-pet",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "A floating desktop pet for the DeepSeek Harness Web UI: idle breathing, occasional direction turns, random actions, and screen wandering.",
5
5
  "keywords": [
6
6
  "dsh",
package/README.zh.md DELETED
@@ -1,97 +0,0 @@
1
- # dsh-pet 🐾
2
-
3
- <p align="center">
4
- <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-pet?label=npm&color=blue"></a>
5
- <a href="https://www.npmjs.com/package/dsh-pet"><img alt="npm downloads" src="https://img.shields.io/npm/dm/dsh-pet?color=brightgreen"></a>
6
- <a href="https://github.com/PC2005-cloud/dsh-pet"><img alt="stars" src="https://img.shields.io/github/stars/PC2005-cloud/dsh-pet?style=social"></a>
7
- <a href="https://github.com/PC2005-cloud/dsh-pet/blob/master/LICENSE"><img alt="license" src="https://img.shields.io/github/license/PC2005-cloud/dsh-pet?color=orange"></a>
8
- <a href="https://awesome-dsh-plugin.com"><img alt="awesome dsh plugin" src="https://awesome-dsh-plugin.com/badge.svg"></a>
9
- <img alt="platform" src="https://img.shields.io/badge/platform-DeepSeek%20Harness%20Web-8A2BE2">
10
- <img alt="assets" src="https://img.shields.io/badge/assets-25%20animations-ff69b4">
11
- </p>
12
-
13
- > 一只住在 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) Web 界面里的桌面宠物:待机呼吸、随机动作、屏幕漫游、点击反应、可拖拽。
14
- > A floating desktop pet for the DeepSeek Harness Web UI.
15
-
16
- ---
17
-
18
- ## ✨ 功能特性
19
-
20
- - **28 个手绘风透明动画**:待机呼吸、打瞌睡、玩魔方、哼歌、炸毛、吐泡泡、玩水枪、小提琴演奏……全部无缝衔接
21
- - **永不停止的动画链**:每段动画播完立即按概率选下一个(30% 待机 / 10% 转向 / 40% 动作 / 20% 移动)
22
- - **屏幕漫游**:朝 facing 方向行走,自动检查空间、不走出屏幕
23
- - **点击 / 拖拽**:点击有随机回应动画(开心 / 害羞 / 傲娇),可拖到任意位置
24
- - **左右朝向**:所有动画 CSS 镜像,人物可朝左 / 朝右
25
- - **落地对齐**:动画统一脚底线,宠物始终站在"地面"上
26
- - **流畅切换**:双缓冲 video 交叉淡入,切换零空白帧
27
- - **无障碍友好**:支持 `prefers-reduced-motion`
28
-
29
- ## 📦 安装
30
-
31
- ```sh
32
- dsh plugin --profile web add dsh-pet
33
- ```
34
-
35
- 重启 `dsh web`,宠物出现在界面右下角。
36
-
37
- ## ⚙️ 配置
38
-
39
- | 配置项 | 说明 | 当前状态 |
40
- |---|---|---|
41
- | `size` | 宠物显示高度(px) | 默认 260,**暂未下发到浏览器**(DSH 客户端配置管线限制,走代码默认值) |
42
- | `position` | 默认角落位置 | 默认右下角,同上暂未下发 |
43
- | `fullRoot` | 原始 1200×1200 母版资源目录 | 默认 `$DSH_HOME/pet-assets`,需手动下载母版后生效 |
44
-
45
- > 说明:插件安装即用,上述配置均为可选;`size`/`position` 的浏览器侧配置化正在规划中。
46
-
47
- ## 🗑️ 卸载
48
-
49
- ```sh
50
- dsh plugin --profile web remove dsh-pet
51
- ```
52
-
53
- ## 🖥️ 运行效果
54
-
55
- 宠物实际运行在 DSH Web 界面中的样子:
56
-
57
- <p>
58
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-1.png" width="380" alt="dsh-pet 运行效果 1" title="dsh-pet 运行效果 1">
59
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/assets/screenshots/dsh-pet-running-2.png" width="380" alt="dsh-pet 运行效果 2" title="dsh-pet 运行效果 2">
60
- </p>
61
-
62
- ## 🎬 效果预览
63
-
64
- > 动画为透明背景;GIF 预览中透明部分显示为页面底色,实际播放为透明。
65
-
66
- <p>
67
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%BE%85%E6%9C%BA%E5%91%BC%E5%90%B8%E4%BC%91%E9%97%B2.gif" width="160" alt="待机呼吸休闲" title="待机呼吸休闲">
68
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E4%B8%9C%E5%BC%A0%E8%A5%BF%E6%9C%9B.gif" width="160" alt="东张西望" title="东张西望">
69
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E6%BC%82%E6%B5%AE%E8%B8%8F%E6%AD%A5.gif" width="160" alt="原地漂浮踏步" title="原地漂浮踏步">
70
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E5%8E%9F%E5%9C%B0%E5%B0%8F%E6%86%A9%E6%B2%89%E7%9C%A0.gif" width="160" alt="原地小憩沉眠" title="原地小憩沉眠">
71
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E7%82%B9%E5%87%BB%E5%9B%9E%E5%BA%94%20-%20%E5%BC%80%E5%BF%83%E8%B7%83%E5%8A%A8.gif" width="160" alt="点击回应 - 开心跃动" title="点击回应 - 开心跃动">
72
- <img src="https://raw.githubusercontent.com/PC2005-cloud/dsh-pet/main/dsh-pet/assets/preview/%E8%A2%AB%E9%BC%A0%E6%A0%87%E6%8B%96%E6%8B%BD%E6%82%AC%E7%A9%BA%E5%8F%8D%E9%A6%88.gif" width="160" alt="被鼠标拖拽悬空反馈" title="被鼠标拖拽悬空反馈">
73
- </p>
74
-
75
- 全部 28 个动画见仓库:`dsh-pet/assets/thumb/`。
76
-
77
- ## 📚 完整项目(不止是插件)
78
-
79
- 这是**完整的三件套项目**,任何人 clone 仓库都可以从零生成自己的桌面宠物:
80
-
81
- ```
82
- ① 提示词(配方) → ② 素材生成链(引擎) → ③ 插件(成品)
83
- AI 生成动画的配方 源视频 → 透明动画的管线 运行在 DSH 里的宠物
84
- ```
85
-
86
- - 仓库:[PC2005-cloud/dsh-pet](https://github.com/PC2005-cloud/dsh-pet)
87
- - 设计与实现文档:[DESIGN.md](https://github.com/PC2005-cloud/dsh-pet/blob/master/DESIGN.md)
88
-
89
- ## 🔎 发现更多 DSH 插件
90
-
91
- - 社区插件目录:[awesome-dsh-plugin.com](https://awesome-dsh-plugin.com)
92
- - DSH 官方仓库:[deepseek-ai/DeepSeek-Harness](https://github.com/deepseek-ai/deepseek-harness)
93
-
94
- ## 📄 许可
95
-
96
- - 代码:MIT
97
- - 素材(动画/提示词):见仓库说明