@linxin666/dsh-pet 0.3.2 → 0.3.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 (127) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +25 -7
  3. package/README.zh.md +25 -7
  4. package/assets/ouo-neko/pet.json +31 -0
  5. package/assets/ouo-neko/previews/failed.gif +0 -0
  6. package/assets/ouo-neko/previews/idle.gif +0 -0
  7. package/assets/ouo-neko/previews/jumping.gif +0 -0
  8. package/assets/ouo-neko/previews/review.gif +0 -0
  9. package/assets/ouo-neko/previews/running-left.gif +0 -0
  10. package/assets/ouo-neko/previews/running-right.gif +0 -0
  11. package/assets/ouo-neko/previews/running.gif +0 -0
  12. package/assets/ouo-neko/previews/waiting.gif +0 -0
  13. package/assets/ouo-neko/previews/waving.gif +0 -0
  14. package/assets/ouo-neko/spritesheet.webp +0 -0
  15. package/contracts/pet-manifest-v2.schema.json +102 -1
  16. package/lib/client.js +830 -26
  17. package/lib/client.js.map +1 -1
  18. package/lib/index.js +1226 -24
  19. package/lib/types/client/PetDockEntry.d.ts +3 -0
  20. package/lib/types/client/PetDockEntry.d.ts.map +1 -1
  21. package/lib/types/client/PetDockEntry.js +18 -2
  22. package/lib/types/client/PetSprite.d.ts +23 -0
  23. package/lib/types/client/PetSprite.d.ts.map +1 -1
  24. package/lib/types/client/PetSprite.js +34 -29
  25. package/lib/types/client/PluginSettingsCard.d.ts +2 -0
  26. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
  27. package/lib/types/client/PluginSettingsCard.js +2 -2
  28. package/lib/types/client/drag-stream.d.ts +19 -0
  29. package/lib/types/client/drag-stream.d.ts.map +1 -0
  30. package/lib/types/client/drag-stream.js +26 -0
  31. package/lib/types/client/gameplay-hud.d.ts +50 -0
  32. package/lib/types/client/gameplay-hud.d.ts.map +1 -0
  33. package/lib/types/client/gameplay-hud.js +274 -0
  34. package/lib/types/client/index.d.ts +1 -1
  35. package/lib/types/client/index.d.ts.map +1 -1
  36. package/lib/types/client/index.js +16 -0
  37. package/lib/types/client/locales.d.ts +34 -0
  38. package/lib/types/client/locales.d.ts.map +1 -1
  39. package/lib/types/client/locales.js +36 -0
  40. package/lib/types/client/pet-store.d.ts +7 -1
  41. package/lib/types/client/pet-store.d.ts.map +1 -1
  42. package/lib/types/client/pet-store.js +4 -0
  43. package/lib/types/client/renderers/Frames2dVisualMount.d.ts +29 -0
  44. package/lib/types/client/renderers/Frames2dVisualMount.d.ts.map +1 -0
  45. package/lib/types/client/renderers/Frames2dVisualMount.js +83 -0
  46. package/lib/types/client/renderers/PetRendererSwitch.d.ts +6 -0
  47. package/lib/types/client/renderers/PetRendererSwitch.d.ts.map +1 -1
  48. package/lib/types/client/renderers/PetRendererSwitch.js +14 -1
  49. package/lib/types/client/renderers/frames2d.d.ts +36 -0
  50. package/lib/types/client/renderers/frames2d.d.ts.map +1 -0
  51. package/lib/types/client/renderers/frames2d.js +196 -0
  52. package/lib/types/client/settings-form.d.ts +1 -1
  53. package/lib/types/client/settings-form.js +1 -1
  54. package/lib/types/client/telemetry.d.ts +27 -0
  55. package/lib/types/client/telemetry.d.ts.map +1 -0
  56. package/lib/types/client/telemetry.js +97 -0
  57. package/lib/types/defaults.d.ts +6 -0
  58. package/lib/types/defaults.d.ts.map +1 -0
  59. package/lib/types/defaults.js +5 -0
  60. package/lib/types/dsh-home.d.ts.map +1 -1
  61. package/lib/types/dsh-home.js +9 -3
  62. package/lib/types/gameplay.d.ts +182 -0
  63. package/lib/types/gameplay.d.ts.map +1 -0
  64. package/lib/types/gameplay.js +618 -0
  65. package/lib/types/http.d.ts +1 -1
  66. package/lib/types/http.js +1 -1
  67. package/lib/types/index.d.ts +1 -1
  68. package/lib/types/index.js +1 -1
  69. package/lib/types/ledger.d.ts +14 -0
  70. package/lib/types/ledger.d.ts.map +1 -1
  71. package/lib/types/ledger.js +30 -0
  72. package/lib/types/loopback.d.ts +1 -1
  73. package/lib/types/loopback.js +1 -1
  74. package/lib/types/manifest-v2.d.ts +38 -1
  75. package/lib/types/manifest-v2.d.ts.map +1 -1
  76. package/lib/types/manifest-v2.js +182 -2
  77. package/lib/types/mount-once.d.ts +1 -1
  78. package/lib/types/mount-once.js +2 -2
  79. package/lib/types/persist.d.ts +4 -4
  80. package/lib/types/persist.d.ts.map +1 -1
  81. package/lib/types/persist.js +41 -4
  82. package/lib/types/registry.d.ts +29 -0
  83. package/lib/types/registry.d.ts.map +1 -1
  84. package/lib/types/registry.js +170 -1
  85. package/lib/types/routes.d.ts.map +1 -1
  86. package/lib/types/routes.js +22 -0
  87. package/lib/types/service.d.ts +56 -0
  88. package/lib/types/service.d.ts.map +1 -1
  89. package/lib/types/service.js +181 -0
  90. package/package.json +6 -3
  91. package/src/client/PetDockEntry.test.tsx +6 -0
  92. package/src/client/PetDockEntry.tsx +32 -1
  93. package/src/client/PetSprite.test.tsx +36 -6
  94. package/src/client/PetSprite.tsx +42 -21
  95. package/src/client/PluginSettingsCard.tsx +4 -2
  96. package/src/client/drag-stream.ts +35 -0
  97. package/src/client/gameplay-hud.test.tsx +338 -0
  98. package/src/client/gameplay-hud.tsx +403 -0
  99. package/src/client/index.ts +23 -2
  100. package/src/client/locales.ts +36 -0
  101. package/src/client/pet-store.ts +10 -1
  102. package/src/client/pet.module.css +192 -29
  103. package/src/client/renderers/Frames2dVisualMount.tsx +111 -0
  104. package/src/client/renderers/PetRendererSwitch.tsx +28 -1
  105. package/src/client/renderers/frames2d.test.ts +137 -0
  106. package/src/client/renderers/frames2d.ts +216 -0
  107. package/src/client/settings-card.module.css +5 -0
  108. package/src/client/settings-form.ts +1 -1
  109. package/src/client/telemetry.ts +105 -0
  110. package/src/defaults.ts +7 -0
  111. package/src/dsh-home.ts +9 -3
  112. package/src/gameplay.test.ts +239 -0
  113. package/src/gameplay.ts +692 -0
  114. package/src/http.ts +1 -1
  115. package/src/index.ts +1 -1
  116. package/src/ledger.test.ts +16 -0
  117. package/src/ledger.ts +31 -0
  118. package/src/loopback.ts +1 -1
  119. package/src/manifest-v2.test.ts +130 -1
  120. package/src/manifest-v2.ts +181 -2
  121. package/src/mount-once.ts +2 -2
  122. package/src/persist.test.ts +3 -0
  123. package/src/persist.ts +43 -6
  124. package/src/registry.test.ts +168 -1
  125. package/src/registry.ts +199 -1
  126. package/src/routes.ts +19 -0
  127. package/src/service.ts +208 -0
package/README.i18n.yaml CHANGED
@@ -2,5 +2,5 @@
2
2
  # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
3
  # after editing either side, bring the other along and re-record with:
4
4
  # node scripts/verify-docs.mjs --write <dir>
5
- README.md: 02e682f7c14dee40461f177660a3c976fc4bb05d
6
- README.zh.md: d263d62d64cde1cd14a4e8656646166b944c4c0c
5
+ README.md: 515f3af940b587c685e194b5467ca91020af36a2
6
+ README.zh.md: f3dc4a805673d04289018dab31a9a4f0d16112fb
package/README.md CHANGED
@@ -65,9 +65,9 @@ A pet is a directory holding one `pet.json` manifest and one atlas image. Nothin
65
65
  A pet directory's `pet.json` declares its renderer explicitly in v2:
66
66
 
67
67
  - `petManifestVersion: 2` (absent = v1, compat-read as `sprite2d` with a migration hint);
68
- - `renderer`: `"sprite2d"` (the atlas contract above) or `"live2d"`;
68
+ - `renderer`: `"sprite2d"` (the atlas contract above), `"live2d"`, or `"frames2d"`;
69
69
  - `license` (required in v2): asset license identifier — community pets carry provenance;
70
- - a renderer block: `sprite2d` (spritesheetPath/cell/columns/atlasRows/frames/tracks) or `live2d` (model/motions/expressions/hitAreas/scale/translate).
70
+ - a renderer block: `sprite2d` (spritesheetPath/cell/columns/atlasRows/frames/tracks), `live2d` (model/motions/expressions/hitAreas/scale/translate), or `frames2d` (dir/defaultFrameMs/tracks/phases — directory-style frame sequences).
71
71
 
72
72
  Validation is fail-closed on structure (unknown fields or renderer kinds reject the entry with a diagnostic) and warn-and-drop on sequence/remark content. The machine-readable schema lives at `contracts/pet-manifest-v2.schema.json`; the authoritative validator is `src/manifest-v2.ts`. Migrate v1 manifests with `node scripts/dsh-pet-migrate-v2.mjs <dir> --write` (dry-run by default; keeps `pet.json.v1.bak`).
73
73
 
@@ -157,6 +157,14 @@ A Live2D manifest maps the seven activity phases onto the model's motion groups:
157
157
 
158
158
  Model licensing: the official Live2D sample models (Hiyori, Haru, and friends) are evaluation-only and must not be redistributed — ship only models you have rights to (original creations or permissively licensed ones).
159
159
 
160
+ ## Frames2d pets and gameplay (renderer: frames2d)
161
+
162
+ Frames2d pets ship directory-style frame sequences instead of an atlas: `thumb/<track>/<frame>.webp`, with per-frame durations from an optional `_<ms>` filename tail or the track's `frameMs` list (default 200 ms, bounds 16–5000). The manifest maps the activity phases onto tracks; a `drag` track follows the chrome's drag gesture, and non-looping tracks settle into their `fallback` (default the idle track), so intro/loop splits (sleep-intro → sleep) are plain manifest data.
163
+
164
+ A frames2d pet may declare a `gameplay` block — an opt-in mini-game layer generalized from the miku desktop pet: decaying stat bars (`stats` with per-minute decay, a working variant and an idle variant), the unified treat (小鱼干) currency — gameplay income and shop spending ride the same panel treat stock (capped at 20): `work` success, `passiveIncome` and lottery prizes grant treats, and shop items are priced and paid in treats, with no separate wallet page — a weighted `idleDirector` (rolls an act every `intervalMs`, `maxMiss` forces one after consecutive idle rolls), `touch` zones inside a `hitBox` (roll branches with effects, a track hold and phrase bubbles), a `work` loop (host-adjudicated ticks with success/fail result tracks), a `sleep` loop (lazy stat restore), `passiveIncome`, and a `shop` whose items carry effects or tiered lotteries. All rolls and bookkeeping are host-authoritative (`POST /api/pet/gameplay/*`); state persists per pet in `pet.json` and settles lazily on the treats-economy discipline. The browser half renders the menu card (stat bars, work/sleep toggles, shop grid) automatically for any pet that declares the block.
165
+
166
+ The **Miku pet** (contributed by stushansusu under MIT; Hatsune Miku character rights belong to Crypton Future Media under the Piapro Character License — see THIRD_PARTY_NOTICES.md) is the reference frames2d gameplay pet. It ships through the **Workshop** only (not the npm bundle): install it from the Workshop's pet list and it lands in `$DSH_HOME/pets/miku/`.
167
+
160
168
  ## Status decorations (decoration.json, pet-center M5, #567)
161
169
 
162
170
  A status bubble can carry a small ornament ahead of its text (built-in: the spouting whale), driven by the ActivityPhase stream. Decorations are independent of pets: own descriptor, own id, own directory — switching pets never switches decorations. Entry assets are PNG/WebP single-row sprite strips only (no SVG/CSS); the bubble always keeps its role=status/aria-live (or session-bubble button semantics), the ornament is aria-hidden; prefers-reduced-motion holds the segment first frame, and a broken asset only removes the ornament — the text stays.
@@ -189,14 +197,17 @@ A status bubble can carry a small ornament ahead of its text (built-in: the spou
189
197
 
190
198
  | Registry id | Selector label | Source |
191
199
  |---|---|---|
200
+ | `ouo-neko` | OUO Neko | Pink-sakura cat-eared companion contributed by `Pessimist0906` under MIT |
192
201
  | `whale-girl` | 鲸鱼娘(原版) | The repository's original whale-girl atlas |
193
202
  | `whale-girl-refined` | 鲸鱼娘(精致版) | An AI-assisted derivative with repaired and refined details, based on the whale-girl design direction |
194
203
 
195
- The refined variant references DreamSkin's “DeepSeek-Whale” theme. The historical source record identifies `powerdog996` as the original theme author and marks the theme as MIT: [DreamSkin](https://dreamskin.cc), [repository source record](https://github.com/zhu1090093659/dsh-web-ui/commit/87edd7ff4800dffd40bc93fb76e4ae450390facd). This attribution records the source and derivative relationship; it does not present the refined variant as an official work of the original author or redefine the original artwork's licensing scope.
204
+ The Miku pet is deliberately not bundled: it is a frames2d gameplay pet installed on demand from the Workshop (see the frames2d section above).
205
+
206
+ The refined variant references DreamSkin's “DeepSeek-Whale” theme. The historical source record identifies `powerdog996` as the original theme author and marks the theme as MIT: [DreamSkin](https://dreamskin.cc), [repository source record](https://github.com/zhu1090093659/dsh-web/commit/87edd7ff4800dffd40bc93fb76e4ae450390facd). This attribution records the source and derivative relationship; it does not present the refined variant as an official work of the original author or redefine the original artwork's licensing scope.
196
207
 
197
208
  ## Animation preview
198
209
 
199
- The sprites are an 8-column × 9-row atlas (192×208 cells) generated by the [hatch-pet](https://github.com/dsh2026) pipeline; below are previews of each state:
210
+ Sprite pets use 8-column atlases with 192×208 cells generated by the [hatch-pet](https://github.com/dsh2026) pipeline. Classic atlases carry 9 animation rows; v2 atlases add 2 rows for 16 look directions. Below are previews of the standard animation states:
200
211
 
201
212
  | idle | waiting | running | jumping |
202
213
  |---|---|---|---|
@@ -230,6 +241,7 @@ dsh-pet/
230
241
  | `-- pet.module.css
231
242
  |-- assets/whale/ # built-in original whale-girl (manifest + atlas + previews)
232
243
  |-- assets/whale-refined/ # built-in refined whale-girl registry variant
244
+ |-- assets/ouo-neko/ # built-in OUO Neko v2 pet (11-row atlas + previews)
233
245
  `-- cordis.patch.yml # bundle patch: inserts the pet plugin row
234
246
  ```
235
247
 
@@ -255,15 +267,15 @@ global React root (createRoot → document.body) <-- polling 2s -- pet-client (b
255
267
 
256
268
  ## Install
257
269
 
258
- Install the family aggregate package `@linxin666/dsh-web-ui-all` (all plugins and skins in one) or this plugin alone:
270
+ Install the family aggregate package `@linxin666/dsh-web-all` (all plugins and skins in one) or this plugin alone:
259
271
 
260
272
  ```sh
261
273
  ### From npm (recommended)
262
274
  dsh plugin --profile web add @linxin666/dsh-pet@latest
263
275
 
264
276
  ### From the repository (development)
265
- git clone https://github.com/zhu1090093659/dsh-web-ui.git
266
- cd dsh-web-ui
277
+ git clone https://github.com/zhu1090093659/dsh-web.git
278
+ cd dsh-web
267
279
  pnpm install && pnpm -r build
268
280
  dsh plugin --profile web add link:$(pwd)/packages/dsh-pet
269
281
 
@@ -286,6 +298,8 @@ The browser bundle rides the `window.__ModuleLoader__.load` contract; React/cord
286
298
 
287
299
  The two built-in whale-girl atlases use the same 9-state × 8-column contract: `assets/whale/` is the original and `assets/whale-refined/` is the refined variant. Each atlas is 1536×1872 (8 columns × 9 rows of 192×208 cells). Frame counts, rhythm, and scene rotation live in each directory's `pet.json`; pets without overrides follow the hatch-pet contract rhythm and canonical single-track scene mapping (row order: 0 idle / 1 running-right / 2 running-left / 3 waving / 4 jumping / 5 failed / 6 waiting / 7 running / 8 review).
288
300
 
301
+ OUO Neko uses the extended v2 contract: a 1536×2288 atlas with the same 9 animation rows plus 2 eight-frame look-direction rows. Its manifest declares `sprite2d.atlasRows: 11`, and the renderer treats the last 16 cells as the clockwise look loop.
302
+
289
303
  ## Security model
290
304
 
291
305
  - Every `/api/pet/*` and `/pet/<id>/*` route is loopback-only by default (the shared plugin-family fence: loopback socket + Host header + browser same-origin markers): unpaired LAN clients get `403 forbidden: loopback-only` before any pet state or atlas is served. When `dsh-remote-web-ui` is also loaded, a live paired-device cookie is an additional allow path (the same cookie `api/gate` already checks); unpaired and revoked devices stay 403. The pet does not depend on the remote plugin.
@@ -294,6 +308,10 @@ The two built-in whale-girl atlases use the same 9-state × 8-column contract: `
294
308
  - The plugin never downloads executables and never bundles the Live2D Cubism Core.
295
309
  - Manifests are fail-closed on structure: unknown fields or renderers reject the entry with a diagnostic shown in settings.
296
310
 
311
+ ## Telemetry
312
+
313
+ The browser half sends one anonymous install heartbeat per UTC day to dsh-market.com: a random localStorage id plus this package's name, nothing else. The server stores only a salted hash of that id, never IP addresses, and exposes aggregate counts only. See [docs/telemetry.md](../../docs/telemetry.md) for the full contract.
314
+
297
315
  ## License
298
316
 
299
317
  [BSD-3-Clause](LICENSE)
package/README.zh.md CHANGED
@@ -65,9 +65,9 @@
65
65
  宠物目录的 `pet.json` 在 v2 中显式声明渲染器:
66
66
 
67
67
  - `petManifestVersion: 2`(缺省 = v1,按 `sprite2d` 兼容读并给出迁移提示);
68
- - `renderer`:`"sprite2d"`(上文图集契约)或 `"live2d"`;
68
+ - `renderer`:`"sprite2d"`(上文图集契约)、`"live2d"` `"frames2d"`;
69
69
  - `license`(v2 必填):资产授权标识——社区宠物必须携带来源声明;
70
- - 渲染器专属块:`sprite2d`(spritesheetPath/cell/columns/atlasRows/frames/tracks)或 `live2d`(model/motions/expressions/hitAreas/scale/translate)。
70
+ - 渲染器专属块:`sprite2d`(spritesheetPath/cell/columns/atlasRows/frames/tracks)、`live2d`(model/motions/expressions/hitAreas/scale/translate)或 `frames2d`(dir/defaultFrameMs/tracks/phases——目录式帧序列)。
71
71
 
72
72
  校验纪律:结构 fail-closed(未知字段或未知渲染器直接拒载并给出诊断),sequences/remarks 内容维持 warn-and-drop。机器可读 schema 见 `contracts/pet-manifest-v2.schema.json`,权威校验器为 `src/manifest-v2.ts`。迁移 v1 清单:`node scripts/dsh-pet-migrate-v2.mjs <dir> --write`(默认 dry-run;保留 `pet.json.v1.bak`)。
73
73
 
@@ -157,6 +157,14 @@ Live2D 清单把七个活动相位映射到模型的动作组:
157
157
 
158
158
  模型授权:Live2D 官方示例模型(Hiyori、Haru 等)仅供评估、禁止再分发——只发布你有权的模型(原创作品或宽松授权的模型)。
159
159
 
160
+ ## Frames2d 宠物与玩法(renderer: frames2d)
161
+
162
+ frames2d 宠物不用图集,直接交付目录式帧序列:`thumb/<track>/<frame>.webp`,帧时长取文件名 `_<ms>` 尾缀或轨道的 `frameMs` 列表(默认 200ms,范围 16–5000)。清单把七个活动相位映射到轨道;`drag` 轨道跟随外壳的拖拽手势;非循环轨道播完进入 `fallback`(默认 idle 轨道),入睡/睡熟这类"引子 + 循环"拆分(sleep-intro → sleep)就是纯清单数据。
163
+
164
+ frames2d 宠物可声明 `gameplay` 块——从 miku 桌宠泛化而来的可选玩法层:属性条(`stats`,按分钟衰减,另有打工中与空闲变体)、统一的小鱼干货币(玩法收入与商店支出都走宠物面板那条小鱼干库存,上限 20 条:`work` 成功、`passiveIncome` 与彩票奖品发放小鱼干,商品也以小鱼干标价扣款,无独立钱包页)、加权 `idleDirector`(每 `intervalMs` 掷骰演出小动作,连续落空 `maxMiss` 次必演)、`hitBox` 内的 `touch` 触摸分区(分支掷骰:效果 + 轨道保持 + 台词气泡)、`work` 打工循环(宿主裁决 tick,成功/失败结果轨道)、`sleep` 睡觉循环(惰性恢复)、`passiveIncome` 被动收入,以及 `shop` 商店(商品可带效果或分档抽奖)。所有掷骰与记账由宿主权威裁决(`POST /api/pet/gameplay/*`),状态按宠物持久化在 `pet.json`,沿用小鱼干经济的惰性结算纪律。浏览器半侧为声明了该块的宠物自动渲染玩法菜单卡(属性条、打工/睡觉开关、商店网格)。
165
+
166
+ **Miku 宠物**(stushansusu 涂山苏苏以 MIT 贡献;初音未来角色权利归 Crypton Future Media,受 Piapro 角色许可约束——见 THIRD_PARTY_NOTICES.md)是 frames2d 玩法的参考实现。它只经**创意工坊**分发(不打进 npm 包):从工坊宠物列表安装后落在 `$DSH_HOME/pets/miku/`。
167
+
160
168
  ## 状态装饰(decoration.json,宠物中心 M5,#567)
161
169
 
162
170
  宠物状态气泡里的文字之前可以有一个小的状态装饰(内置:喷水鲸鱼),由 ActivityPhase 流驱动换帧。装饰与宠物相互独立:独立描述符、独立 id、独立目录,换宠物不换装饰。入口资产只收 PNG/WebP 单行精灵条带(不收 SVG/CSS);气泡自身的 role=status/aria-live(或会话气泡按钮语义)永远保留,装饰 aria-hidden;prefers-reduced-motion 时停在帧段首帧,资产加载失败只消失装饰、文字照常。
@@ -189,14 +197,17 @@ Live2D 清单把七个活动相位映射到模型的动作组:
189
197
 
190
198
  | 注册表 id | 选择器名称 | 来源 |
191
199
  |---|---|---|
200
+ | `ouo-neko` | OUO Neko | `Pessimist0906` 以 MIT 许可证贡献的粉色樱花猫耳伙伴 |
192
201
  | `whale-girl` | 鲸鱼娘(原版) | 仓库原有的鲸鱼娘图集 |
193
202
  | `whale-girl-refined` | 鲸鱼娘(精致版) | 以鲸鱼娘设计方向为基础,经 AI 辅助二次创作、修复和细节精修的衍生版本 |
194
203
 
195
- 精致版参考了 DreamSkin 的「DeepSeek-鲸鱼娘」主题。历史来源记录标注原主题作者为 `powerdog996`,并标注主题为 MIT:[DreamSkin](https://dreamskin.cc)、[仓库来源记录](https://github.com/zhu1090093659/dsh-web-ui/commit/87edd7ff4800dffd40bc93fb76e4ae450390facd)。此处用于记录素材来源与衍生关系;精致版不表述为原作者的官方作品,也不重新定义原始美术作品的授权范围。
204
+ Miku 宠物有意不随包内置:它是 frames2d 玩法宠物,经创意工坊按需安装(见上文 frames2d 一节)。
205
+
206
+ 精致版参考了 DreamSkin 的「DeepSeek-鲸鱼娘」主题。历史来源记录标注原主题作者为 `powerdog996`,并标注主题为 MIT:[DreamSkin](https://dreamskin.cc)、[仓库来源记录](https://github.com/zhu1090093659/dsh-web/commit/87edd7ff4800dffd40bc93fb76e4ae450390facd)。此处用于记录素材来源与衍生关系;精致版不表述为原作者的官方作品,也不重新定义原始美术作品的授权范围。
196
207
 
197
208
  ## 动画预览
198
209
 
199
- 精灵图是由 [hatch-pet](https://github.com/dsh2026) 流水线生成的 8 × 9 行图集(192×208 单元格);各状态预览:
210
+ 精灵宠物使用由 [hatch-pet](https://github.com/dsh2026) 流水线生成的 8 列图集,单元格为 192×208。经典图集包含 9 行动画;v2 图集额外增加 2 行,共提供 16 个观察方向。以下为标准动画状态预览:
200
211
 
201
212
  | idle | waiting | running | jumping |
202
213
  |---|---|---|---|
@@ -230,6 +241,7 @@ dsh-pet/
230
241
  | `-- pet.module.css
231
242
  |-- assets/whale/ # 内置原版鲸鱼娘(manifest + 图集 + 预览)
232
243
  |-- assets/whale-refined/ # 内置精致版鲸鱼娘注册表变体
244
+ |-- assets/ouo-neko/ # 内置 OUO Neko v2 宠物(11 行图集 + 预览)
233
245
  `-- cordis.patch.yml # bundle 补丁:插入宠物插件行
234
246
  ```
235
247
 
@@ -255,15 +267,15 @@ dsh-pet/
255
267
 
256
268
  ## 安装
257
269
 
258
- 安装聚合全家桶 `@linxin666/dsh-web-ui-all`(全部插件与皮肤一次到位),或单独安装本插件:
270
+ 安装聚合全家桶 `@linxin666/dsh-web-all`(全部插件与皮肤一次到位),或单独安装本插件:
259
271
 
260
272
  ```sh
261
273
  ### 从 npm 安装(推荐)
262
274
  dsh plugin --profile web add @linxin666/dsh-pet@latest
263
275
 
264
276
  ### 从仓库安装(开发调试)
265
- git clone https://github.com/zhu1090093659/dsh-web-ui.git
266
- cd dsh-web-ui
277
+ git clone https://github.com/zhu1090093659/dsh-web.git
278
+ cd dsh-web
267
279
  pnpm install && pnpm -r build
268
280
  dsh plugin --profile web add link:$(pwd)/packages/dsh-pet
269
281
 
@@ -286,6 +298,8 @@ pnpm typecheck # 仅类型检查
286
298
 
287
299
  两套内置鲸鱼娘图集使用同一份 9 态 × 8 列契约:`assets/whale/` 是原版,`assets/whale-refined/` 是精致版。每张图集均为 1536×1872(8 列 × 9 行,192×208 单元格)。每行帧数、节奏与场景轮换写在各目录的 `pet.json` 中;未覆盖的宠物沿用 hatch-pet 契约节奏和标准单轨场景映射(行序:0 idle / 1 running-right / 2 running-left / 3 waving / 4 jumping / 5 failed / 6 waiting / 7 running / 8 review)。
288
300
 
301
+ OUO Neko 使用扩展 v2 契约:图集为 1536×2288,在相同 9 行动画之后增加 2 行、共 16 帧观察方向。其清单声明 `sprite2d.atlasRows: 11`,渲染器把最后 16 个单元格作为顺时针观察方向循环。
302
+
289
303
  ## 安全模型
290
304
 
291
305
  - 全部 `/api/pet/*` 与 `/pet/<id>/*` 路由默认仅限 loopback(插件家族共享围栏:loopback 套接字 + Host 头 + 浏览器同源标记):未配对的局域网客户端在任何宠物状态或图集下发前即收到 `403 forbidden: loopback-only`。同时装了 `dsh-remote-web-ui` 时,有效的已配对设备 cookie 是额外放行路径(与 `api/gate` 检查同一枚 cookie);未配对与已撤销设备仍 403。宠物插件不硬依赖远程插件。
@@ -294,6 +308,10 @@ pnpm typecheck # 仅类型检查
294
308
  - 插件从不下载可执行文件,也从不内置 Live2D Cubism Core。
295
309
  - 清单结构 fail-closed:未知字段或未知渲染器直接拒载,并在设置中给出诊断。
296
310
 
311
+ ## 数据遥测
312
+
313
+ 浏览器半区每个 UTC 日向 dsh-market.com 发送一次匿名安装心跳:仅含一个 localStorage 随机 ID 与本包名,无其他数据。服务端只存储该 ID 的加盐哈希,不存 IP,且只暴露聚合计数。完整契约见 [docs/telemetry.md](../../docs/telemetry.md)。
314
+
297
315
  ## 许可证
298
316
 
299
317
  [BSD-3-Clause](LICENSE)
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "https://schemas.linxin666.org/dsh-pet/pet-manifest-v2.schema.json",
3
+ "petManifestVersion": 2,
4
+ "id": "ouo-neko",
5
+ "displayName": "OUO Neko",
6
+ "author": "Pessimist0906",
7
+ "version": "1.0.0",
8
+ "description": "A warm pink-sakura companion with cat ears and a lively chibi personality.",
9
+ "license": "MIT",
10
+ "renderer": "sprite2d",
11
+ "sprite2d": {
12
+ "spritesheetPath": "spritesheet.webp",
13
+ "cell": {
14
+ "width": 192,
15
+ "height": 208
16
+ },
17
+ "columns": 8,
18
+ "atlasRows": 11,
19
+ "frames": [
20
+ 6,
21
+ 8,
22
+ 8,
23
+ 4,
24
+ 5,
25
+ 8,
26
+ 6,
27
+ 6,
28
+ 6
29
+ ]
30
+ }
31
+ }
Binary file
@@ -55,7 +55,8 @@
55
55
  "renderer": {
56
56
  "enum": [
57
57
  "sprite2d",
58
- "live2d"
58
+ "live2d",
59
+ "frames2d"
59
60
  ],
60
61
  "default": "sprite2d",
61
62
  "description": "Renderer kind; omitted means sprite2d (v1 compatibility). Unknown values are rejected."
@@ -239,6 +240,88 @@
239
240
  }
240
241
  }
241
242
  },
243
+ "frames2d": {
244
+ "type": "object",
245
+ "additionalProperties": false,
246
+ "required": [
247
+ "tracks",
248
+ "phases"
249
+ ],
250
+ "description": "Frame-sequence renderer block; required when renderer=frames2d. Free-form named tracks laid out as <dir>/<track>/<frame>.(webp|png|gif|jpg|jpeg); phase-direct state selection (the live2d motions precedent). Frame durations resolve frameMs[i] > filename-encoded <base>_<index>_<ms> suffix > defaultFrameMs.",
251
+ "properties": {
252
+ "dir": {
253
+ "type": "string",
254
+ "minLength": 1,
255
+ "default": ".",
256
+ "description": "Frame root directory relative to the manifest directory (safe segments only)."
257
+ },
258
+ "defaultFrameMs": {
259
+ "type": "integer",
260
+ "minimum": 16,
261
+ "maximum": 5000,
262
+ "default": 200
263
+ },
264
+ "tracks": {
265
+ "type": "object",
266
+ "minProperties": 1,
267
+ "maxProperties": 64,
268
+ "description": "Named tracks (lowercase kebab ids, at most 32 chars).",
269
+ "additionalProperties": {
270
+ "type": "object",
271
+ "additionalProperties": false,
272
+ "properties": {
273
+ "frames": {
274
+ "type": "array",
275
+ "minItems": 1,
276
+ "maxItems": 64,
277
+ "items": {
278
+ "type": "string",
279
+ "minLength": 1,
280
+ "description": "Frame file name inside the track directory (no path segments)."
281
+ },
282
+ "description": "Explicit ordered frame list; omitted means list the track directory in filename order."
283
+ },
284
+ "frameMs": {
285
+ "type": "array",
286
+ "minItems": 1,
287
+ "items": {
288
+ "type": "integer",
289
+ "minimum": 16,
290
+ "maximum": 5000
291
+ },
292
+ "description": "Per-frame durations; requires an explicit frames list of the same length."
293
+ },
294
+ "loop": {
295
+ "type": "boolean",
296
+ "default": true,
297
+ "description": "false stops on the last frame, then enters fallback."
298
+ },
299
+ "fallback": {
300
+ "type": "string",
301
+ "description": "Track entered when a non-loop track ends; defaults to the idle-mapped track."
302
+ }
303
+ }
304
+ }
305
+ },
306
+ "phases": {
307
+ "type": "object",
308
+ "additionalProperties": false,
309
+ "required": [
310
+ "idle"
311
+ ],
312
+ "description": "ActivityPhase -> track name; idle is required, unmapped phases fall back to it.",
313
+ "properties": {
314
+ "idle": { "type": "string", "minLength": 1 },
315
+ "waiting": { "type": "string", "minLength": 1 },
316
+ "thinking": { "type": "string", "minLength": 1 },
317
+ "tool": { "type": "string", "minLength": 1 },
318
+ "review": { "type": "string", "minLength": 1 },
319
+ "done": { "type": "string", "minLength": 1 },
320
+ "failed": { "type": "string", "minLength": 1 }
321
+ }
322
+ }
323
+ }
324
+ },
242
325
  "sequences": {
243
326
  "type": "object",
244
327
  "description": "Renderer-agnostic ActivityPhase sequence table (v1 structure; every declared sequence has at least 5 items)."
@@ -246,6 +329,10 @@
246
329
  "remarks": {
247
330
  "type": "object",
248
331
  "description": "Per-slot witty-remark pools (v1 structure; a slot replaces the built-in pool for that slot only)."
332
+ },
333
+ "gameplay": {
334
+ "type": "object",
335
+ "description": "Optional gameplay layer (frames2d pets only): stat decay, currencies, touch zones, work/sleep loops, passive income and a shop with optional lotteries. State references name frames2d tracks; structure is fail-closed in the validator."
249
336
  }
250
337
  },
251
338
  "allOf": [
@@ -276,6 +363,20 @@
276
363
  "live2d"
277
364
  ]
278
365
  }
366
+ },
367
+ {
368
+ "if": {
369
+ "properties": {
370
+ "renderer": {
371
+ "const": "frames2d"
372
+ }
373
+ }
374
+ },
375
+ "then": {
376
+ "required": [
377
+ "frames2d"
378
+ ]
379
+ }
279
380
  }
280
381
  ]
281
382
  }