dsh-pighub 0.9.56 → 0.9.61
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.
- package/CHANGELOG.md +126 -0
- package/README.md +127 -13
- package/assets/img/pen-fence.png +0 -0
- package/assets/img/pighub-101.png +0 -0
- package/assets/img/pighub-1031.png +0 -0
- package/assets/img/pighub-1038.png +0 -0
- package/assets/img/pighub-1053.png +0 -0
- package/assets/img/pighub-1096.png +0 -0
- package/assets/img/pighub-1106.png +0 -0
- package/assets/img/pighub-115.png +0 -0
- package/assets/img/pighub-12.png +0 -0
- package/assets/img/pighub-1318.png +0 -0
- package/assets/img/pighub-134.png +0 -0
- package/assets/img/pighub-201.png +0 -0
- package/assets/img/pighub-209.png +0 -0
- package/assets/img/pighub-210.png +0 -0
- package/assets/img/pighub-217.png +0 -0
- package/assets/img/pighub-242.png +0 -0
- package/assets/img/pighub-250.png +0 -0
- package/assets/img/pighub-258.png +0 -0
- package/assets/img/pighub-262.png +0 -0
- package/assets/img/pighub-271.png +0 -0
- package/assets/img/pighub-272.png +0 -0
- package/assets/img/pighub-293.png +0 -0
- package/assets/img/pighub-337.png +0 -0
- package/assets/img/pighub-376.png +0 -0
- package/assets/img/pighub-38.png +0 -0
- package/assets/img/pighub-40.png +0 -0
- package/assets/img/pighub-417.png +0 -0
- package/assets/img/pighub-423.png +0 -0
- package/assets/img/pighub-473.png +0 -0
- package/assets/img/pighub-560.png +0 -0
- package/assets/img/pighub-680.png +0 -0
- package/assets/img/pighub-683.png +0 -0
- package/assets/img/pighub-685.png +0 -0
- package/assets/img/pighub-686.png +0 -0
- package/assets/img/pighub-751.png +0 -0
- package/assets/img/pighub-873.png +0 -0
- package/assets/img/pighub-922.png +0 -0
- package/assets/img/pighub-974.png +0 -0
- package/assets/img/pighub-993.png +0 -0
- package/assets/img/standard-pig.png +0 -0
- package/assets/manifest.json +166 -154
- package/lib/assets.js +11 -0
- package/lib/client.js +532 -236
- package/lib/desktop-pet.js +268 -17
- package/lib/index.js +226 -41
- package/lib/native/pet-window.cs +310 -2
- package/lib/store.js +1 -1
- package/package.json +3 -3
- package/test/client.test.mjs +537 -15
- package/test/host.test.mjs +177 -5
- package/test/lifecycle.test.mjs +87 -0
- package/test/smoke.mjs +19 -4
- package/test/_d4.mjs +0 -18
- package/test/_gif.mjs +0 -5
- package/test/_s.mjs +0 -12
- package/test/_sheet2.mjs +0 -17
- package/test/_sheet3.mjs +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,132 @@
|
|
|
3
3
|
本项目遵循 [Semantic Versioning](https://semver.org/lang/zh-CN/);每条记录只写「对使用者可见的变化」,
|
|
4
4
|
内部重构不单列。README 只描述项目整体,**版本相关内容一律记在这里**。
|
|
5
5
|
|
|
6
|
+
## [0.9.60] — 2026-11-14
|
|
7
|
+
|
|
8
|
+
### Changed — 猪圈围栏换成用户给的木栅栏图(远/近两层、真景深)
|
|
9
|
+
|
|
10
|
+
围栏不再是自己画的 SVG,而是**用户给的 1254×1254 木栅栏方框图**,逐字节入库(`assets/img/pen-fence.png`,
|
|
11
|
+
sha256 `30b82f48…`,815 114 B),由新路由 `GET /pighub/pen/pen-fence.png` 提供。不重画、不改色、不拉伸。
|
|
12
|
+
|
|
13
|
+
- **去白底**:这张图的背景本来就是 `alpha=0`;「只删与画布边缘连通的近白」那条规则(与 `scripts/gif-alpha.py` 同一套)
|
|
14
|
+
跑完命中 **0** 个像素 —— 所以「去白底前后栅栏像素逐字节一致」是实测的 0(`scripts/pen-fence-split.py` 自带这条断言)。
|
|
15
|
+
- **切两层**:同一条水平线(1254 第 **636** 行 = 50.68%,取内圈竖直中点)切成上(远)/下(近),**每行只归一层**;
|
|
16
|
+
叠回去与单层整图**显示空间逐像素 0 差异**。
|
|
17
|
+
- **怎么摆**:两层各是一个 `overflow:hidden` 裁剪盒 + 盒里一张贴顶/贴底的同一张图。不用 `clip-path`
|
|
18
|
+
(它的边会抗锯齿,分割线上两层 alpha 都 <1,顺序合成后那条线会亮:实测 53 px 宽、绿通道 +14/255)。
|
|
19
|
+
溢出裁剪是硬边、按整像素归属 → 两层叠出来与单层整图在 452 px 下**逐像素 0 差异**。
|
|
20
|
+
- **谁压谁**:远栏 1 < 仓库小屋 2 < 猪 3..28(按脚底名次)< 近栏 30。猪从中间走过时头压住远栏、身子被近栏挡住。
|
|
21
|
+
- **猪的活动区**:= 栅栏内圈各收半个猪身(`PEN_BOX` 由 `{16,84,24,76}` 改为 `{24.04,75.96,29.16,72.28}`),
|
|
22
|
+
所以猪的整只可见像素都在栏内。
|
|
23
|
+
|
|
24
|
+
### Changed — 草坪只铺在给定红框里,猪圈其余区域透明
|
|
25
|
+
|
|
26
|
+
- 草坪按红框内缩(8.37% / 91.47% × 18.26% / 96.65%),红框外不铺草;原先画在牧场最外圈的 9 处草簇删掉。
|
|
27
|
+
- `.pighub-pen` 改成 `background: transparent`、去掉 1px 内描边与空占位层 —— 草地与围栏之外的区域 **alpha=0**,
|
|
28
|
+
直接露宿主页面底色(深色页面上不再出现「一块绿色/深色方块」)。圆角只做裁切、不填充。
|
|
29
|
+
- 实测:亮/暗两种页面底色各 8 个采样点全部等于底色;真机「围栏外 vs 插件不在时同坐标」6 点全部 `[21,21,23]`。
|
|
30
|
+
|
|
31
|
+
### Changed — 仓库小屋站到草坪左上角,压住后栏
|
|
32
|
+
|
|
33
|
+
- `left 14% / bottom 13%` → `left 9.7% / top 6.7%`(宽 18%、高 15.3%):屋身盖住远栏**两道横梁**
|
|
34
|
+
(实测 2079 个栅栏像素:上横梁 693 px、下横梁 1016 px,被遮高度 53 px),屋底 22.0% 仍落在草坪里。
|
|
35
|
+
- z 从「压在猪身上」改为「压后栏、被猪压」:猪走到小屋前面时猪在小屋之上。
|
|
36
|
+
- 落地阴影是小屋 SVG 里的同一个椭圆,跟着一起走。
|
|
37
|
+
|
|
38
|
+
### Verification
|
|
39
|
+
|
|
40
|
+
`npm test` **120 项全绿**(smoke 19 / store 16 / host 22 / imaging 13 / client 46 / lifecycle 4)。
|
|
41
|
+
逐项读数(切分坐标、叠回 diff、三次真机截图、遮挡两张、像素改动清单)见 `archive/pen-fence-art.md`。
|
|
42
|
+
|
|
43
|
+
## [0.9.60] — 2026-11-14
|
|
44
|
+
|
|
45
|
+
### Changed — 猪圈换成用户给的木栅栏图(按景深分两层)
|
|
46
|
+
|
|
47
|
+
- 新增 `assets/img/pen-fence.png`(815 114 B,sha256 `30b82f48…`,**与用户原图逐字节相同**);
|
|
48
|
+
- 按同一条水平分割线切成 **back / front 两层**,同一份像素、不重画:远栏在猪后、近栏在猪前;
|
|
49
|
+
- **叠回 diff = 0**(显示空间 0 px;直通 RGB 的 2262 px 全在 alpha=0 的不可见像素上,最大 7/255);
|
|
50
|
+
- 接缝方案实测淘汰三种(`clip-path` +14/255、预切图 +18/255、`background-size` 两段整体糊),
|
|
51
|
+
最终用「溢出裁剪盒 + 贴顶/贴底方块 shot」,噪声地板 167 px/≤4/255 下方案 166 px/≤4/255;
|
|
52
|
+
浏览器真实标记两层 vs 单层 **逐像素 0**。
|
|
53
|
+
|
|
54
|
+
### Changed — 草坪限红框、框外透明、小屋压后栏
|
|
55
|
+
|
|
56
|
+
- `PEN_GRASS = 8.37/91.47 × 18.26/96.65`(用户红线外沿);`PEN_INNER` 与 `PEN_BOX` 依次内收(猪的活动区各收半个猪身);
|
|
57
|
+
- `.pighub-pen{background:transparent}`、去 1px 内描边、删 `.pighub-ground` 占位层;
|
|
58
|
+
真机「围栏外 6 点 vs 插件不在时同坐标」全部 `[21,21,23]`(窗口底 `[27,27,28]`);
|
|
59
|
+
- 小屋 `left 9.7% / top 6.7%`:盖住远栏 **2079 px**(上横梁 693 + 下横梁 1016,被遮高度 53 px),全部在分割线以上;猪在小屋之上。
|
|
60
|
+
|
|
61
|
+
### Changed — 猪之间按脚底 y 遮挡
|
|
62
|
+
|
|
63
|
+
- 猪的 z 落在 `Z_ACTOR_MIN..Z_ACTOR_MAX`(3..28)一整档里,按脚底 y 单调排序;
|
|
64
|
+
- z 序固定为 `Z_FENCE_BACK < Z_HOUSE < Z_ACTOR_MIN ≤ Z_ACTOR_MAX < Z_FENCE_FRONT < Z_SETTINGS < Z_GALLERY`。
|
|
65
|
+
|
|
66
|
+
### Fixed — 拖动落地即游走起点
|
|
67
|
+
|
|
68
|
+
- 根因:`pig.posAt` 被 `normaliseState` 白名单丢弃 → `hostMoved` 恒真 → 松手那次 effect 重跑用旧快照把猪搬回拖动前的点;
|
|
69
|
+
- 改用 `lastPosWritten` + `sameSpot`(容差 0.05%)只认「值真的变了」,落地那一拍 `walkMs: 0` 取消在飞过渡;
|
|
70
|
+
- 实测:首可见帧落点误差 **x 0.00–0.01 px / y 0.00–0.03 px**、**反向位移 0**(修复前 96/120/130 px,其中一次反向 93 px)。
|
|
71
|
+
|
|
72
|
+
## [0.9.59] — 2026-11-14
|
|
73
|
+
|
|
74
|
+
### Fixed — 桌宠回猪圈的空窗从 8.36 s 降到 ~0.27 s
|
|
75
|
+
|
|
76
|
+
根因(量化实验证实):浏览器半只有 **10 s 一轮的整张快照**。两只猪放回相隔 1 139 ms,落到面板却相隔 10 030.9 ms,
|
|
77
|
+
T2 对 10 s 取模 271/301 ms —— 渲染与停止窗口都解释不了这种量化。T1(桌宠消失)实测 184–209 ms,1.2 s 只是上限从未用到。
|
|
78
|
+
|
|
79
|
+
- 新增 `action:'rev'`:只回 ~150 字符的「渲染相关状态变了没有」令牌(今日抽取/draws/桌宠名单/库存/逐只 id:place:motion:stars/排序/星级/素材版本/原生桌宠在跑没跑),
|
|
80
|
+
**不回整张快照**(38 137 B);`pos` 故意不进令牌(猪圈每 ~1.7 s 写一次,进去等于每 1.7 s 拉一张快照);
|
|
81
|
+
- 客户端两档对账:桌宠在场 **250 ms** 问令牌、空闲 **1 s**、**10 s** 整张快照兜底;令牌变了才 `load()`;
|
|
82
|
+
- 降级不粘住:只有 `unknown_action` 才永久退回 10 s,重载瞬间的 404/500 只算「这一拍不算数」;
|
|
83
|
+
- 落地卡顿:`moveActorHandler` 原来同时设 `holdUntil(6000)` 与 `fresh:true` → 实际 6 s + 1.7 s 完全不动;现在只留 `holdUntil`(`SETTLE_MS` 仍与 `pet-window.cs:397` 对齐)。
|
|
84
|
+
|
|
85
|
+
实测修复后 4 次:**261.9 / 175.2 / 266.7 / 176.0 ms**。残差 = 轮询最坏相位 250 ms + 一次 38 KB 快照;再小需换推送通道(未验证宿主能力,本轮不做)。
|
|
86
|
+
|
|
87
|
+
## [0.9.58] — 2026-11-14
|
|
88
|
+
|
|
89
|
+
### Fixed — 兼容 Cordis 核的统一停止(插件 disable / 卸载 / 宿主关闭)
|
|
90
|
+
|
|
91
|
+
- **disposer 改为返回 Promise**(`return () => stopDesktopPet('plugin_unloaded')`):Cordis 的 `_unload()` 会 `await` disposer,
|
|
92
|
+
原来的 `undefined` 等于放弃了被等待的机会;
|
|
93
|
+
- `stopDesktopPet` 加 **2s 硬上限**:stop 文件 → 1.2s → `taskkill /PID <pid> /T /F` → 0.6s → `child.kill()`,异常吞成 `{ok:false}`;
|
|
94
|
+
- **幂等**:stopping 期间共用同一次停止,无会话回 `already_stopped`;
|
|
95
|
+
- **世代守卫 `stopEpoch`**:`startDesktopPet` 在 `await ensurePetBinary()`(首次 csc 1–3s)后复核代数,修掉「disable 落在编译窗口里拉起孤儿」;
|
|
96
|
+
- 拉起时写 `<session>/pid`;新增 `reclaimStaleSessions()`:下次 apply 只清「宿主已死」的会话自愈;
|
|
97
|
+
- `sayOnDesktop` 在 stopping 期间回 `not_running`。
|
|
98
|
+
|
|
99
|
+
### Verified
|
|
100
|
+
|
|
101
|
+
- 3 次开停实测:进程消失 **819 / 767 / 842 ms**,disable 返回 1225 / 1079 / 1176 ms,`tasklist` 均为 0;
|
|
102
|
+
- 连点两次 disable 无异常;enable 4 次都能拉回桌宠;自愈实测通过;
|
|
103
|
+
- 新增 `test/lifecycle.test.mjs`(4 条)→ 全量 **107 PASS / 0 FAIL**。
|
|
104
|
+
|
|
105
|
+
## [0.9.57] — 2026-11-14
|
|
106
|
+
|
|
107
|
+
> 说明:0.9.48–0.9.56 的条目缺失(CHANGELOG 一度落后于 package.json),本轮从 0.9.57 起恢复记录。
|
|
108
|
+
|
|
109
|
+
### Added — `pig-say` 工具(对话里让桌宠说一句话)
|
|
110
|
+
|
|
111
|
+
- `pig-say { text }`:从当前桌宠里**随机选一只**,用 NewMate 同款气泡说 200 字以内纯文本;
|
|
112
|
+
- **无桌宠时拒绝**(`no_desktop_pet`);原生窗口起不来时 `desktop_pet_unavailable`,不谎报成功;
|
|
113
|
+
- 气泡中心与猪中心 Δ0 px、尾尖与猪顶 Δ−3 px、**6 秒后消失**(实测 5.45 s 仍在 / 6.59 s 已不在)、走动跟随 ≤2 px、贴上沿翻到脚下不遮脸;
|
|
114
|
+
- 命令走既有 `commands.jsonl`(`{"type":"say","id","text","until"}`),未新开通道。
|
|
115
|
+
|
|
116
|
+
### Added — 抽卡演出
|
|
117
|
+
|
|
118
|
+
- `pop 520ms → fly 640ms(飞到真实窗口中心、1.8×)→ hold 2500ms(名字 + 描述卡片)→ back → 4440ms 撤层`;
|
|
119
|
+
- 任意处点击跳过;`prefers-reduced-motion` 下不飞、只摆卡片 2.5 s;描述取 manifest 的 `note`(快照新增该字段,超 60 字截断)。
|
|
120
|
+
|
|
121
|
+
### Changed — 普通猪螺旋卷尾 + 两只换头猪连带
|
|
122
|
+
|
|
123
|
+
- `standard-pig` 按用户原图重画尾巴:**1.10 圈螺旋带**(带宽 20.4→11.6px、描边 2.6px);
|
|
124
|
+
- `pighub-751` / `pighub-974` 用各自原脸在新身体上重跑换头,**脸一个像素没动**,接缝 0.0–1.0。
|
|
125
|
+
|
|
126
|
+
### Changed — 幕布清理(道具一律保留)
|
|
127
|
+
|
|
128
|
+
- 去掉 **36 张**的幕布/横幅/角标贴纸(A 线 19 + B 线 17);
|
|
129
|
+
- **道具全部保留**:苹果、蜗牛壳、玫瑰、爱心、星星、光环、音符、礼帽、奖杯、城堡布景等;
|
|
130
|
+
- 19/19 写回逐字节回读相同、擦除像素 ∩ 猪身暖色 = 0。
|
|
131
|
+
|
|
6
132
|
## [0.9.47] — 2026-11-13
|
|
7
133
|
|
|
8
134
|
### Changed — 围栏按设计方案 A 落地(正方形·平涂·闭合框)
|
package/README.md
CHANGED
|
@@ -10,10 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
- **侧边栏入口**:PigHub 站内那只标准小猪,**保留原色彩**(逐色块描摹自 `pighub-1114`:粉身、玫红耳/腮、浅粉高光),镜像成朝右,与已有入口同尺寸。
|
|
12
12
|
- **猪圈面板**:左边带围栏的大正方形猪圈(`min(60vmin,560px)`);右上像素风标题(手写 5×7 位图字模),其下「今日猪猪」;再往下是可排序、可按位置筛选的猪猪清单。
|
|
13
|
-
- **跟随 DSH
|
|
13
|
+
- **跟随 DSH 亮/暗色主题**:草地、小屋、文字全部走 `--dsw-alias-*` 令牌(`color-mix` 与背景令牌混色),围栏用的是**用户给的位图**、
|
|
14
|
+
不参与混色——所以换主题不用改一行代码,也不需要维护第二套围栏;围栏之外的区域是透明的,亮暗两种页面底色都能直接透出来。
|
|
14
15
|
- **设置按钮**在面板整体右上角:星级显示三档(关闭 / 默认 / 常驻)、素材库版本与来源、下一版候选池、数据目录。
|
|
15
16
|
- **每日一只**:一天抽一次,池子是本版本冻结库;重复获得同一只升一星,分别记录「首次获得」与「最近升星」。
|
|
16
|
-
-
|
|
17
|
+
- **抽卡演出**:从你按下的按钮弹出(缩放回弹 + 火花)→ 飞到**窗口中心**放大到 **1.8 倍** → **停留 2.5 秒**,
|
|
18
|
+
头顶一张深色半透明圆角卡片写着**名字 + 描述**(描述 = 这只猪在 manifest 里那一条的逐图判定理由,超 60 字截断)→
|
|
19
|
+
再飞回猪圈,**落点就是这只猪真实的落点**(不是估算,见「验证」里的 landGap)。演出期间**不拦任何交互**:
|
|
20
|
+
点任意地方即刻收场(监听挂在 document 上、不阻止事件传播,按钮照按、猪照拖);`prefers-reduced-motion` 下不飞,
|
|
21
|
+
直接把卡片摆出来停 2.5 秒。
|
|
17
22
|
- **会动的猪**:自己游走、点一下有弹性回弹;游走模型**逐参数对齐桌面桌宠**(`lib/native/pet-window.cs`)——
|
|
18
23
|
每只猪各自计时,**每 1.7 秒决策一次、72% 原地发呆**,动起来就**匀速走过去**(每秒 1 个身位),不是猛跳一下。
|
|
19
24
|
**走动时面朝运动方向**(素材默认朝左,向右走才镜像),**而且是蹦跳不是平移**(外层位移弧 + 内层 squash & stretch)。
|
|
@@ -23,13 +28,25 @@
|
|
|
23
28
|
- **边界是挡住的,不是弹回来的**:撞到围栏就**夹在围栏上**(与桌宠撞到屏幕工作区同一条规则:夹取而非反弹),
|
|
24
29
|
不再重掷方向,也不会把一步拆成碎步。
|
|
25
30
|
- **自由拖动**:按住拖动时**实时跟随指针**(影子与圈里那只同尺寸),拖动期间这只猪**暂停游走**;
|
|
26
|
-
**松手即固定落点**并原地站稳约 6
|
|
31
|
+
**松手即固定落点**并原地站稳约 6 秒(只用一个站稳计时器:不再多叠一次决策延迟),不会一放就自己走开;
|
|
27
32
|
在猪圈里松手即把落脚点改成松手处。落在哪儿会写进 `state.json` 的 `pig.pos`,
|
|
28
33
|
**下次打开面板一进来就在那个点**(第一帧先发呆,不会立刻弹走)。
|
|
34
|
+
**落地即新的游走起点,不许回头**:松手那一拍就把这只猪的位置基准换成落点、并取消在飞的位移过渡,
|
|
35
|
+
下一次决策从落点开始——不会出现「先滑回拖动前的位置、再滑到落点」的两段位移。
|
|
36
|
+
实测落点与猪圆心误差 **≤0.03 px**、反向位移 **0**(3 次 × 2 种 effect 时序 + 像素连拍,
|
|
37
|
+
见 `archive/drag-drop-origin.md`)。
|
|
29
38
|
- **逐只行为开关**:右键猪本体或列表行 → 「允许运动 / 保持静止」。静止的猪不再游走、不响应点击,但仍可拖动;开关存进 `state.json` 的 `pig.motion`,缺省回落素材判定。
|
|
30
39
|
- **猪圈容量 12**:超过就自动落进仓库,并提示「猪圈满了,先住进仓库了」——不静默丢猪。
|
|
31
40
|
- **按位置筛选**:清单上方 全部 / 猪圈 / 桌宠 / 库存 四档;**点库存行即放回猪圈**。
|
|
32
|
-
-
|
|
41
|
+
- **木栅栏(有景深,用一张真图)**:围栏是**一张 1254×1254 的木栅栏方框图**(`assets/img/pen-fence.png`,逐字节原样入库,不重画/不改色/不拉伸),
|
|
42
|
+
按**同一条水平线**切成远/近两层:远侧画在猪后面、近侧画在猪前面,所以猪从中间走过时**头压住远栏、身子被近栏挡住**。
|
|
43
|
+
两层是同一份像素(每行只归一层),叠回去与单层整图**逐像素相同**(452 px 下实测 0 差异)。
|
|
44
|
+
- **草地只铺在框里**:草坪按给定红框内缩(`8.37% / 91.47% × 18.26% / 96.65%`),框外的猪圈区域**一个像素都不画**(alpha=0),
|
|
45
|
+
直接露出宿主页面底色——深色页面上不会出现「一块绿色/深色方块」。
|
|
46
|
+
- **猪之间按脚底排前后**:脚底越靠下(屏幕 y 越大)越靠前,两只猪叠在一起时**下遮挡上**;同一脚底按 id 稳定排序,不会两帧之间抢层。
|
|
47
|
+
脚底 = 猪的**中心 + 渲染高度 / 2**(贴图紧裁到猪身,所以贴图底边就是脚底;高度 = `sizeRatio` × 清单里的高宽比),不是拿 `top` 当脚底。
|
|
48
|
+
z **只在一档区间里变**(远栏 1 < 仓库小屋 2 < 猪 3..28 < 近栏 30),所以猪永远压不过近侧围栏、也不会掉到远栏下面;
|
|
49
|
+
拖动中的那只临时取这一档的顶。逐轮读数与截图见 `archive/pig-occlusion.md`。
|
|
33
50
|
- **仓库小屋**:猪圈左下角的小房子,把小猪拖进去即收进库存——**隐藏且不再加载贴图**。位置三态:猪圈 / 桌宠 / 库存,互斥。
|
|
34
51
|
- **GIF 素材**:动图原样随包分发(去白/裁切/描摹都会把动画冻成静态图),构建期用 magic 判定,客户端直接交给浏览器播放。
|
|
35
52
|
- **桌面桌宠(Windows 原生窗口)**:把猪放到桌宠位后,插件会拉起一个**自建的原生顶层窗口**
|
|
@@ -41,6 +58,11 @@
|
|
|
41
58
|
落地压扁、最高点拉长、脚始终踩在同一条地线上;**站着不动时不缩放**。
|
|
42
59
|
非 Windows 或取不到编译器时**回退到页面级浮层**(不报错)。首次运行会用系统自带 `csc.exe` 编译一次
|
|
43
60
|
(约 1–3 秒,按源码哈希缓存)。
|
|
61
|
+
- **回圈的连贯性**:把猪叫回猪圈时(原生窗口双击 / 拖回猪圈 / 工具或路由的 `{action:'pet',pigId,pet:false}`),
|
|
62
|
+
**猪圈里立刻就有它**:桌宠在场时浏览器半每 **250 ms** 对一次账——只问一个几十字节的「渲染相关状态变了没有」令牌,
|
|
63
|
+
变了才拉整张快照;没有桌宠时 1 s 问一次、10 s 拉一张整张快照兜底(位置靠它对账)。
|
|
64
|
+
实测空窗 **175–267 ms(4 次)**;改前只靠 10 s 一轮整张快照,实测 **0.16–8.36 s**,
|
|
65
|
+
而且两次相隔 1.1 s 的放回动作在界面上相差 **10.03 s**(= 轮询相位,不是渲染慢)。见 `archive/pet-return-continuity.md`。
|
|
44
66
|
- **页面内桌宠**(回退路径):把猪拖出猪圈即成为置顶浮层,可拖动;允许运动的猪会自己溜达(约三成落脚点落回猪圈),
|
|
45
67
|
**拖回猪圈矩形内松手即回圈**(也可以双击回圈)。哪些猪在猪圈外,记录在 `state.json` 的 `pets` 里,清单上会标「桌宠」。
|
|
46
68
|
**平台限制**:原生桌宠只在 Windows 上可用(v0.9.0 起);其它平台自动回退到页面级浮层。
|
|
@@ -105,7 +127,7 @@ dsh plugin --profile <你的 profile> add dsh-pighub
|
|
|
105
127
|
|
|
106
128
|
```text
|
|
107
129
|
dsh-pighub/
|
|
108
|
-
├── lib/index.js Host 半:读盘、POST /pighub
|
|
130
|
+
├── lib/index.js Host 半:读盘、POST /pighub、每张素材一条 /pighub/asset/<file>、pighub_about / pig-say
|
|
109
131
|
├── lib/store.js 抽取 / 升星 / 排序 / 原子写盘
|
|
110
132
|
├── lib/assets.js 冻结库读取(抽猪池只认它)
|
|
111
133
|
├── lib/client.js 浏览器半:closure-factory bundle,注册三个槽位
|
|
@@ -117,6 +139,31 @@ dsh-pighub/
|
|
|
117
139
|
|
|
118
140
|
浏览器半只用官方增量槽位:`sidebar.panellist`(入口)、`main`(面板,key 与入口 id 相同)、`shell.overlay`(页面级桌宠层)。
|
|
119
141
|
|
|
142
|
+
## DSH 工具
|
|
143
|
+
|
|
144
|
+
插件的 Host 半注册两个工具(`ctx.tools.register`,都在 `ctx.effect` 里,可回收):
|
|
145
|
+
|
|
146
|
+
| 工具 | 参数 | 返回 | 说明 |
|
|
147
|
+
|---|---|---|---|
|
|
148
|
+
| `pighub_about` | 无 | 版本 / 数据目录 / 今日状态 / 收藏数 / 素材库摘要 / 运行时探测 | 只读,无副作用 |
|
|
149
|
+
| `pig-say` | `{ text: string }`(必填,≤200 字) | `{ ok:true, pigId, text, truncated }` | 让**桌面上随机一只**桌宠猪用气泡说这句纯文本,约 6 秒后自动消失,气泡跟着猪走 |
|
|
150
|
+
|
|
151
|
+
`pig-say` 的拒绝是**返回值**,不是异常:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{ "ok": false, "error": "no_desktop_pet", "message": "当前没有桌宠猪猪,先把猪猪放到桌宠" }
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
同一族里还有 `empty_text`(空/纯空白)、`desktop_pet_no_asset`(桌宠列表里的猪找不到贴图)、
|
|
158
|
+
`desktop_pet_unavailable`(有猪但原生窗口起不来,例如非 Windows 或 `desktopPet:false`)。
|
|
159
|
+
超过 200 字按**码点**截断(不切坏 emoji)并回 `truncated:true` + `note`。
|
|
160
|
+
|
|
161
|
+
气泡走既有 IPC:宿主往原生窗口会话目录的 `commands.jsonl` 追加一行
|
|
162
|
+
`{"type":"say","id":"<猪>","text":"…","until":<Unix 毫秒>}`,原生侧下一帧读到就画、到点自动不画。
|
|
163
|
+
样式对齐 NewMate 的桌宠气泡(同字体/圆角/浅底/细边/尾巴),三处刻意的差异与理由见
|
|
164
|
+
[`docs/DESKTOP-PET-NATIVE.md`](./docs/DESKTOP-PET-NATIVE.md) §7。验收读数见
|
|
165
|
+
[`archive/pig-say.md`](./archive/pig-say.md)。
|
|
166
|
+
|
|
120
167
|
## 三层一致:尺寸、运动、进出
|
|
121
168
|
|
|
122
169
|
猪有三个显示层——**猪圈本体**、**页面级浮层**(非 Windows 的回退路径)、**原生桌面窗口**(Windows)。
|
|
@@ -140,6 +187,24 @@ dsh-pighub/
|
|
|
140
187
|
|
|
141
188
|
**进出连续**:从猪圈拖出去时,桌面上的落点就是松手点(实测误差 ≤ 2px);拖回猪圈时,落点换算成圈内百分比
|
|
142
189
|
(也是松手处,不是回到原位);往返前后尺寸不变。静止的猪同样会采纳新落点,只是不走动。
|
|
190
|
+
## 停止与卸载(Cordis 契约)
|
|
191
|
+
|
|
192
|
+
插件的每一样东西都挂在 `ctx.effect` 上:两个工具、状态路由、每张素材的静态路由、以及**原生桌宠的生命周期**。
|
|
193
|
+
Cordis 卸载 fiber 时会 **await 每一个 disposer**(`fiber.ts` 的 `_unload()`),所以桌宠的 disposer 返回的是一个 Promise:
|
|
194
|
+
|
|
195
|
+
| 契约 | 现在的做法 | 实测 |
|
|
196
|
+
|---|---|---|
|
|
197
|
+
| disposer 可等待 | `return () => stopDesktopPet('plugin_unloaded')`,硬上限 **2 s** 一定 settle | disable 返回时进程已不在(3 次,见 [报告](./archive/cordis-stop-compat.md)) |
|
|
198
|
+
| 停止幂等 | 并发/重复调用共用同一次停止;没有会话直接回 `already_stopped` | 连点两次 disable 第二次 `changed:false`、无异常 |
|
|
199
|
+
| 强杀兜底 | 写 `<session>/stop` → 等 1.2 s → `taskkill /PID <pid> /T /F` → 再等 0.6 s → `child.kill()` | 正常路径 `graceful:true`,只用了 105–128 ms |
|
|
200
|
+
| 启动竞态 | 首次编译 csc 要 1–3 s;这期间被 disable 的拉起请求回 `stopped_during_start` | 探针实测:2.5 s 后没有多出进程 |
|
|
201
|
+
| 宿主被强杀 | 拉起时写 `<session>/pid`(含宿主 pid),下次 apply 先 `reclaimStaleSessions()` | 造一个宿主已死的会话 → 下次 enable 时进程被杀、目录被删 |
|
|
202
|
+
|
|
203
|
+
停止的完整读数(3 次开停、逐毫秒时间戳、tasklist / 采样进程 / HTTP 404 三种独立读数)见
|
|
204
|
+
[`archive/cordis-stop-compat.md`](./archive/cordis-stop-compat.md)。做不到的两条也写在那里:
|
|
205
|
+
`taskkill /T` 的孙进程语义在本机没拿到干净对照(真实桌宠不派生子进程,实测 children=0),
|
|
206
|
+
轮询定时器的清理只有代码证据、没有进程外读数。
|
|
207
|
+
|
|
143
208
|
## 素材补全(逐角色卡)
|
|
144
209
|
|
|
145
210
|
池子里的猪来自上游社区图,**有一部分天生就是半身像**(构建期没有切坏它们,是源图如此)。
|
|
@@ -156,7 +221,16 @@ dsh-pighub/
|
|
|
156
221
|
**校验读数**(2026-11-13 实测,报告 `archive/verify-completion-and-stability.md`):14 只的
|
|
157
222
|
bytes/sha256/size 与磁盘逐字节相符、sizeRatio 落在 68.52–102.95、`/pighub/asset/<file>` 全部 200 且字节数等于清单、
|
|
158
223
|
`scripts/audit-completeness.py` 无切边;接缝(±8 逐列/行中位亮度剖面的最大相邻台阶)13 只 ≤ 3.18,
|
|
159
|
-
**pighub-
|
|
224
|
+
**pighub-1099 是 3.18**(接缝处 0.00,底边是直线)。
|
|
225
|
+
|
|
226
|
+
**pighub-868 已于 2026-11-13 23:58 单独返修**(腹底原本是一条横贯 200px 的平切直边,记录值 144.18):
|
|
227
|
+
按「重定义剪影 → 沿新剪影重画 2px 描边」重做了腹底收口,报告 [`archive/fix-868-belly.md`](./archive/fix-868-belly.md)。
|
|
228
|
+
两点值得写在这里,因为它们改变了判据本身:
|
|
229
|
+
|
|
230
|
+
- **接缝台阶这条判据对它是"已经满足"的**:抹暗行那版就已经是 0.00,改后仍是 0.00——
|
|
231
|
+
所以 868 是否修好不能看这个数。真正的证据是**腹底缘的平直度**:最长严格水平段 **42 列 → 12 列**,
|
|
232
|
+
最长「极差 ≤1px」段 **42 列 → 21 列**(标准猪同类位置 31 列,折算到同画布宽 15 列),外加 3 倍放大目检。
|
|
233
|
+
- **它现在比房子里的标准猪更有弧度**,代价是腿短了约 7 行(腿只有 25 行可让,腹底下沉就得吃腿)。
|
|
160
234
|
> `audit-completeness.py` 通过**不等于**切口不外露:它的判据落在 bbox 最外一行/列,而补出来的腿会把 bbox 撑开,
|
|
161
235
|
> 切口于是变成内部边。判封口要同时看接缝台阶与 3 倍放大图(taste.md §Q.5)。
|
|
162
236
|
|
|
@@ -165,6 +239,23 @@ bytes/sha256/size 与磁盘逐字节相符、sizeRatio 落在 68.52–102.95、`
|
|
|
165
239
|
> 按「以代码为准」的口径改成上面这一张。
|
|
166
240
|
|
|
167
241
|
标准猪(普通猪)是 `standard-pig`,也是补全时的形状参考。
|
|
242
|
+
|
|
243
|
+
### 标准猪的尾巴(2026-11-14 重画)
|
|
244
|
+
|
|
245
|
+
标准猪的尾巴**原来是错的**:它是一根「直条 + 端头」,是当年从侧栏图标(220px 源图)矢量化时丢掉的细节。
|
|
246
|
+
按用户给的权威原图 `archive/reference-standard-pig-tail.jpg`(863×764)重画成**螺旋卷尾**:
|
|
247
|
+
|
|
248
|
+
- **原图量到了什么**:那条尾巴是一条**带宽 30px**(中位;8 个极角 26–41)的带子,绕 **1.1 圈**后末端压回起始带,
|
|
249
|
+
环心映射到 482 画布是 (440,59)、外缘半径 ≈33.5px;**原图自己的顶边与右边是贴画布被切掉的**。
|
|
250
|
+
- **画成什么**:螺旋中心 (438,49)、`r0=46px → r_loop=23px`、**1.10 圈**、带宽 20.4→11.6px、描边 2.6px、色 (252,124,132);
|
|
251
|
+
臀部背线在 `x∈[380,428]` 按原图重接。缩放后四边留白 ≥6px(不会重蹈原图被切的覆辙)。
|
|
252
|
+
**偏离任务书的两点**(量出来才改的):带宽按原图 ~16px 而不是 2px(2px 在 96px 显示尺寸上是 0.4px,
|
|
253
|
+
屏幕上会消失),环比原图小 ~7%(原图那只被画布切过)。逐条读数见
|
|
254
|
+
[`archive/standard-pig-tail.md`](./archive/standard-pig-tail.md)。
|
|
255
|
+
- **两只换头猪跟着重跑**:`751` / `974` 用各自的原脸在新身体上重合成,**脸一个像素没动**
|
|
256
|
+
(`face_box` 与色偏都与 2026-11-13 那次逐字相同;头区只有挖空椭圆边界的 117/166 px、最大差 ≤10/255),
|
|
257
|
+
然后自动带上新尾巴。接缝读数与修前**逐位相同**:974 列 **1.0** / 行 **1.0**,751 列 **0.0** / 行 **0.33**。
|
|
258
|
+
|
|
168
259
|
## 图鉴(未获取的猪)
|
|
169
260
|
|
|
170
261
|
面板右上角「图鉴」按钮打开一个网格,列出池子里**全部**猪猪(不只是已获取的):
|
|
@@ -176,10 +267,24 @@ bytes/sha256/size 与磁盘逐字节相符、sizeRatio 落在 68.52–102.95、`
|
|
|
176
267
|
|
|
177
268
|
标题栏显示「图鉴 N 只 · 已收集 M 只」。数据来自快照里的 `pool` 字段(id / 名字 / 贴图地址,含未获取)。
|
|
178
269
|
|
|
179
|
-
## 猪圈视觉(2026-11-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
270
|
+
## 猪圈视觉(2026-11-14 换成用户给的木栅栏)
|
|
271
|
+
|
|
272
|
+
围栏不再是自己画的 SVG,而是**用户给的一张 1254×1254 木栅栏图**,原样入库(`assets/img/pen-fence.png`,
|
|
273
|
+
sha256 `30b82f48…` 与用户给的文件逐字节相同),整幅由 `GET /pighub/pen/pen-fence.png` 提供。
|
|
274
|
+
|
|
275
|
+
- **去白底**:这张图的背景本来就是 alpha=0,棱边那条"近白"规则(与 `scripts/gif-alpha.py` 同一套:只删与画布边缘连通的近白)
|
|
276
|
+
跑完**命中 0 个像素**——所以"去白底前后栅栏像素逐字节一致"是实测出来的 0,不是"没做"。
|
|
277
|
+
- **切两层**:同一条水平线(1254 原图第 **636** 行 = 50.68%,取内圈竖直中点)把图切成上半(远)/下半(近),
|
|
278
|
+
每行只属于一层;两层叠回去与单层整图**显示空间逐像素 0 差异**(`scripts/pen-fence-split.py` 自带这条断言)。
|
|
279
|
+
- **怎么摆**:两层各是一个 `overflow:hidden` 裁剪盒 + 盒里一张**贴顶/贴底的同一张图**(`background-size:100% 100%`)。
|
|
280
|
+
不用 `clip-path`:它的边会抗锯齿,分割线上两层 alpha 都 <1,顺序合成后那条线会亮出来(实测 53 px 宽、绿通道 +14/255)。
|
|
281
|
+
溢出裁剪是硬边、按整像素归属,所以叠出来与整图一致(实测 452 px 下 0 差异)。
|
|
282
|
+
- **谁压谁**:远栏 `1` < 仓库小屋 `2` < **猪 `3..28`**(档内按脚底名次排,见上文「猪之间按脚底排前后」)< 近栏 `30` < 设置 `31` < 图鉴 `32`。
|
|
283
|
+
整档留在 40 以下:猪圈自己没有层叠上下文,越过 40 就会盖到右键菜单/桌宠层(40/41)、抽卡演出(59/60/61)与 toast(62)。
|
|
284
|
+
猪的活动区(圆心)= 栅栏内圈各收半个猪身。
|
|
285
|
+
- **草地**:只铺在给定红框里(`8.37% / 91.47% × 18.26% / 96.65%`),红框外**不铺草**;猪圈自己 `background:transparent`、
|
|
286
|
+
没有描边、没有铺满全圈的叠层,所以草地与围栏之外的区域 alpha=0,直接露宿主页面底色(亮/暗两种底色都实测过)。
|
|
287
|
+
- 猪圈里其余的东西(仓库小屋、踩踏土、草簇)保持原样,只是被红框裁住。逐项读数与三次真机截图见 `archive/pen-fence-art.md`。
|
|
183
288
|
## 与其他桌宠插件共存
|
|
184
289
|
|
|
185
290
|
插件市场上的桌宠(例如 [dsh-pet](https://www.npmjs.com/package/dsh-pet))都是页面级浮层,所以按同一套既有约定来:容器 `pointer-events: none`、自有 z-index 层、样式标签与类名全带 `dsh-pighub` / `.pighub-` 前缀、尊重 `prefers-reduced-motion`。
|
|
@@ -187,12 +292,15 @@ bytes/sha256/size 与磁盘逐字节相符、sizeRatio 落在 68.52–102.95、`
|
|
|
187
292
|
## 验证
|
|
188
293
|
|
|
189
294
|
```sh
|
|
190
|
-
npm test #
|
|
295
|
+
npm test # 107 项离线断言:契约 / 规则 / HTTP 面 / 成像与描摹 / 浏览器半结构 / 停止契约
|
|
191
296
|
npm run assets:build # 重新生成包内贴图(需要源图;会把处理结果写进 assets/img)
|
|
192
297
|
```
|
|
193
298
|
|
|
194
|
-
>
|
|
195
|
-
>
|
|
299
|
+
> 2026-11-14 02:14 实测:smoke 19 / store 16 / host 20 / imaging 13 / client 35 / lifecycle 4 = **107 项**(`npm test` 退出码 0)。
|
|
300
|
+
> client 多出的 5 条是抽卡演出的(时间轴常量、描述截断、三段演出、点击跳过、reduced-motion),
|
|
301
|
+
> host 的 20 里含「快照带 note」断言与另一条线新增的用例。
|
|
302
|
+
> 同一时刻 `node test/smoke.mjs` 曾报「素材字节数与清单不符」——那是**并行的素材重写**(15 张图已写、清单未更),
|
|
303
|
+
> 与本轮无关,读数与时刻见 `archive/draw-reveal.md` §4。
|
|
196
304
|
|
|
197
305
|
补全产物与运行时稳定性另有三支探针(`_` 前缀,不进管线):
|
|
198
306
|
|
|
@@ -201,6 +309,12 @@ npm run assets:build # 重新生成包内贴图(需要源图;会把处
|
|
|
201
309
|
回调里的路径零覆盖——`ReferenceError` 那类缺陷只有它能抓),并做「卸载重挂 20 次,活着的定时器数量不变」的累积检查;
|
|
202
310
|
- `scripts/_probe-assets.mjs` / `_probe-consistency.mjs` / `_probe-asseturl.mjs`:贴图 HTTP 200 与字节对账、
|
|
203
311
|
id ↔ 文件名串号、URL 上 `?v=` 的幂等性。
|
|
312
|
+
- `scripts/_probe-pet-stop.mjs`:**直接量 `stopDesktopPet`**(不经 Cordis)——优雅停的毫秒数、幂等、以及
|
|
313
|
+
「不 await 的 start + 立刻 stop」的启动竞态(必须回 `stopped_during_start` 且不留进程);
|
|
314
|
+
- `scripts/_probe-taskkill-tree.mjs`:`taskkill /T` 与「只杀父进程」的对照实验(本机环境干扰,未能区分,见停止报告 §7);
|
|
315
|
+
- `scripts/_868-belly.py`:pighub-868 腹底收口的构造与复量(剪影曲线 → 描边距渲染),
|
|
316
|
+
默认干跑、`--write` 才写素材,**幂等**(在已修好的图上再跑 `changed px = 0`),
|
|
317
|
+
同时报「接缝台阶」与「底缘平直度」两套读数——后者才是这类形状缺陷的判据。
|
|
204
318
|
|
|
205
319
|
界面另有一套**本地**验证台(不随仓库分发、不进 npm 包):它按宿主契约把 `lib/client.js` 挂到普通页面上,并埋四个探针——
|
|
206
320
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/assets/img/pighub-12.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/assets/img/pighub-38.png
CHANGED
|
Binary file
|
package/assets/img/pighub-40.png
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|