dsh-pighub 0.3.1 → 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.
Files changed (281) hide show
  1. package/CHANGELOG.md +1056 -0
  2. package/README.md +260 -18
  3. package/assets/ATTRIBUTION.md +38 -0
  4. package/assets/img/pen-fence.png +0 -0
  5. package/assets/img/pig-1355.png +0 -0
  6. package/assets/img/pig-1358.png +0 -0
  7. package/assets/img/pig-1361.svg +1 -1
  8. package/assets/img/pighub-1000.png +0 -0
  9. package/assets/img/pighub-1003.png +0 -0
  10. package/assets/img/pighub-1005.png +0 -0
  11. package/assets/img/pighub-101.png +0 -0
  12. package/assets/img/pighub-1012.png +0 -0
  13. package/assets/img/pighub-1015.png +0 -0
  14. package/assets/img/pighub-1018.png +0 -0
  15. package/assets/img/pighub-102.png +0 -0
  16. package/assets/img/pighub-1020.png +0 -0
  17. package/assets/img/pighub-103.png +0 -0
  18. package/assets/img/pighub-1031.png +0 -0
  19. package/assets/img/pighub-1038.png +0 -0
  20. package/assets/img/pighub-104.png +0 -0
  21. package/assets/img/pighub-1048.png +0 -0
  22. package/assets/img/pighub-105.png +0 -0
  23. package/assets/img/pighub-1053.png +0 -0
  24. package/assets/img/pighub-1055.png +0 -0
  25. package/assets/img/pighub-1060.png +0 -0
  26. package/assets/img/pighub-1063.png +0 -0
  27. package/assets/img/pighub-1069.png +0 -0
  28. package/assets/img/pighub-1079.png +0 -0
  29. package/assets/img/pighub-1080.png +0 -0
  30. package/assets/img/pighub-1087.png +0 -0
  31. package/assets/img/pighub-1093.png +0 -0
  32. package/assets/img/pighub-1095.png +0 -0
  33. package/assets/img/pighub-1096.png +0 -0
  34. package/assets/img/pighub-1099.png +0 -0
  35. package/assets/img/pighub-1103.png +0 -0
  36. package/assets/img/pighub-1106.png +0 -0
  37. package/assets/img/pighub-1112.png +0 -0
  38. package/assets/img/pighub-1114.png +0 -0
  39. package/assets/img/pighub-1124.png +0 -0
  40. package/assets/img/pighub-1130.png +0 -0
  41. package/assets/img/pighub-1134.png +0 -0
  42. package/assets/img/pighub-1135.png +0 -0
  43. package/assets/img/pighub-1139.png +0 -0
  44. package/assets/img/pighub-1140.png +0 -0
  45. package/assets/img/pighub-115.png +0 -0
  46. package/assets/img/pighub-1162.png +0 -0
  47. package/assets/img/pighub-1172.png +0 -0
  48. package/assets/img/pighub-1181.png +0 -0
  49. package/assets/img/pighub-1182.png +0 -0
  50. package/assets/img/pighub-1183.png +0 -0
  51. package/assets/img/pighub-1191.png +0 -0
  52. package/assets/img/pighub-1198.png +0 -0
  53. package/assets/img/pighub-1199.png +0 -0
  54. package/assets/img/pighub-12.png +0 -0
  55. package/assets/img/pighub-1201.png +0 -0
  56. package/assets/img/pighub-1208.png +0 -0
  57. package/assets/img/pighub-1213.png +0 -0
  58. package/assets/img/pighub-1222.png +0 -0
  59. package/assets/img/pighub-1226.png +0 -0
  60. package/assets/img/pighub-1232.png +0 -0
  61. package/assets/img/pighub-1236.png +0 -0
  62. package/assets/img/pighub-1243.png +0 -0
  63. package/assets/img/pighub-1244.png +0 -0
  64. package/assets/img/pighub-1252.png +0 -0
  65. package/assets/img/pighub-1256.png +0 -0
  66. package/assets/img/pighub-1279.png +0 -0
  67. package/assets/img/pighub-129.png +0 -0
  68. package/assets/img/pighub-1305.png +0 -0
  69. package/assets/img/pighub-1318.png +0 -0
  70. package/assets/img/pighub-1320.png +0 -0
  71. package/assets/img/pighub-134.png +0 -0
  72. package/assets/img/pighub-138.png +0 -0
  73. package/assets/img/pighub-142.png +0 -0
  74. package/assets/img/pighub-148.png +0 -0
  75. package/assets/img/pighub-151.png +0 -0
  76. package/assets/img/pighub-155.png +0 -0
  77. package/assets/img/pighub-159.png +0 -0
  78. package/assets/img/pighub-164.png +0 -0
  79. package/assets/img/pighub-167.png +0 -0
  80. package/assets/img/pighub-175.png +0 -0
  81. package/assets/img/pighub-182.png +0 -0
  82. package/assets/img/pighub-188.png +0 -0
  83. package/assets/img/pighub-192.png +0 -0
  84. package/assets/img/pighub-197.png +0 -0
  85. package/assets/img/pighub-199.png +0 -0
  86. package/assets/img/pighub-2.png +0 -0
  87. package/assets/img/pighub-201.png +0 -0
  88. package/assets/img/pighub-209.png +0 -0
  89. package/assets/img/pighub-210.png +0 -0
  90. package/assets/img/pighub-217.png +0 -0
  91. package/assets/img/pighub-219.png +0 -0
  92. package/assets/img/pighub-222.png +0 -0
  93. package/assets/img/pighub-24.png +0 -0
  94. package/assets/img/pighub-242.png +0 -0
  95. package/assets/img/pighub-243.png +0 -0
  96. package/assets/img/pighub-244.png +0 -0
  97. package/assets/img/pighub-249.png +0 -0
  98. package/assets/img/pighub-250.png +0 -0
  99. package/assets/img/pighub-252.png +0 -0
  100. package/assets/img/pighub-254.png +0 -0
  101. package/assets/img/pighub-255.png +0 -0
  102. package/assets/img/pighub-258.png +0 -0
  103. package/assets/img/pighub-261.png +0 -0
  104. package/assets/img/pighub-262.png +0 -0
  105. package/assets/img/pighub-266.png +0 -0
  106. package/assets/img/pighub-267.png +0 -0
  107. package/assets/img/pighub-27.png +0 -0
  108. package/assets/img/pighub-271.png +0 -0
  109. package/assets/img/pighub-272.png +0 -0
  110. package/assets/img/pighub-273.png +0 -0
  111. package/assets/img/pighub-275.png +0 -0
  112. package/assets/img/pighub-276.png +0 -0
  113. package/assets/img/pighub-280.png +0 -0
  114. package/assets/img/pighub-282.png +0 -0
  115. package/assets/img/pighub-283.png +0 -0
  116. package/assets/img/pighub-286.png +0 -0
  117. package/assets/img/pighub-29.gif +0 -0
  118. package/assets/img/pighub-293.png +0 -0
  119. package/assets/img/pighub-294.png +0 -0
  120. package/assets/img/pighub-296.png +0 -0
  121. package/assets/img/pighub-300.png +0 -0
  122. package/assets/img/pighub-311.png +0 -0
  123. package/assets/img/pighub-315.png +0 -0
  124. package/assets/img/pighub-328.png +0 -0
  125. package/assets/img/pighub-334.png +0 -0
  126. package/assets/img/pighub-337.png +0 -0
  127. package/assets/img/pighub-341.png +0 -0
  128. package/assets/img/pighub-351.png +0 -0
  129. package/assets/img/pighub-356.png +0 -0
  130. package/assets/img/pighub-366.png +0 -0
  131. package/assets/img/pighub-369.png +0 -0
  132. package/assets/img/pighub-372.png +0 -0
  133. package/assets/img/pighub-376.png +0 -0
  134. package/assets/img/pighub-379.png +0 -0
  135. package/assets/img/pighub-38.png +0 -0
  136. package/assets/img/pighub-40.png +0 -0
  137. package/assets/img/pighub-404.png +0 -0
  138. package/assets/img/pighub-408.png +0 -0
  139. package/assets/img/pighub-409.png +0 -0
  140. package/assets/img/pighub-417.png +0 -0
  141. package/assets/img/pighub-423.png +0 -0
  142. package/assets/img/pighub-426.png +0 -0
  143. package/assets/img/pighub-439.png +0 -0
  144. package/assets/img/pighub-44.png +0 -0
  145. package/assets/img/pighub-452.png +0 -0
  146. package/assets/img/pighub-461.png +0 -0
  147. package/assets/img/pighub-462.png +0 -0
  148. package/assets/img/pighub-463.png +0 -0
  149. package/assets/img/pighub-468.png +0 -0
  150. package/assets/img/pighub-469.png +0 -0
  151. package/assets/img/pighub-473.png +0 -0
  152. package/assets/img/pighub-479.png +0 -0
  153. package/assets/img/pighub-481.png +0 -0
  154. package/assets/img/pighub-497.png +0 -0
  155. package/assets/img/pighub-511.png +0 -0
  156. package/assets/img/pighub-512.png +0 -0
  157. package/assets/img/pighub-513.png +0 -0
  158. package/assets/img/pighub-544.png +0 -0
  159. package/assets/img/pighub-55.png +0 -0
  160. package/assets/img/pighub-556.png +0 -0
  161. package/assets/img/pighub-560.png +0 -0
  162. package/assets/img/pighub-563.png +0 -0
  163. package/assets/img/pighub-583.png +0 -0
  164. package/assets/img/pighub-589.png +0 -0
  165. package/assets/img/pighub-590.png +0 -0
  166. package/assets/img/pighub-598.png +0 -0
  167. package/assets/img/pighub-599.png +0 -0
  168. package/assets/img/pighub-600.png +0 -0
  169. package/assets/img/pighub-604.png +0 -0
  170. package/assets/img/pighub-606.png +0 -0
  171. package/assets/img/pighub-607.png +0 -0
  172. package/assets/img/pighub-608.png +0 -0
  173. package/assets/img/pighub-609.png +0 -0
  174. package/assets/img/pighub-61.png +0 -0
  175. package/assets/img/pighub-610.png +0 -0
  176. package/assets/img/pighub-613.png +0 -0
  177. package/assets/img/pighub-631.png +0 -0
  178. package/assets/img/pighub-641.png +0 -0
  179. package/assets/img/pighub-65.png +0 -0
  180. package/assets/img/pighub-650.png +0 -0
  181. package/assets/img/pighub-652.png +0 -0
  182. package/assets/img/pighub-655.png +0 -0
  183. package/assets/img/pighub-658.png +0 -0
  184. package/assets/img/pighub-659.png +0 -0
  185. package/assets/img/pighub-66.png +0 -0
  186. package/assets/img/pighub-661.png +0 -0
  187. package/assets/img/pighub-664.png +0 -0
  188. package/assets/img/pighub-67.png +0 -0
  189. package/assets/img/pighub-675.png +0 -0
  190. package/assets/img/pighub-676.png +0 -0
  191. package/assets/img/pighub-679.png +0 -0
  192. package/assets/img/pighub-680.png +0 -0
  193. package/assets/img/pighub-682.png +0 -0
  194. package/assets/img/pighub-683.png +0 -0
  195. package/assets/img/pighub-684.png +0 -0
  196. package/assets/img/pighub-685.png +0 -0
  197. package/assets/img/pighub-686.png +0 -0
  198. package/assets/img/pighub-695.png +0 -0
  199. package/assets/img/pighub-701.png +0 -0
  200. package/assets/img/pighub-705.png +0 -0
  201. package/assets/img/pighub-710.png +0 -0
  202. package/assets/img/pighub-723.png +0 -0
  203. package/assets/img/pighub-727.png +0 -0
  204. package/assets/img/pighub-744.png +0 -0
  205. package/assets/img/pighub-751.png +0 -0
  206. package/assets/img/pighub-768.png +0 -0
  207. package/assets/img/pighub-772.png +0 -0
  208. package/assets/img/pighub-774.png +0 -0
  209. package/assets/img/pighub-776.png +0 -0
  210. package/assets/img/pighub-780.png +0 -0
  211. package/assets/img/pighub-791.png +0 -0
  212. package/assets/img/pighub-792.png +0 -0
  213. package/assets/img/pighub-794.png +0 -0
  214. package/assets/img/pighub-804.png +0 -0
  215. package/assets/img/pighub-812.gif +0 -0
  216. package/assets/img/pighub-813.gif +0 -0
  217. package/assets/img/pighub-814.png +0 -0
  218. package/assets/img/pighub-815.png +0 -0
  219. package/assets/img/pighub-829.png +0 -0
  220. package/assets/img/pighub-830.png +0 -0
  221. package/assets/img/pighub-836.png +0 -0
  222. package/assets/img/pighub-854.gif +0 -0
  223. package/assets/img/pighub-860.png +0 -0
  224. package/assets/img/pighub-861.png +0 -0
  225. package/assets/img/pighub-865.png +0 -0
  226. package/assets/img/pighub-866.png +0 -0
  227. package/assets/img/pighub-868.png +0 -0
  228. package/assets/img/pighub-872.png +0 -0
  229. package/assets/img/pighub-873.png +0 -0
  230. package/assets/img/pighub-874.png +0 -0
  231. package/assets/img/pighub-878.gif +0 -0
  232. package/assets/img/pighub-879.png +0 -0
  233. package/assets/img/pighub-88.png +0 -0
  234. package/assets/img/pighub-880.png +0 -0
  235. package/assets/img/pighub-895.png +0 -0
  236. package/assets/img/pighub-902.png +0 -0
  237. package/assets/img/pighub-906.png +0 -0
  238. package/assets/img/pighub-910.png +0 -0
  239. package/assets/img/pighub-920.png +0 -0
  240. package/assets/img/pighub-921.png +0 -0
  241. package/assets/img/pighub-922.png +0 -0
  242. package/assets/img/pighub-925.png +0 -0
  243. package/assets/img/pighub-927.png +0 -0
  244. package/assets/img/pighub-930.png +0 -0
  245. package/assets/img/pighub-932.png +0 -0
  246. package/assets/img/pighub-933.png +0 -0
  247. package/assets/img/pighub-936.png +0 -0
  248. package/assets/img/pighub-948.png +0 -0
  249. package/assets/img/pighub-950.png +0 -0
  250. package/assets/img/pighub-953.png +0 -0
  251. package/assets/img/pighub-955.png +0 -0
  252. package/assets/img/pighub-97.png +0 -0
  253. package/assets/img/pighub-974.png +0 -0
  254. package/assets/img/pighub-975.png +0 -0
  255. package/assets/img/pighub-981.png +0 -0
  256. package/assets/img/pighub-986.png +0 -0
  257. package/assets/img/pighub-989.png +0 -0
  258. package/assets/img/pighub-993.png +0 -0
  259. package/assets/img/pighub-994.png +0 -0
  260. package/assets/img/standard-pig.png +0 -0
  261. package/assets/libraries.json +141 -0
  262. package/assets/manifest.json +7134 -134
  263. package/lib/assets.js +17 -1
  264. package/lib/client.js +1432 -222
  265. package/lib/desktop-pet.js +447 -0
  266. package/lib/imaging.js +319 -0
  267. package/lib/index.js +500 -42
  268. package/lib/native/pet-window.cs +768 -0
  269. package/lib/store.js +131 -8
  270. package/package.json +9 -4
  271. package/test/client.test.mjs +893 -20
  272. package/test/host.test.mjs +282 -12
  273. package/test/imaging.test.mjs +106 -10
  274. package/test/lifecycle.test.mjs +87 -0
  275. package/test/smoke.mjs +130 -11
  276. package/test/store.test.mjs +72 -2
  277. package/assets/img/pig-1300.png +0 -0
  278. package/assets/img/pig-1354.png +0 -0
  279. package/assets/img/pig-1355.svg +0 -1
  280. package/assets/img/pig-1357.png +0 -0
  281. package/assets/img/pig-1360.png +0 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,1062 @@
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
+
132
+ ## [0.9.47] — 2026-11-13
133
+
134
+ ### Changed — 围栏按设计方案 A 落地(正方形·平涂·闭合框)
135
+
136
+ - 侧栏改为**同族栏身**:两道竖横杆 + 3 根横躺短柱,上下各伸进角柱 1 单位;
137
+ - **角柱加宽到 6.7 单位**——上一版「转角断开」的根因是侧栏横杆跨度 x 4.8–9.6 够不到角柱(只占 8.9–14.1);
138
+ - 柱子落地三件套:柱脚深色段 + 压扁接触影 + 栏带内缘接触暗带;
139
+ - 草地改四块平涂(远坡冷/近坡暖,波浪硬边)+ 26 丛稀疏三叶草,**去掉渐变与暗角**;
140
+ - 小屋换成 SVG,bottom 13%,不再戳穿近栏;
141
+ - 投影单独成层 `.pighub-fence-shadow`,不再糊在木构件上。
142
+
143
+ ### Changed — 素材到 256 只
144
+
145
+ - 收编到 **256 只**(静态 +5、动画 +5;动画卡新增 `scripts/gif-alpha.py` 去除边缘连通近白底);
146
+ - 修掉收编覆盖回归:`adopt-cards.mjs` 不再重写已存在的素材文件(既有 246 个 sha256 0 改);
147
+ - 按硬理由剔掉 4 张动画卡(818 核爆帧无猪、808/809 与 813 同底图、1131 与库里同 sha)。
148
+
149
+ ## [0.9.46] — 2026-11-13
150
+
151
+ ### Changed — 围栏回到「正方形 · 无景深 · 不透视」
152
+
153
+ 用户三次修正的最终口径:**正正常常最简单的正方形围栏**。所以把 0.9.45 的梯形透视整个去掉:
154
+
155
+ - 四条边**完全平行**,同一栏高(7 单位)、同一粗细;
156
+ - 每边两道横杆 + 11 根等距柱子,柱粗一致,**没有近大远小、没有消失点、没有梯形**;
157
+ - 平涂木色 `#e3b478` / 柱色 `#c8934f`,方头线帽(不是圆头),干净收边。
158
+
159
+ ## [0.9.45] — 2026-11-13
160
+
161
+ ### Changed — 围栏改成「平面化 2.5D 正方形」
162
+
163
+ - 之前是三段 SVG(顶带 + 两条侧栏 + 底带)拼的,怎么调都像贴纸。现在换成**一张 SVG 铺满猪圈**:
164
+ 四条边按一点透视画(后边窄、前边宽),每条边两道扁平横杆 + 一排柱子,柱子近大远小,
165
+ 四条边在画布边缘**天然相接**,没有拼接缝。
166
+ - 风格:平涂木色 `#e5b574` / 柱色 `#c98f4e` + 细描边 + 轻微落地投影,不打光不渐变(平面卡通)。
167
+
168
+ ### Fixed — 三条误判 + 一处真 bug
169
+
170
+ - 242 / 376 / 40 解除 `incomplete`:现场核过,切的是**布景**(横幅/床架),猪身轮廓闭合;
171
+ - 659 / 865 的 side-body 记录与指纹补齐(子代理裁到内容 bbox 后重新挤出 24px,右脸占比 0.66/0.69 → 0.12/0.13);
172
+ - 记录一处待修:`extrude-complete.py` 的 ERASE 是**死代码**(擦边只作用在副本上),这是 v5/v6「擦不掉的暗线」的根因。
173
+
174
+ ## [0.9.44] — 2026-11-13
175
+
176
+ ### Changed — 猪圈美化(用户反馈:只是修边不算美化)
177
+
178
+ - **地面**:纯渐变绿 → 斜纹 + **草簇小点**(三套错位圆点做出毛绒质感)+ 中心提亮 + 四周暗角;新增 `.pighub-grass` 层;
179
+ - **围栏**:整条围栏加 `drop-shadow`(柱子像立在草地上)、立柱再加 1px 硬投影;
180
+ - **侧栏**:宽度 3.6% → **4.4%**,**加透视**——柱子沿纵深越来越密、越来越细(间距按 1-(1-t)^1.7 收窄),外缘加深色内阴影;
181
+ - 侧栏数量 7 → **9** 根,纵深更连贯。
182
+
183
+ ## [0.9.43] — 2026-11-13
184
+
185
+ ### Added — 图鉴入口(用户口径)
186
+
187
+ - 面板右上角新增「图鉴」按钮:打开一个网格,列出池子里**全部**猪猪;
188
+ - **未获取的猪覆盖为暗色剪影**(`filter:brightness(0) saturate(0); opacity:.28`),名字显示 **「???」**;
189
+ - 已获取的显示原名,标题栏显示已收集/总数;点「关闭」收起;
190
+ - 宿主快照新增 `pool`(id/名字/贴图地址,含未获取),图鉴不再依赖工具输出。
191
+
192
+ ## [0.9.42] — 2026-11-13
193
+
194
+ ### Changed — 猪圈围栏视觉(用户口径)
195
+
196
+ - **顶部不再多出一圈草坪**:围栏 SVG 的高度原本是 `tall + 6`,那 6 个单位留白显示的是草地,
197
+ 看起来像猪圈外面还有一条草坪。现在 `height = tall`,立柱与横杆直接贴到猪圈顶边。
198
+ - **侧面围栏改成真正的侧视**:原来的侧边是一条 `repeating-linear-gradient` 的「假栅栏」,
199
+ 和上下围栏不是一套语言。现在新增 `FenceSide` 组件,用**同样的立柱 + 双横杆**画竖直带
200
+ (侧视时横杆是竖线、立柱是一排短横条),上下与顶带/底带相接,左右镜像对称。
201
+
202
+ ## [0.9.41] — 2026-11-13
203
+
204
+ ### Changed — 普通猪的眼睛改成黑色(用户口径)
205
+
206
+ - 标准猪原本**整只没有任何深色像素**(最暗的颜色是粉色 `(252,124,132)`),眼睛和腮红是同一批粉点。
207
+ - 按用户要求把两个小圆点(面积约 970,左右对称)改成**纯黑** `(0,0,0)`,共 1939 px;耳朵与身上的 C 形花纹仍是粉色。
208
+ - manifest 的 sha256 / bytes / size 已更新,sizeRatio 已重算。
209
+
210
+ ## [0.9.40] — 2026-11-13
211
+
212
+ ### Changed
213
+
214
+ - 给 426 / 974 / 1099 在 manifest 里写入 `completion = { mode: 'not-completed', reason }`,把「为什么不补」固化成数据。
215
+
216
+ ## [0.9.39] — 2026-11-13
217
+
218
+ ### Changed — 逐卡补全 6/9 + 工具入库
219
+
220
+ - **pighub-341** 入库(`side-body`,右侧接躯干 + 两条腿,留 10px 边距)。
221
+ - 侧面模式并入仓库脚本 `scripts/complete-pigs-side.py`,并加入 **写回前自动备份**(`archive/asset-backup/<id>.png`)——
222
+ 上次把 1099 写坏就是因为没有备份,只能从打好的 tgz 里还原。
223
+ - 全量核对表:`archive/20261113-completion/check-table-final.png`(6 只 before/after + 模式,另标注 3 只未完成的原因)。
224
+
225
+ ### Still open
226
+
227
+ - **426**(左切):当前算法几乎看不出变化,需要另想办法;
228
+ - **974**(巨大侧脸,切口高 84%):通用参数接出来的身体比例过大且接缝可见;
229
+ - **1099**(俯视/正面半身像):补腿与圆底两版都不合适,保持原样。
230
+
231
+ ## [0.9.38] — 2026-11-13
232
+
233
+ ### Changed — 逐卡补全进度:5/9
234
+
235
+ | 卡 | 模式 | 说明 |
236
+ |---|---|---|
237
+ | pighub-868 / 379 / 255 | `bottom-legs` | 底部切断:腹部收口 + 3 条圆底腿 |
238
+ | pighub-865 / 659 | `side-body` | 右侧切断:向右接躯干 + 2 条腿(659 四周留 10px 边距) |
239
+ | pighub-1099 | 搁置 | 俯视/正面半身像,两版试补都不合适,保持原样 |
240
+ | 341 / 426 / 974 | 待做 | 预览已出,尚未逐张确认 |
241
+
242
+ 核对表:`archive/20261113-completion/check-table-v2.png`(逐张 before/after + 模式)。
243
+
244
+ ## [0.9.37] — 2026-11-13
245
+
246
+ ### Changed — 逐卡补全(第一批,3 只)
247
+
248
+ | 卡 | 切口 | 补法 |
249
+ |---|---|---|
250
+ | pighub-868 | 底部直线切断 | 抹掉切边硬线 → 腹部从切口宽度平滑收到腿宽 → 3 条圆底腿,统一填切口上方中位体色 |
251
+ | pighub-379 | 底部直线切断 | 同上 |
252
+ | pighub-255 | 底部(左侧还缺一点) | 同上;**左侧切口本轮未补** |
253
+
254
+ - 工具:`scripts/complete-pigs.py`(Pillow,`--write` 写回 assets 并更新 bytes/sha256/size/completion 记录)。
255
+ - 每只都留 before/after:`archive/20261113-completion/check-table.png`。
256
+
257
+ ### Deferred
258
+
259
+ - **pighub-1099**(俯视/正面半身像):试过补腿与圆底两版都不对(视角上不该有腿),**保持原样**,在 manifest 的 note 里标了「待补」。
260
+ - 剩下 5 只**侧面切口**(974/865/659/341/426)还没做:需要「往侧面接一段身体」,跟底部补的算法不同。
261
+
262
+ ## [0.9.36] — 2026-11-13
263
+
264
+ ### Added — 标准猪(普通猪)
265
+
266
+ - 侧边栏图标那只猪(`PIG_ICON_PATHS` 的矢量路径)在本机重新光栅化成 `assets/img/standard-pig.png`(482×433,朝左),
267
+ 作为 **普通猪** 进了素材库:id `standard-pig`、稀有度 common、`standard: true`、来源 `builtin`。
268
+ - **每个用户开局自带它**:`emptyState()` 直接带一只;老状态文件在 `normaliseState` 里幂等补上。
269
+ - 素材总数 118 → **119**。
270
+
271
+ ### Note
272
+
273
+ - 标准猪不进可爱闸门的 judged 记录(它不是上游素材),smoke 里对 `standard:true` 单独放行并断言其来源与说明。
274
+ - 它同时是**补全残缺素材的身体参考**(下一步逐卡补全用)。
275
+
276
+ ## [0.9.35] — 2026-11-13
277
+
278
+ ### Fixed — 「闪现」(位置跳变)
279
+
280
+ 排查出三条会让猪瞬移的路径,全部修掉:
281
+
282
+ 1. **渲染层用宿主 pos 覆盖 actor**(0.9.27 加的那个「兜底」):快照里的 `pig.pos` 总是滞后的,
283
+ 于是每 10 秒轮询、每次重渲染都可能把正在走的猪拽回旧点。现在 **actor 是唯一真相**,
284
+ 宿主 pos 只用来播种(还没有 actor 的那一帧)和触发「平滑走过去」。
285
+ 2. **外部位置变更直接赋值**:现在改成按「距离 ÷ 速度」平滑走过去(`walkMs`),不再瞬移。
286
+ 3. **原生窗口每次 sync 都把坐标重置**:改运动开关/星级/penRect 都会重写 pets.json,
287
+ 旧代码每次都从文件覆盖 `pet.X/Y`,正在走动的桌宠被拽回上一版坐标。
288
+ 现在只在**第一次看到这只猪**时采纳文件坐标。
289
+
290
+ ## [0.9.34] — 2026-11-13
291
+
292
+ ### Fixed
293
+
294
+ - **猪不再游走(自己引入的回归)**:0.9.33 加的「没变化就返回同一引用」只比较了 x/y/mode/dir,
295
+ 于是「发呆」这一拍新算的 `nextAt` 被丢掉、猪永远停在 `fresh` 状态 → 一只都不走。
296
+ 比较里补上 `fresh / nextAt / holdUntil`,并加了断言防止再犯。
297
+
298
+ ## [0.9.33] — 2026-11-13
299
+
300
+ ### Fixed — 游走回退(用户报障)
301
+
302
+ - **根因**:10 秒静默轮询拿回的快照可能带着「比本地写入更旧」的 `pig.pos`,客户端以为是外部改动就采纳了,
303
+ 正在走的猪被拽回上一个点——看起来就是「游走回退」。
304
+ - **修法**:每次上报位置都带 `posAt` 时间戳(宿主存进 state.json 并随快照回传),
305
+ 客户端**只采纳比自己最后一次写入更新**的位置。轮询因此变成安全的(外部改动仍然会被采纳)。
306
+
307
+ ### Changed — 性能(用户报卡顿)
308
+
309
+ - 游走调度器一拍下来没有任何 actor 变化时**返回同一个引用**,React 直接跳过重渲染(原来每 250ms 无条件刷新一次)。
310
+ - 悬停胶囊的 400ms 计时器改成「只有确实有胶囊到期」时才触发重渲染。
311
+ - 10 秒轮询拿到与上次完全相同的快照时不再 setState。
312
+
313
+ ### Changed — 整体缩小到 75%(用户口径)
314
+
315
+ - 新增 `PIG_SCALE = 0.75`:快照里的 `sizeRatio` 与原生窗口的 `size` 都乘它,
316
+ 基准从 96 CSS px 变成 **72 CSS px**。单步距离与速度按「身位」定义,所以自动跟着缩小。
317
+
318
+ ## [0.9.32] — 2026-11-13
319
+
320
+ ### Fixed
321
+
322
+ - **面板没打开时桌宠只有一半大**:宿主按 `sizeRatio × devicePixelRatio` 下发物理尺寸,而 dpr 是浏览器半上报的——
323
+ 插件刚重启、面板还没打开过时 dpr=1,桌宠就以一半尺寸出现。现在宿主只下发 **CSS px**(= sizeRatio),
324
+ 原生窗口用 `GetDpiForWindow` 自己换成物理像素(它本来就是 per-monitor DPI aware)。
325
+
326
+ ## [0.9.31] — 2026-11-13
327
+
328
+ ### Fixed
329
+
330
+ - 胶囊档位读错来源:prefs 是**独立文件**(`prefs.json`),代码却从 state 里取 `state.prefs`,
331
+ 永远是 undefined → 一直按 hover 下发。改用 `readPrefs(root)`。
332
+
333
+ ## [0.9.30] — 2026-11-13
334
+
335
+ ### Fixed
336
+
337
+ - `petsPayload` 只挑了 id/path/x/y/size/motion 几个字段,把 `stars` 丢了——胶囊在原生窗口里始终不出现。现在补上。
338
+
339
+ ## [0.9.29] — 2026-11-13
340
+
341
+ ### Added — 星级胶囊上桌面(goal 验收线 4 收口)
342
+
343
+ - 原生窗口现在也会画**星级胶囊**:宿主把 `stars` 与胶囊档位 `starMode`(off / hover / always)随 `pets.json` 下发,
344
+ 原生进程在合成时按同一档位画一个小药丸(`★N`)。悬停判定用当前光标是否落在猪的包围盒内。
345
+ - 至此三层的视觉要素齐了:尺寸、朝向镜像、跳动起伏、星级胶囊。
346
+
347
+ ## [0.9.28] — 2026-11-13
348
+
349
+ ### Fixed / Added
350
+
351
+ - **渲染以宿主 pos 为准**:actor 状态偶尔没跟上宿主记录的位置,画面就停在上一次的位置;
352
+ 现在只要不是正在走,就用 `pig.pos` 渲染(位置只有一份真相)。这是「位置记了但没生效」的根治。
353
+ - README 新增「三层一致:尺寸、运动、进出」一节,把尺寸口径与运动服务写成一张表。
354
+
355
+ ### Verified(真机,指针级往返)
356
+
357
+ | 段 | 数据 | 误差 |
358
+ |---|---|---|
359
+ | 圈 → 桌面 | 拖到 (1900,1150) → 原生窗口 (1786,1081)+226×139 → 中心 (1899,1151) | **(-1, +1) px** |
360
+ | 桌面 → 圈 | 拖到 (1000,700) → `pig.pos=(44.77,64.72)` → 像素 (1000,700) | **(0, 0) px** |
361
+ | 尺寸不变 | 往返前后 `sqrt(不透明面积)` 143.8 → 144.2 | 差异 < 1% |
362
+
363
+ ## [0.9.27] — 2026-11-13
364
+
365
+ ### Added
366
+
367
+ - 设置浮层显示客户端 bundle 版本(vX.Y.Z),用于确认浏览器半真的换上了新包。
368
+
369
+ ## [0.9.26] — 2026-11-13
370
+
371
+ ### Fixed
372
+
373
+ - 面板每 10 秒静默拉一次快照(外部改了状态时界面不再一直停在旧位置)。
374
+
375
+ ## [0.9.25] — 2026-11-13
376
+
377
+ ### Fixed
378
+
379
+ - **拖回猪圈的落点纵向偏高 44px**:原生窗口上报中心点时用 `pet.Size / 2` 当了高的一半,
380
+ 而 `Size` 是宽度。扁猪(纵横比 0.61)因此把中心算低了 44px。
381
+ 现在高度按素材纵横比算:`height = size × sprite.Height / sprite.Width`。
382
+
383
+ ### Verified(真机,指针级往返)
384
+
385
+ | 段 | 数据 | 误差 |
386
+ |---|---|---|
387
+ | 圈 → 桌面 | 拖到 (1900,1150) → 原生窗口 (1786,1081)+226×139 → 中心 (1899,1150) | **1 px** |
388
+ | 桌面 → 圈 | 拖到 (1000,700) → 命令中心 → `pig.pos=(44.77,69.59)` → 像素 (1000,744) | X **0 px** / Y **44 px**(本条已在本版修复) |
389
+
390
+ ## [0.9.24] — 2026-11-13
391
+
392
+ ### Added
393
+
394
+ - 设置浮层显示「插件版本:vX.Y.Z」——用于确认浏览器半真的换上了新 bundle(本轮排查反复卡在这点上)。
395
+
396
+ ## [0.9.23] — 2026-11-13
397
+
398
+ ### Fixed
399
+
400
+ - **面板数据不会自发刷新**:只有面板自己发请求时才更新,别的窗口或工具改了状态(例如 `pig.pos`)界面上还是旧的。
401
+ 实测踩到:外部把猪设到 (33.69%,20.39%),面板仍画在网格兜底位置。现在每 10 秒静默拉一次快照。
402
+
403
+ ## [0.9.22] — 2026-11-13
404
+
405
+ ### Added — 三层朝向一致(goal 验收线 4)
406
+
407
+ - 页面级桌宠浮层现在也会按运动方向镜像(`--pighub-dir` + `scaleX`),与猪圈本体、原生窗口(`pet-window.cs` 的镜像绘制)一致。
408
+
409
+ ### Verified(真机,命令级往返)
410
+
411
+ | 段 | 数据 |
412
+ |---|---|
413
+ | 圈 → 桌面 | 落点中心 (1900,1150) → 原生窗口左上角 (1787,1081) → 中心 (1900,1150),**误差 0px** |
414
+ | 桌面 → 圈 | 注入 return 中心 (900,300) → `pig.pos=(33.69,20.39)` → 反算像素 (900,300),**误差 0px** |
415
+ | 尺寸不变 | 往返前后 `sqrt(不透明面积)` 都是 **144.0** |
416
+
417
+ ## [0.9.21] — 2026-11-13
418
+
419
+ ### Fixed
420
+
421
+ - **静止的猪不采纳宿主改的位置**:播种逻辑里「宿主位置变了就采纳」这段排在 `!canMove` 分支**之后**,
422
+ 于是「保持静止」的猪永远接不到新落点——拖回猪圈时它不会落在松手处。现在判定提到前面,
423
+ 静止猪也会被搬到新位置(只是不走动)。
424
+ - 该分支同时把 `mode`/`fresh`/`nextAt` 按是否允许运动分别处理,不会给静止猪排游走计时。
425
+
426
+ ## [0.9.20] — 2026-11-13
427
+
428
+ ### Fixed
429
+
430
+ - **拖出猪圈的落点差半个身位**:原生窗口的 (x,y) 是左上角,而指针停在猪身上时语义是中心。
431
+ 上报落点时减掉半个身位(宽 `sizeRatio×dpr`、高再乘素材纵横比 `aspect`),松手时猪的中心正好在指针处。
432
+ - **桌宠初始位置用旧坐标**:拖出时只更新了页面浮层的种子,宿主那边 `pig.desktopPos` 还是上次的,原生窗口从旧位置冒出来。
433
+ 新增 `{action:'desktopPos'}` 动作,拖出时把落点一并报给宿主。
434
+ - **拖动可能永远不结束**:指针在猪之外松开(或系统取消)时 `endDrag` 不会被调用,那只猪会一直 `is-hidden`,
435
+ 既看不见也再也拖不动。加了 document 级 `pointerup/pointercancel/blur` 兜底。
436
+
437
+ ## [0.9.19] — 2026-11-13
438
+
439
+ ### Added
440
+
441
+ - 拖动兜底(见 0.9.20 的第三条)。
442
+
443
+ ## [0.9.18] — 2026-11-13
444
+
445
+ ### Added
446
+
447
+ - `desktopPos` 动作:浏览器半把桌面落点(物理像素)报给宿主,写进 `pig.desktopPos`。
448
+
449
+ ## [0.9.17] — 2026-11-13
450
+
451
+ ### Changed — 从桌面拖回来接着走,不重置节奏(goal 验收线 3)
452
+
453
+ - 面板会记下「上一帧还在桌宠名单里、这一帧回到猪圈」的 id(`returnedIds`),
454
+ 这些猪播种时用 `fresh:false, nextAt: now` ——**立刻恢复游走**,而不是像新抽到的猪那样先发呆一拍。
455
+ - 首次摆放 / 面板重开仍然保留「先站稳一拍」,所以「进入就在记录点」这条没被破坏。
456
+
457
+ ## [0.9.16] — 2026-11-13
458
+
459
+ ### Fixed
460
+
461
+ - 非 PNG 素材的口径:GIF 其实**带透明**(400×350 里只有 57400 个不透明像素),
462
+ 之前按「整块不透明」估,导致它被缩小到 48(其余是 75.6)。现在清单里可带 `sizeOpaque`,
463
+ 脚本优先用它;GIF 的不透明像素数已量好写进 manifest。
464
+ - 独立复测(Pillow 重跑一遍、不依赖脚本自述):**117 只的视觉体量极差 1.6%**(74.33 – 75.52),远低于 15% 的验收线;
465
+ 唯一没进统计的是那只 SVG(Pillow 读不了)。
466
+
467
+ ## [0.9.15] — 2026-11-13
468
+
469
+ ### Added — 视觉体量归一化 sizeRatio(goal 验收线 1)
470
+
471
+ - 新增 `scripts/size-ratios.mjs`:用 Node 内置 zlib 自解 PNG,统计每只猪的**不透明像素数 A** 与宽 W,
472
+ 按 `ratio = W / sqrt(A)` 求系数并把中位数拉到 **96px**,写进 `manifest.pigs[].sizeRatio`。
473
+ 口径记在 `manifest.sizeRatioBasis`(sqrt(opaque area) / 96px)。
474
+ - 三层共用这一系数:猪圈本体 `width: sizeRatio px`、页面浮层同宽、原生窗口下发 `size = sizeRatio × dpr`。
475
+ - 单步距离与速度也随各自身位走(1 身位 = 这只猪自己的宽度),所以大猪走大一点、小猪走小一点。
476
+
477
+ ### 数据
478
+
479
+ - 118 只全部测到:sizeRatio 范围 **62.81 – 120.84**,中位数 96;
480
+ 按口径换算后的「视觉体量」= sqrt(渲染不透明面积),极差 **0.0%**(构造使然,用来自检公式)。
481
+
482
+ ## [0.9.14] — 2026-11-13
483
+
484
+ ### Added — 拖回猪圈落在松手处(进出连续,用户口径)
485
+
486
+ - 原生窗口的 `return` 命令现在带上这只猪**中心的屏幕坐标(物理像素)**。
487
+ - 宿主用 `penPercentFromScreen(x, y, penRect)` 把它换算成猪圈内的百分比(夹在 10–90 / 16–88),
488
+ 写回 `pig.pos` 再 `place(id,'pen')`——所以从桌面拖回猪圈时,猪**落在你松手的位置**,
489
+ 而不是回到它原来的落脚点。这一条是「猪圈进出连续性」的第一块。
490
+
491
+ ## [0.9.13] — 2026-11-13
492
+
493
+ ### Fixed — 桌宠比猪圈里的猪小一半(DPI)
494
+
495
+ - 原生窗口是 **per-monitor DPI aware**,它说的 96 是 **96 物理像素**;页面上的 96 是 **96 CSS px**(本机 dpr=2 即 192 物理像素)。
496
+ 实测同一只猪:猪圈里可见宽 **185px**,桌面上只有 **78px**。
497
+ 现在浏览器半把 `devicePixelRatio` 随 `penRect` 一起上报,宿主按 `96 × dpr` 下发尺寸;
498
+ 桌宠的落点种子(拖出猪圈的位置)也一并乘 dpr,否则会差一倍。
499
+
500
+ ## [0.9.12] — 2026-11-13
501
+
502
+ ### Fixed
503
+
504
+ - **猪圈内外大小仍不一致**:0.9.11 把两边都写成 96px,但猪圈本体是「宽 96、高自适应」,
505
+ 桌宠浮层却是「96×96 + `object-fit:contain`」——扁猪/瘦猪在桌宠层会被塞进方框里等比缩放,看起来更小。
506
+ 现在两层都是**宽 96、高自适应**(与原生窗口 `size=96` 等比高度一致)。
507
+ - **桌宠拖回猪圈有时不返回**:判定原来是「猪的**中心点**落在猪圈矩形内」,用户把猪头一段搭进猪圈就松手时不触发。
508
+ 改成**矩形相交**:猪身上任何一部分和猪圈重叠就算回圈。
509
+
510
+ ## [0.9.11] — 2026-11-13
511
+
512
+ ### Fixed — 拖动时「原地还留一只」
513
+
514
+ - `is-hidden` 这个 class **从来就没有对应样式**:拖动时只有 JSX 加了 class、CSS 里没有规则,
515
+ 所以本体照旧显示,加上跟着指针的影子就成了两只。现在有 `.pighub-actor.is-hidden{opacity:0;pointer-events:none}`。
516
+
517
+ ### Changed — 猪圈与桌宠完全一致(用户口径:以桌宠行为为准)
518
+
519
+ - **尺寸**:猪圈本体从「猪圈宽度的 15%」(本机约 68px)改成**固定 96px**,与桌面桌宠同一常数;
520
+ 拖动影子、桌宠浮层也统一 96px。CSS 里不再出现 `width:15%`。
521
+ - **步长**:改成与桌宠同一口径——**1.65–3.0 个身位**(桌宠是 `size × (1.65..3.0)`)。
522
+ 猪圈只有四个多身位宽,3 个身位的一步在里面必然撞墙,所以按**同一比例整体缩放**进活动区
523
+ (区间比例 3.0/1.65 保持与桌宠一致)。
524
+ - **速度**:每秒 1 个身位(96px/s),与桌宠的 `speed = size × 1.0` 一致;猪圈里换算成百分比。
525
+ - **桌宠浮层**(非 Windows 的回退路径)也换成同一套:1.7s 决策、72% 发呆、1.65–3.0 身位、恒速。
526
+
527
+ ### Added — 拖出猪圈松手即落点
528
+
529
+ - 从猪圈拖出去时,桌宠**就在松手处落地**(之前会落到屏幕右下角的默认位置):
530
+ `STORE.seedPet(id, x, y)` 记录落点,桌宠层首帧用它当初始坐标。
531
+
532
+ ## [0.9.10] — 2026-11-13
533
+
534
+ ### Changed — 猪圈内的游走对齐桌面桌宠(用户口径)
535
+
536
+ 「猪圈内的游走没有对齐桌宠的游走,我更喜欢现在桌宠的游走方式,对齐。」
537
+
538
+ 桌宠(`lib/native/pet-window.cs`)的模型搬到页面内:
539
+
540
+ | 维度 | 之前(猪圈) | 现在(对齐桌宠) |
541
+ |---|---|---|
542
+ | 决策节奏 | 每只猪随机等 1.5–6s | **固定 1.7s** 一次(每只猪自己一个 `nextAt`,各自独立) |
543
+ | 发呆 | 无(每次到点就走) | **72% 概率原地发呆** |
544
+ | 位移 | 固定 1.35s 缓动(`cubic-bezier`) | **恒速**:`transition-duration = 距离 / 速度`(15 个百分点/秒 = 每秒 1 个身位),`linear` |
545
+ | 步长 | [1/4, 1/3] 圈边长 | 不变(用户既定口径) |
546
+ | 起伏 | `pighub-travel` 跳动 | 不变 |
547
+
548
+ 净效果:猪不再是"隔很久猛跳一下",而是**慢慢走过去**,走完站定、再决定下一步,和桌面上那只一个气质。
549
+
550
+ ## [0.9.9] — 2026-11-13
551
+
552
+ ### Changed — 用户可见处不再出现「活猪 / 死猪」的话术
553
+
554
+ - **设置里的素材库只报总数**:原来写「版本 · 共 N 只(活 X · 死 Y)」,现在只有「版本 · 共 N 只」。
555
+ 「会不会动」是逐只的行为开关,不是分类。
556
+ - 顺手统一了行为判定:桌宠层(是否自走、是否播 idle 动画、签名重算)不再看素材的 `kind`,统一看 `pig.motion`,
557
+ 这样右键把某只猪设成"允许运动"后,桌宠层也会立刻动起来。
558
+ - README 里描述素材处理的句子改成「默认会不会动」,不再用活/死措辞(那是内部判定字段的名字)。
559
+
560
+ ## [0.9.8] — 2026-11-13
561
+
562
+ ### Fixed
563
+
564
+ - **拖回猪圈永远不触发**:`WM_LBUTTONUP` 里先 `Capture = false`,而释放捕获会**同步**触发
565
+ `WM_CAPTURECHANGED`——那个分支把 `dragging` 清空了,于是后面的"落点是否在猪圈里"判定拿到的永远是 null。
566
+ 改成先把引用取出来、再做其它事。
567
+
568
+ ## [0.9.7] — 2026-11-13
569
+
570
+ ### Fixed
571
+
572
+ - **0.9.6 把快照打挂了**:`penRect` 加进 `snapshot()`,但 `penRectOnScreen` 声明在 `apply()` 作用域里 →
573
+ `snapshot()` 一调用就 ReferenceError,`GET /pighub` 返回空 body(面板读不到数据)。
574
+ 变量提到模块级。教训:`snapshot()` 是模块级函数,它引用的状态也必须在模块级。
575
+
576
+ ## [0.9.6] — 2026-11-13
577
+
578
+ ### Added
579
+
580
+ - 快照里补 `penRect`(当前下发给原生窗口的猪圈屏幕矩形,物理像素),便于核对"拖回猪圈"的判定区。
581
+
582
+ ### Verified(真机,0.9.5/0.9.6)
583
+
584
+ 三个手势全部实测通过:拖动(796,1333 → 996,1433,宿主落盘 `desktopPos` 一致)、
585
+ 右键(写 `{"cmd":"menu"}` → 运动开关 false→true)、双击(写 `{"cmd":"return"}` → 回猪圈、进程退出、无残留)。
586
+
587
+ ## [0.9.5] — 2026-11-13
588
+
589
+ ### Fixed — 桌面桌宠「拖不动 / 右键没反应」(真机报障)
590
+
591
+ - **鼠标消息的坐标用了两次换算**:`WM_LBUTTONDOWN/MOUSEMOVE/LBUTTONUP/DBLCLK/RBUTTONUP` 的 `LParam` 本来就是
592
+ **客户区坐标**,代码却又调了一次 `PointToClient`,坐标被窗口原点平移,`HitTest` 永远落空 →
593
+ 按住没反应、右键也没反应。现在鼠标消息直接用 `LParam`,只有 `WM_NCHITTEST`(屏幕坐标)才换算。
594
+ - **抓取期间没有捕获鼠标**:`WS_EX_NOACTIVATE` 窗口不会自动 `SetCapture`,指针一离开那个小窗口就收不到
595
+ `WM_MOUSEMOVE`,拖动会中途断掉。现在 mousedown 时 `Capture = true`,释放/捕获被抢走时清状态。
596
+ - **首帧透明的窗口会整体穿透**:`canvas` 还没画出来时 `HitTest` 全部判空,窗口在启动瞬间点不到;
597
+ 现在空画布按"命中第一只猪"处理。
598
+
599
+ ### Added
600
+
601
+ - **拖回猪圈**:浏览器半每秒把实测的猪圈屏幕矩形上报给宿主(`{action:'penRect'}`),宿主下发到 `pets.json`;
602
+ 原生窗口在拖拽松手时判断猪的中心是否落在矩形内,是就发 `return` 命令,宿主把它 `place` 回猪圈。
603
+ - **回退提示**:桌宠存在但原生跑不起来(非 Windows / 编译失败)时,面板弹一次明确提示,
604
+ 而不是让用户以为"拖出去丢了"。
605
+
606
+ ## [0.9.4] — 2026-11-13
607
+
608
+ ### Changed
609
+
610
+ - **运动速度减慢**(用户口径):页面内一次位移的过渡 1.15s → **1.35s**(同样 25–33 个百分点的步长走得更从容),
611
+ 并断言"位移时长 < 最短等待 1.5s",避免下一步插进上一步的动画里;
612
+ 原生桌面桌宠的移动速度 `size × 1.6` → **`size × 1.0`**(同样 33ms 帧,约 96 px/s)。
613
+
614
+ ## [0.9.3] — 2026-11-13
615
+
616
+ ### Fixed
617
+
618
+ - **步长单位搞错了:每步只挪 0.3%(约 1px)**。actor 的 `x/y` 是**百分点**,而常量写成了 `1/4`、`1/3`
619
+ (= 0.25 与 0.33 个百分点)。真机现象就是"猪在原地抖"。现在 `STEP_MIN = 25`、`STEP_MAX = 100/3 ≈ 33.33`。
620
+ 单测当时断言的是同一个常量,所以没拦住——已补一条"常量必须是百分点量级"的断言。
621
+ - **贴边不再缩短步长**:改成"多试几个方向、挑落点仍在活动区的那一个",实际位移就等于选中的步长;
622
+ 12 次都失败才退回镜面反弹(角落里的可用方向是一段圆弧,基本不会失败)。
623
+
624
+ ## [0.9.2] — 2026-11-13
625
+
626
+ ### Fixed
627
+
628
+ - **贴边的猪会卡在角落迈碎步**:真机实测 974 连续三次只挪 0.2%(79.49→79.3→79.41)——因为步长是 1/4~1/3 圈边长,
629
+ 而旧实现是"目标越界就 clamp",靠近角落时每一步都被截成一两像素。改成**镜面反弹**(撞围栏弹回来),
630
+ 每一步仍是完整的一步;新增用例:四个角各走 200 步,碎步比例 < 5%。
631
+
632
+ ## [0.9.1] — 2026-11-13
633
+
634
+ ### Changed
635
+
636
+ - **单个步长 = [1/4, 1/3] 猪圈边长**(用户口径):上一版是 [0.55, 1]×1/3(≈18%–33%),现在下限明确到 1/4。
637
+ 方向仍随机,落点仍受活动区夹取。
638
+ - **等待时长随机 + 每只猪独立计时**(用户口径):丢掉全局 1.7s tick + 0.72 发呆概率的老模型,
639
+ 改成每只猪一个 `nextAt`,走完一步后随机等 **1.5–6 秒**(均值 ≈3.75s)再决定下一步;
640
+ 调度器只是每 250ms 扫一遍,谁到点谁动,所以猪不会"列队一起挪"。
641
+ - **进入猪圈不再从中心滑到位置**:首帧渲染用的种子与 effect 播种现在是同一个确定性坐标
642
+ (以前首帧兜底是 `{x:50,y:46}`,CSS 的 left/top 过渡会把它从中心滑过去)。
643
+
644
+ ## [0.9.0] — 2026-11-13
645
+
646
+ ### Added — 独立于 DSH 页面的**全局 Windows 桌面桌宠**
647
+
648
+ - `lib/native/pet-window.cs`:一个自制的 WinForms 顶层分层窗口(`ExStyle = 0x08080088`
649
+ = TOPMOST|LAYERED|TOOLWINDOW|NOACTIVATE,`UpdateLayeredWindow` 逐像素 alpha)。
650
+ **一个窗口画全部桌宠**(不是一只猪一个进程);窗口只围住猪的并集,透明处靠
651
+ `WM_NCHITTEST` 返回 `HTTRANSPARENT` 让鼠标穿过去;`CS_DBLCLKS` 让双击可识别。
652
+ - `lib/desktop-pet.js`:编译缓存(**按 `pet-window.cs` 源码 sha256 前 20 位**建目录,改一行就重编)、
653
+ 拉起/停止(写 `stop` 文件,1.5s 后才强杀)、目录 IPC(`pets.json` 下行 / `positions.json` + `commands.jsonl` 上行)。
654
+ - 宿主每次状态变化都会同步桌宠:没有桌面猪就停进程;有就拉起并写负载。
655
+ **位置持久化**:原生窗口每 400ms 回报位置,宿主节流写进 `state.json` 的 `pig.desktopPos`(屏幕像素,
656
+ 与猪圈里的 `pig.pos`(百分比)分开)。
657
+ - 双击 → 回猪圈(`commands.jsonl` 的 `return`);右键 → 切换这只猪的运动开关。
658
+ - 页面级浮层在原生桌宠运行时自动收起,避免一只猪两个身子。
659
+
660
+ ### Note — 平台与代价(必须知道)
661
+
662
+ - **只支持 Windows**:`process.platform !== 'win32'` 时 `startDesktopPet` 返回
663
+ `unsupported_platform`,插件保留原来的页面级浮层,不报错、不降级成半个功能。
664
+ - **首次运行要编译**:用系统自带的 `%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe`
665
+ 编 `pet-window.cs`(本机实测产物约 30–90 KB,编译 1–3 秒),之后按源码哈希复用。
666
+ 包里带的是 **C# 源码**(约 15 KB),不是二进制。
667
+ - `TOPMOST` 会盖住全屏应用(游戏/视频);暂时没有开关。
668
+
669
+ ## [0.8.6] — 2026-11-13
670
+
671
+ ### Fixed
672
+
673
+ - **拖动中的猪不再自己游走**:游走 tick 现在跳过正在拖的那只(`usePenActors(pigs, reduced, draggingId)`),
674
+ 位置只由指针决定。
675
+ - **松手后固定落点**:落点带 `fresh` + `holdUntil = now + 6s`,落地后原地站稳约 3 个 tick 才可能继续走。
676
+ 以前松手后下一拍就自己走开,「拖到哪儿」根本看不出来。
677
+ - **拎起来和放下的尺寸一致**:拖动影子按猪圈里那只的实际渲染尺寸(猪圈宽 × 15%)显示,
678
+ 不再固定 72px——避免拿起/放下时突然缩一圈。
679
+
680
+ ## [0.8.5] — 2026-11-13
681
+
682
+ ### Changed
683
+
684
+ - **步长倾向逼近上限**:原来距离在 [0, 1/3 圈边长] 均匀取,均值只有上限一半,看着还是"挪一点点"。
685
+ 现在取 [0.55, 1.0]×上限(均值 77.5%),方向仍随机。
686
+ - **进入面板就在记录位置**:新增「宿主位置变更」判定(`pig.pos` 进签名 + `seenPos` 去重),
687
+ 换窗口/换视图进来时立刻落到 `state.json` 记的那个点;首次摆放也会立刻记一笔(不再每次重新随机)。
688
+ 刚摆好的那一帧带 `fresh`,**第一个 tick 先发呆**,所以"进门就在原地"不是只维持 1.7 秒。
689
+
690
+ ## [0.8.4] — 2026-11-13
691
+
692
+ ### Changed
693
+
694
+ - **拖动改成「自由拖动」**:拖动中把猪圈里的**本体隐藏**(`.is-hidden`),页面上只剩跟着指针的那一只。
695
+ 以前本体没藏,拖动时枪枪"原地还有一个",看起来像复制了一只。
696
+ - **猪圈内拖动 = 换位置**:在圈里松手不再算「取消」,而是把落脚点改成松手处(按矩形换算成百分比并写回宿主)。
697
+ - **游走步长上限改为 1/3 猪圈边长**(用户口径):先前按「2 倍猪半径」=15% 太拘谨,配上 0.72 发呆权重几乎看不出在动;
698
+ 现在上限 33.3%(本机猪圈 451px ⇒ 约 150px/步),仍按欧氏距离卡,不越出围栏。
699
+
700
+ ### Added
701
+
702
+ - **落点持久化**:`state.json` 的每只猪新增 `pos: {x,y}`(百分比)。走动与拖放都会写回,
703
+ 下次打开面板(或换会话)时从记过的位置接着走,不再"每次都从网格原点重新开始"。
704
+ 新 HTTP 动作 `{action:'position', pigId, x, y}`;越界/非数字一律 `bad_position` 拒收,不覆盖旧落点。
705
+
706
+ ## [0.8.3] — 2026-11-13
707
+
708
+ ### Changed
709
+
710
+ - **单步距离改成「绝对步长 ≤ 2 倍猪半径」**:猪的尺寸是相对猪圈定义的(`.pighub-actor` 宽 15% 圈边长),
711
+ 所以猪半径 = 7.5%、2r = 15% 圈边长——换算成像素就是「每步最多挪自己一个身位」。距离按**欧氏距离**卡
712
+ (随机方向 + 随机距离 ≤ 2r),不是每轴各卡一次:每轴各卡 15% 时对角步长会是 21%,等于 2.8 个身位。
713
+ 常量 `PIG_RADIUS_RATIO=0.075` / `STEP_LIMIT=0.15`,测试断言欧氏距离、活动区边界与「2r 正好等于两倍半径」。
714
+ - **桌宠可以拖回猪圈**:以前只有双击回圈。现在把桌宠拖到猪圈矩形内松手即回圈(落点用面板实测后报给 store 的
715
+ `penRect` 判定),圈外松手保持原位。提示文案同步改成「拖进猪圈或双击都回猪圈」。
716
+
717
+ ## [0.8.2] — 2026-11-13
718
+
719
+ ### Changed
720
+
721
+ - **拖动最高优先,不许连带选中文字**:面板与桌宠层整体 `user-select:none`;猪本体与桌宠的 `pointerdown`
722
+ 都 `preventDefault()`(掐掉原生拖图/选区/焦点转移);拖动期间给 `body` 挂 `pighub-dragging`,
723
+ 连 `!important` 级别的 `user-select:none` 一起上——因为拖出面板后选区会落到下面的聊天区。
724
+ - **发呆权重 0.28 → 0.72**:每个 tick 有 72% 概率原地发呆、28% 才走一步(tick 1.7s ⇒ 平均约 6 秒挪一小步)。
725
+
726
+ ### Added
727
+
728
+ - `pighub_about` 增加 `runtime` 字段:实测宿主进程能不能拿到 Electron `BrowserWindow`。
729
+ 桌面级桌宠(在整个桌面上走)只有两条路——宿主开透明置顶窗,或另起原生窗口进程;
730
+ 先探测再动手,不拿用户机器试错。
731
+
732
+ **实测结果(本机,2026-11-13)**:`{"electron":true,"browserWindow":false,"processType":"node","platform":"win32","keys":[]}`
733
+ —— `import('electron')` 能解析,但导出表是空对象、`BrowserWindow` 不是函数,且 `process.type` 是 `node`
734
+ 而不是 `browser`。**结论:插件宿主进程没有 Electron 主进程能力,开不了透明置顶窗口。**
735
+ 桌面级桌宠只能走「另起原生窗口进程」(NewMate 那条 WinForms 路),未在本轮实现。
736
+
737
+ ## [0.8.1] — 2026-11-13
738
+
739
+ ### Changed
740
+
741
+ - **侧边栏图标改成原色彩色**(用户口径:不要变黑白)。原来是单色剪影吃 `currentColor`,跟着侧栏配色走;
742
+ 现在把 `assets/img/pighub-1114.png` 整张图做平涂描摹(vectorise 量化成 5 个色块:玫红耳/腮、粉身、浅粉高光),
743
+ 每个色块一条 path、fill 用源图实测色值,外层仍 `scale(-1 1)` 镜像成朝右。
744
+ 代价是这个图标不再跟随侧栏亮/暗色——这是明确要的取舍,其它 UI 仍全走语义令牌。
745
+ - **限制每只猪单步移动的距离**:原先每次在整块猪圈里随机挑点(跨度可达 70% 圈宽),猪会「一步窜到对角」;
746
+ 现在单步上限横向 **12%**、纵向 **9%** 圈边长,并夹在活动区内(`PEN_BOX`),连续小跳才像在圈里溜达。
747
+ `penStep()` 抽成纯函数并通过 `plugin.__test` 暴露给离线测试:2000 次抽样断言单步不超限、不越界。
748
+
749
+ ## [0.8.0] — 2026-11-13
750
+
751
+ 目标「100 张可爱的猪猪角色卡」达成。逐条数字都可在 `assets/cards/index.json` 复核。
752
+
753
+ ### Added
754
+
755
+ - **角色卡扩到 111 张可用**:候选从 50 张扩到 334 张(累计处理),逐张目检后
756
+ **pass 111 / fail 95 / 待检 128**;111 张全部过可爱闸门(mood=cute + 逐条理由),
757
+ 其中 2 张被闸门明确拒收留档(恐怖猪「獠牙 + 嘴角血痕」、双面幽灵猪「一具身体三张脸」)。
758
+ - **`scripts/make-cards.mjs --append`**:默认模式会 `rm -rf` 整个 `assets/cards`(历史判定会被抹掉),
759
+ 扩包必须用 append:跳过已有 id、索引合并后重写、新条目 `vision=pending` 等人工判定。
760
+ - **卡片记录源图 URL**:这是 ATTRIBUTION 里挂了两天的缺口——此前只存产物与指纹,
761
+ 收编进冻结库时 `source` 指不到具体地址。现在每条卡都有 `url`,收编时一并写进 `source.url`。
762
+ - **`scripts/cards-report.mjs`**:从 `index.json` 生成 `assets/cards/README.md`(判定表与索引同源,杜绝手写漂移)。
763
+ - **`scripts/cards-selection.mjs`**:从索引生成 `selection.json`(pass+cute 全部进收编名单,reject 只留档)。
764
+
765
+ ### Changed
766
+
767
+ - **冻结库 31 → 118 只**(活 117 / 死 1 / 矢量 1,其中 104 张本轮收编 + 7 张与老素材同 id 跳过)。
768
+ 包内贴图 5.56 MB。
769
+
770
+ ### Fixed
771
+
772
+ - **收编会撞 id**:卡片里有 7 只与老素材同 id(圆猪/矮脚猪/小眼猪/苹果猪/墨镜猪/幽灵猪/红包猪),
773
+ 旧逻辑会把它们收编成第二份并**覆盖同名贴图**,导致清单出现重复 id、老素材指纹对不上。
774
+ 现在收编前先排除「老素材已占用的 id」,并在收编前做清单自检(指纹不符直接失败)。
775
+ - 被覆盖的 7 张老贴图已从 git 恢复,清单复核 `dupes=0`、`with url 118/118`。
776
+
777
+ ## [0.7.0] — 2026-11-12(未发布)
778
+
779
+ 用户这一轮给了六条交互口径 + 一条目标(详见 design.md §10.21)。逐条落地:
780
+
781
+ ### Changed
782
+
783
+ - **猪圈变大**:`width:min(46vmin,400px)` → `min(60vmin,560px)`(本机 1279×752 视口下 451 CSS px,原来 346)。
784
+ - **侧边栏 icon 换成 PigHub 标准 title 小猪(朝右)**:原来那只几何小猪是手画的、不是站内那只标准猪。
785
+ 现在用 `assets/img/pighub-1114.png` 的 alpha 掩膜描出轮廓(220px → vectorise(ε=1.4) → bbox 居中到 24 格),
786
+ 再 `translate(24 0) scale(-1 1)` 镜像成朝右;眼睛位置由源图深色连通块量出来换算。运行时零计算、零请求。
787
+ - **走动改成「朝运动方向 + 蹦跳」**:新增 `--pighub-dir`(素材默认朝左,向右走镜像);
788
+ 位移从「CSS 平移」改成外层 `pighub-travel` 的位移弧 + 内层 squash & stretch。
789
+ 顺带补上**两段从来没定义过的动画** `pighub-hop` / `pighub-breathe`——此前 `.is-walk`/`.is-idle` 引用了它们,
790
+ 等于一直在空转,这正是「只会平移」的根因之一。
791
+
792
+ ### Added
793
+
794
+ - **猪圈容量 12**:`PEN_CAP=12`。投放(抽猪、从仓库放出、从桌宠收回)时若已满 12 只,自动落到仓库,
795
+ 并回 `placement.capped`,前端提示「猪圈满了(最多 12 只),先住进仓库了」。快照里带 `penCap`/`penCount`。
796
+ - **列表筛选**:新增 全部 / 猪圈 / 桌宠 / 库存 四档,库存档显示数量;库存为空时给空态文案。
797
+ - **从列表放出库存猪**:点库存行即放回猪圈(满员则按上面的规则进仓库并提示)。
798
+ - **逐只运动开关**:右键猪本体或列表行 → 「允许运动 / 保持静止」,落进 `state.json` 的 `pig.motion`;
799
+ 静止的猪不再游走、不再响应点击,但仍可拖动。缺省回落素材判定 kind,老状态文件不需要迁移。
800
+ - 新增 HTTP 动作 `{action:'motion', pigId, motion}`;`place` 现在区分 `unknown_pig` 与 `unknown_place`。
801
+
802
+ ### Changed(界面口径)
803
+
804
+ - **列表不再标「活猪 / 死猪」**:会动/静止是行为开关,不是身份。列表只在「静止」时给一个提示标签,
805
+ 位置标签保留(库存 / 桌宠)。
806
+
807
+ ## [0.6.0] — 2026-11-12(未发布)
808
+
809
+ ### Added
810
+
811
+ - **可爱闸门(新硬约束)**:用户新增「要可爱,血腥怪异的不要」。判定表 `judgements.json` 与角色卡选择表
812
+ `assets/cards/selection.json` 都新增 `mood: 'cute' | 'reject'` + `moodReason`,与 `kind` 同级:
813
+ **没有理由就不许生成冻结库**。拒收口径写进 `manifest.moodGate`:血腥(獠牙撕咬/伤口/血)、
814
+ 身体恐怖(一具身体多张脸)、惊悚造型一律 reject。
815
+ - **冻结库 14 → 31 只**:把角色卡样例集里通过可爱闸门的 17 只收编进 `assets/img` 与 `manifest.json`
816
+ (抽象猪、欺负一只小猪、猪伤心哼!猪、+1猪、白羊猪、对牛弹猪、双子猪、简单风格猪、你是小猪、猪叠猪、
817
+ 萝卜幽灵猪、天气指令猪、续订猪猪、好猪好猪、猪外有猪、超级赛亚猪、猪咪猪咪猪)。
818
+ - **`scripts/adopt-cards.mjs`(`npm run assets:adopt`)**:只增不改的第二条写入口——
819
+ 校验 selection 的 mood/kind/vector/理由 → 核对卡片指纹字节 → 复制进 `assets/img` → 追加清单条目
820
+ (`adopted: true` + `source.via='cards'`)。幂等:重跑不会重复收编,也不会动老素材。
821
+
822
+ ### Changed
823
+
824
+ - `scripts/build-assets.mjs` 现在**保留收编素材**:重建前把 `adopted:true` 的贴图读进内存,
825
+ 重建后原样写回并并进清单——否则「重跑一次构建,扩包会静默消失」。
826
+ - `manifest.counts` 增加 `adopted`;`moodRejected` 留档拒收(本轮 2 条:恐怖猪、双面幽灵猪)。
827
+
828
+ ### Note(已知缺口)
829
+
830
+ - 角色卡管线(`scripts/make-cards.mjs`)没有把每张卡的**上游源图 URL** 落盘,所以收编素材的
831
+ `source` 只有 `via:'cards'` + 卡片产物路径与指纹,没有 url。已在 ATTRIBUTION 记缺口,下一轮补。
832
+
833
+ ## [0.5.10] — 2026-11-12(未发布)
834
+
835
+ ### Fixed
836
+
837
+ - **围栏只铺了猪圈宽度的约 59%**:`.pighub-fence-band` 是 `<svg>`(替换元素),只写 `left:0;right:0`
838
+ 而 `width:auto` 时按内在比例 shrink-to-fit —— 真机实测围栏宽 203 px / 猪圈 346 px(46vmin),
839
+ 于是上下两条围栏在右侧断开 40%。补 `width:100%`。
840
+ - **面板顶部写着「0 只猪猪可选」,但按「今日猪猪」能抽出猪**:那个数字取的是**下一版候选池**
841
+ (`catalog.count`),而真实安装里候选池为空、抽池是**冻结素材库**(`assets.total` = 14)。
842
+ 改成素材库口径,候选池只在真的有数时附在后面(`· 候选池 N 只`)。
843
+
844
+ ## [0.5.9] — 2026-11-12(未发布)
845
+
846
+ ### Fixed
847
+
848
+ - **真实宿主装不上**:宿主 `@deepseek-ai/dsh-tools` 0.2.2-rc.1 起 `ToolDefinition.output` 是必填项,
849
+ `pighub_about` 没声明它,整行插件在装配时报
850
+ `TypeError: tool "pighub_about" must declare output { schema, render, presentationMeta? }`,
851
+ Host 半不激活(`application: failed`),浏览器半也就没有 `/pighub` 数据路由可用。
852
+ 补上 `output: { schema: { type: 'object' }, render }`(`render` 返回单个 text ContentBlock)。
853
+ 冒烟测试相应加一条断言:`ToolDefinition.output` 缺失、schema 非 object、render 不返回 ContentBlock 都算失败。
854
+
855
+ ## [0.5.8] — 2026-11-12(未发布)
856
+
857
+ ### Changed
858
+
859
+ - **角色卡样例集全部目检完毕**:50 张(42 静态 + 1 动图 + 8 生成时排除),逐张判定写入 `assets/cards/README.md`。**26 通过 / 15 不合格**(63%),失败原因逐张可查:三角/圆形底卡 4、直角切边 5、图上文字 3、场景 1、比例异常 1、非猪 1。
860
+
861
+ ### Fixed
862
+
863
+ - `assets/work/` 只接受 `<id>.json`:子代理的中间产物(`cover_*.json`、`parts.json`、掩膜、截图)不再入库;构建时对不上的文件告警。
864
+
865
+ ## [0.5.7] — 2026-11-12(未发布)
866
+
867
+ ### Added
868
+
869
+ - **pighub-65 幽灵猪**:背景是**双色**——白 52.62%(中间光柱)+ 紫 rgb(88,76,112) 14.22%(左右两角),一个色键删不干净。做法:trim 收紧到猪 bbox(341×489)后,紫在框里只剩**左上角三角 479 px**,于是「白交给色键(T=220, all:true,removed 22,000 = 13.19%)+ 紫交给 1 个 erase 框」;光环(y≤106)与底部 2 个桃色斑点(y≥648)靠 trim 挤出画布(余量 38 / 16 px),erase 不必再管装饰。阈值余量:猪身 min 通道最大 214 ⇒ T=220 误删 0(T=212 才丢 4 px,T=208 丢 21 px 且全在轮廓)。复算核对:**349×497 / 不透明 144,270 px(猪 138,955 + 边缘过渡 5,315)/ 连通块 1 / 封闭洞 0 / palette 0.982 flatness 0.964**。
870
+
871
+ ## [0.5.7] — 2026-11-12(未发布)
872
+
873
+ ### Added
874
+
875
+ - **pighub-65 幽灵猪**:**双色背景**(白 52.62% 中间光柱 + 紫 14.22% 左右角),一个色键删不干净。解法是把 trim 收紧到猪 bbox 之后再看剩余量:紫只剩左上 479 px 三角 → 1 个 erase 框;白 22,000 px → 色键(threshold 220,猪身最亮 min=214,实测 T=220 误删 0 px)。装饰光环与底部斑点被 trim 挤出画布。成品 349×497,不透明连通块 = 1。
876
+
877
+ ## [0.5.6] — 2026-11-12(未发布)
878
+
879
+ ### Added
880
+
881
+ - **pighub-1256 红包猪**:白底 51.46%,猪 718,931 px。**`all: true` 必须开**:trim 内还剩 598 px 封闭白(尾卷环内的背景),`all:false` 会留成白斑(两版帧 sha 不同)。红包+金币 37,424 px **保留**——它的 1 px 外环 1,615 px 全接猪身、接背景 0 px,擦掉等于在猪背正中挖洞。复算核对:**512×469 / 195,067 B / removed 374,664** 三项与预测完全一致。
882
+
883
+ ### Changed
884
+
885
+ - `assets/work/` 只提交规格 JSON:子代理产出的测量脚本、掩膜 `.npy`、临时截图不再入库(`.gitignore` 加 `assets/work/*` + `!*.json`)。
886
+
887
+ ## [0.5.5] — 2026-11-12(未发布)
888
+
889
+ ### Added
890
+
891
+ - **pighub-369 苹果猪**:白底,猪 103,667 px + **苹果叶 5,628 px 是两个连通块**(叶子与猪同色,色键删不掉;但不能用 `keep` 保护——`keep` 走 restoreRects 会把框内白底一起还原),靠 trim 把紫色底纹与「苹果猪」文字整体排除。复算核对:**388×463 / 不透明 115,554 px / removed 75,097** 三项与规格预测**完全一致**;实测阈值 T=215~250 猪像素丢失全 0,T=200 丢 58。
892
+
893
+ ## [0.5.4] — 2026-11-12(未发布)
894
+
895
+ ### Added
896
+
897
+ - **最小补色 `patchMinimal()`**:猪身上的字与猪身粘连时,只能连猪身一起擦;擦完用**紧邻猪身色按距离扩散**补回去(多源 BFS,不整片糊一个中位色)。只补「外接框与 erase 框相交」的透明区,不扩散到擦除区之外。`work.inpaint: 'minimal'` 启用。
898
+ - 两项单测:字擦掉后用周围颜色补满且不出框;无 erase 框时不动。imaging 断言 11 → **13**。
899
+
900
+ ### Note(实测边界)
901
+
902
+ - 在真猪身上做了一次演示(`assets/cards/demo-*.png`):一条横贯猪身的「名字」擦掉后补色 21,280 px,黑色文字完全消失、颜色来自猪身;但**擦除带越宽、周围颜色越杂,补色越糊**——跨过粉色耳纹/腮红时会出现横向拖影。
903
+ - 结论:最小补色适合**字形尺寸**的擦除(单行字、水印);对整条横带的擦除,正确做法是缩窄 erase 框只盖字,而不是靠补色去糊。
904
+
905
+ ## [0.5.3] — 2026-11-12(未发布)
906
+
907
+ ### Added
908
+
909
+ - **角色卡样例集**(`assets/cards/`):从 PigHub 按「名字以猪/豚/包结尾且不含行为词」筛出 50 张,逐张跑同一套精修,产出 42 张静态卡 + 1 张动图 + 8 张生成时排除。
910
+ - **矩形底卡自动门槛**:连通块 bbox 填充率 ≥ 0.92 且面积 > 25% 判为底卡、不产出(本轮排掉 8 张,填充率 0.986~1.000)。
911
+ - 逐张**目检**:已检 24 张 → 15 通过 / 9 不合格,失败按「底卡 / 直角切边 / 角色名残留」分类记录(`assets/cards/README.md`)。
912
+
913
+ ## [0.5.2] — 2026-11-12(未发布)
914
+
915
+ ### Added
916
+
917
+ - **pighub-1099 俯视猪**:白底,阈值安全空档实测 [210,250](T=200 丢 33 px、T=190 丢 565 px 猪身);`removed: 42125` 与规格一致。
918
+ - **pighub-1162 墨镜猪**:源图自带 alpha(背景全透明 47.76%),白键是**无害空操作**(`removed: 0`);不能用 dark 键——墨镜主体 (51,51,51)/(77,77,77),取 ≥51 会连墨镜删、取 ≤40 仍删 3,170 px 猪身暗部,没有安全档位。
919
+
920
+ ### Changed
921
+
922
+ - **manifest 统一记录背景决策**:每只猪都带 `background: { key, threshold, all, removed }`(动图记 `key:'none'`)。此前老素材走白键分支不记 `removed`,无法对账「这张到底删了多少」。
923
+
924
+ ## [0.5.1] — 2026-11-12(未发布)
925
+
926
+ ### Added
927
+
928
+ - **pighub-974 斗鸡眼猪**:白底素材。复算核对:**512×490 / 164,693 B 与规格预测逐字节一致**,`removed: 30846` 也与实测相同。
929
+
930
+ ### Note(重要口径)
931
+
932
+ - 同一张图里的「白」有两种:**背景 57,958 px**(与四边连通)与**眼白 11,462 px**(两只 98×98 / 99×99,斗鸡眼的全部特征)。所以 `background.all` 必须是 `false`——`all:true` 会一次删光 11,462 px,猪就没眼睛了。判据不是「是不是白」,而是「这块白算不算猪」。
933
+ - 这条对**所有白底猪**都成立:白键只能删连通背景,`whiteAll` 只适用于「图里除了背景没有别的白」的情形(例如纯填充的贴纸)。
934
+
935
+ ## [0.5.0] — 2026-11-12(未发布)
936
+
937
+ ### Added
938
+
939
+ - `padFrame()` 单测(加边后内容不偏移、新边透明);断言总数 58 → **61**。
940
+ - README 补「去底三件套」对照表(白键 / 色键 / 框阵 各自适用面 + 实测差距)。
941
+
942
+ ## [0.4.9] — 2026-11-12(未发布)
943
+
944
+ ### Changed
945
+
946
+ - **pighub-55 愤怒猪定稿用背景色键**:实测 `removed: 82333`,剩余不透明 **180,902 px = 猪身像素数**,即**非猪残留 0**。对照 subagent 同时给出的「194 个 erase 框」方案:只覆盖 80,865 px(98.22%),残 1,468 px 黑块。同一张图,色键是精确解,框阵是权宜解——两版都留档以作对照。
947
+ - 规格里 `whiteAll` 关闭:猪身有 1,309 px 牙齿近白像素(最亮 min 通道 255),开 `whiteAll` 会把这排牙齿当白底削掉;实测「与边框连通的近白像素」在 236/250/255 三档都是 0,所以这张根本不需要白键。
948
+
949
+ ## [0.4.8] — 2026-11-12(未发布)
950
+
951
+ ### Fixed
952
+
953
+ - **被画布裁切的猪描边会断**:`addOutline` 只在帧内膨胀,而有些素材四边都贴着画布(愤怒猪:鼻顶左缘、尾顶右缘、腿顶下缘、尾尖顶上缘)。新增 `padFrame()` 在描边前加一圈透明边,描边得以沿裁切边画完整。实测愤怒猪四边描边不再是断口,成品 512×455。
954
+
955
+ ## [0.4.7] — 2026-11-12(未发布)
956
+
957
+ ### Changed
958
+
959
+ - **pighub-66 小眼猪改用背景色键**:`background: { key: 'dark', threshold: 31, all: true }` 取代 621 个 erase 框。`all: true` 是必须的——只删四边连通的会把卷尾 2 个封闭黑洞(465 px)留在环里;`threshold` 被实测夹死在 31(猪身 max 通道最小 32、眼睛/鼻孔最暗 41/45、背景 max ≤ 22;取 32 会多削 78 px 猪身边缘)。
960
+ - **交叉验证**:两种完全不同的方法(621 框 vs 1 个色键)产出的 PNG **逐字节相同**(sha256 `5b51c7de…`),`removed: 101750` 与逐像素预测一致,风格 0.981/0.951、尺寸 512×451 也一致。
961
+
962
+ ## [0.4.6] — 2026-11-12(未发布)
963
+
964
+ ### Added
965
+
966
+ - **pighub-66 小眼猪**:黑底素材(纯黑 rgb(0,0,0) 410,650 px = 62.66%),用 subagent 的 **621 个 erase 框**精确剔除(覆盖 100%,框内猪像素 0),并 `inpaint: false` 保住卷尾 2 个封闭黑洞(465 px)——填了会把卷尾糊成实心。复算核对:风格 **palette 0.981 / flatness 0.951**,与规格预测**完全一致**。
967
+
968
+ ### Note
969
+
970
+ - 试过用本轮的 `background` 色键一步去黑底(`removed: 101356`),但**色键分不清「卷尾外的黑洞」和「猪的深色眼睛」**:只从四边泛洪会留下尾部的封闭黑洞(留下黑点),`all: true` 又会把眼睛一起抠掉。所以这张仍按 621 框的精确方案落地——色键适合黑底**且**无深色细节内露的图(如愤怒猪)。
971
+
972
+ ## [0.4.5] — 2026-11-12(未发布)
973
+
974
+ ### Changed
975
+
976
+ - **补洞只补「被我们抠出来的洞」**:原先 `fillHoles()` 会填掉画面上所有封闭透明区,但卷尾环内、腿间那种透明是**源图应有的负空间**,填了就把环变成实心块(圆猪实测有 3 个洞共 1,734 px 会被毁掉)。现在只填外接框与某个 `erase` 框相交的洞,其余保持透明;新增 2 项回归断言覆盖两个方向。
977
+
978
+ ### Added
979
+
980
+ - **pighub-366 圆猪**:源图自带 alpha(猪身单一连通块 748,676 px,占画布 75.93%),无可删文字/水印/边框,`erase` 为空;成品 512×504,卷尾螺旋的镂空完好。
981
+
982
+ ## [0.4.4] — 2026-11-12(未发布)
983
+
984
+ ### Added
985
+
986
+ - **背景色键 `stripBackground()`**:素材不都是白底。实测「愤怒猪」是**纯黑底**(82,333 px,占 31.28%),而 `refineWhite`/`stripAllWhite` 的判据是 `min(r,g,b) ≥ 236`,对黑底**一个像素都不删**。新增 `work.background = { key: 'dark'|'light', threshold, all }`:从画布四边泛洪,删掉匹配判据的连通像素;`all: true` 则不看连通性。实测 `removed: 82333`,与逐像素预测**完全一致**。
987
+ - **pighub-55 愤怒猪**:黑底素材,成品 512×454,牙齿/嘴/眉毛完好。若改用 `whiteAll` 会把 1,309 px 牙齿近白像素当白底删掉(实测与边框连通的近白像素为 0,所以 `whiteAll=false` 才安全)。
988
+
989
+ ## [0.4.3] — 2026-11-12(未发布)
990
+
991
+ ### Added
992
+
993
+ - 全库分流实测(1,361 张):ok 714 / gif 49 / style-reject 527 / skipped 30 / failed 1,落盘 **133 MB** —— 「全库随包」的真实成本。
994
+ - `scripts/pick-candidates.mjs`:从分流结果按「像猪度 × 单块性 × 尺寸合理」排序候选,供逐素材 subagent 使用。
995
+ - **pighub-1018 矮脚猪**:第二个从全库扩量收进来的「猪的种类」。规格实测全图只有 1 个非白连通块(猪身 2,164,020 px),无文字/水印可删、`erase` 为空;成品 512×438。
996
+
997
+ ## [0.4.2] — 2026-11-12(未发布)
998
+
999
+ ### Changed
1000
+
1001
+ - **素材按「猪的种类」筛选**:逐图判定新增 ~category~(~species~ / ~behavior~)。只收 species(一种猪:角色/品种/风格本身),behavior(猪在做某件事的场景梗)一律不收并记入 ~manifest.excluded~。
1002
+ - 本轮排除 4 张行为类:挂科猪(求情挂科)、乱停猪(躺马路贴罚单)、你已笨哭(电脑前哭)、被捕捉的小猪(网兜捕捉)。
1003
+ - 包内从 7 张收敛到 **4 张**:怪猪(活)、萝卜猪(死)、你知道吗(活·矢量)、像素猪(活·GIF)。
1004
+
1005
+ ## [0.4.1] — 2026-11-12(未发布)
1006
+
1007
+ ### Added
1008
+
1009
+ - **受损补洞(按原色猜测填充)**:删字幕/配件时若在猪身上开了洞,会自动识别「被猪身包住的透明区」并用外圈 2px 的原色中位数填回,记 ~holes~/~filled~ 进 manifest。实测各图:1354 2 洞/383px、1357 2 洞/334px、1358 1 洞/281px、1360 3 洞/455px、1361 1 洞/418px(尾巴卷曲内白)、1355 0 洞。
1010
+
1011
+ ### Changed
1012
+
1013
+ - 逐图判定里的「介绍名字的字」全部去除:1354 的对白气泡(trim+erase)、1357 的「乱停猪」字幕(erase)、1358 的「萝卜猪」标题(trim)、1360 的「你已笨哭」字幕(erase)。成品里已无猪名文字。
1014
+
1015
+ ## [0.4.0] — 2026-11-12(未发布)
1016
+
1017
+ ### Changed
1018
+
1019
+ - **PigHub 为唯一可信源**(用户决定):~assets/libraries.json~ 只把 pighub.top 记为 trusted,其余 8 家标为「参考(不采集)」;smoke 收紧为「进包的每只猪来源必须是 ~pighub-online~」。
1020
+
1021
+ ### Fixed
1022
+
1023
+ - ~pig-1357~(乱停猪,实拍场景图):按 subagent 规格用 **163 个 erase 小框**覆盖 97.55% 街景(矩形无法沿椭圆曲线切割,精确覆盖需 610 框),并用 ~keep~ 框还原罚单白纸。复算核对:**541×386 / 189,539 B**,与规格预测**逐字节一致**;猪像素 150,478 一个不少、非猪残留 1,422 px;风格 0.845/0.907 match。
1024
+ - manifest 的 ~size~ 改记**成品**尺寸(压到 ≤512 之后),不再与裁剪后的原始像素混用。
1025
+ - 动图识别扩展到 **动画 WebP**(~RIFF/WEBP+ANIM~);此前只认 ~GIF8~,会把动画静默冻成首帧。
1026
+
1027
+ ## [0.3.6] — 2026-11-12(未发布)
1028
+
1029
+ ### Fixed
1030
+
1031
+ - **被风格闸门拒掉的图会被打进 npm 包**:构建顺序原来是「先写文件、再判风格」,被拒的图不清盘,而 `package.files` 收了 `assets/img` —— 实测 `pig-1300.png` 就残留在 `assets/img` 里。改为**判定通过才落盘**,被拒时 `rmSync` 清掉同名文件。
1032
+
1033
+ ## [0.3.5] — 2026-11-12(未发布)
1034
+
1035
+ ### Fixed
1036
+
1037
+ - ~pig-1358~(萝卜猪):从 `rejected` 回到包内。规格 trim 收在猪身(胡萝卜即猪身),夜空/星星/标题三块在 trim 内像素数为 0,**靠裁切一次性排除**,另用 6 个小 erase 框擦掉 8 个孤立近白杂点(否则会被描边成黑点)。复算核对:成图 264×376(= 规格 258×370 + 描边留边 6),风格 **palette 0.960 / flatness 0.929** 与规格预测**完全一致** → match。
1038
+
1039
+ ## [0.3.4] — 2026-11-12(未发布)
1040
+
1041
+ ### Fixed
1042
+
1043
+ - ~pig-1355~(怪猪):按 subagent 规格裁到猪身(392×373,与实测 bbox 完全一致),两个 erase 框删掉右上淡色飘带(框内猪像素 0/0,覆盖 trim 内全部 526px)。
1044
+ - **撤销该图的矢量化**:源图是纯填充无描线,220px 描摹会把眼睛/腮红/描边压成色块碎片(目视确认后改为 PNG)。判定里记录了原因。
1045
+ - 修掉一个真问题:紧框会裁掉描边环——crop 的 pad 改为「描边宽度 + 1」,实测 1354 环 6,056px、1355 环 4,737px 都在。
1046
+
1047
+ ## [0.3.3] — 2026-11-12(未发布)
1048
+
1049
+ ### Fixed
1050
+
1051
+ - `pig-1354`(挂科猪):按 subagent 的逐像素规格裁到猪身(trim 0.5332/0.6179/0.4414/0.3694),两个 erase 框删掉落进框内的气泡/文字(框内猪像素 0/0)。复算核对:无描边时不透明像素 **121,231**,与规格预测**完全一致**;成品 446×370。
1052
+ - `pig-1361`(你知道吗):按行剖面找到文字与猪的分界(中间 69 行零墨),trim 收在猪框 + 24px 留白;旧 trim 切掉尾尖 257px 且把水印圈进来(42px 残留),这就是此前「效果一般」的实测成因。成品 SVG 722×597。
1053
+
1054
+ ## [0.3.2] — 2026-11-12(未发布)
1055
+
1056
+ ### Added
1057
+
1058
+ - **可信来源登记表** `assets/libraries.json`:9 个仓库逐条记录 `license.spdx_id`(GitHub API 实测)、许可出处、图片实测数量、是否允许再分发与判定。结论:按「能再分发」严格筛,**没有任何图片库通过**(三个真图库无数据许可,rollpig-resources 明文禁止再托管,MIT 仓库只有文字资料);本包图片按 `inherited-risk` 记录。
1059
+ - **风格化校验闸门**:每张成品按像素颜色分布与平坦度打分(`palette ≥ 0.55 && flatness ≥ 0.35`),只看画风不看文件名/标题文字;不达标的图不进包、记入 `manifest.rejected`。当前排除 2 张(萝卜猪夜景海报、被捕捉的小猪)。
1060
+ - GIF 也过风格闸门(评第一帧,仍原样分发)。
1061
+
6
1062
  ## [0.3.1] — 2026-11-12
7
1063
 
8
1064
  ### Fixed