dsh-feiyu-wardrobe 0.0.0-stage → 0.2.0

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 ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0 — 2026-10-30
4
+
5
+ 「换装是视觉性的」:补齐出图能力,可直接发 QQ 群 / 评论区。
6
+
7
+ ### 新增
8
+
9
+ - `/fish png [尺寸]`:渲染当前穿搭的 PNG(默认 768,可选 256–1600)
10
+ - `dsh-feiyu-report --png <path>` / `--size <像素>`:CLI 直接出图
11
+ - PNG 合成:360×360 场景 + 底部水印条(repo 地址 + 鱼名 + 饲养天数)
12
+ - 依赖 `@resvg/resvg-js`(预编译二进制,本地渲染,无浏览器/无网络)
13
+ - 新增 `screenshots.json`(插件市场 / awesome 列表详情页展示卡图)
14
+ - README 增加「接 QQ / 聊天机器人」章节
15
+
16
+ ### 验证
17
+
18
+ - `npm run verify`:tsc --checkJs + 53 tests
19
+
20
+ ## 0.1.0 — 2026-10-30
21
+
22
+ 第一个公开版本:把 DSH 的 token 花销变成大肥鱼的衣柜。
23
+
24
+ ### 新增
25
+
26
+ - `/fish` 命令:状态、衣柜、购买、换装、脱下、改名、生成报告卡
27
+ - 鱼粮经济:每次模型调用按 DeepSeek 官方峰谷价折 CNY,`1 CNY = 100` 鱼粮币(可配置);出生礼 120 币
28
+ - 亲密度(0–100 六级)与心情(五档,表情随心情变化)、连续天数
29
+ - 21 件原创 SVG 单品:背景 4 / 身体 4 / 颈部 3 / 面部 3 / 手持 3 / 头部 4;稀有度普通 / 稀有 / 史诗
30
+ - 原创胖鲸形象(不打包任何画师二创素材)
31
+ - `dsh-feiyu-report` CLI:`--demo` / `--open` / `--out` / `--sheet`
32
+ - 1080×1440 饲养报告卡(自包含 HTML,无外部资源)
33
+ - 本地状态文件(原子写、schema 归一化、每日台账裁剪、会话列表上限)
34
+ - 49 个测试:定价、经济、状态迁移、渲染、命令、CLI
35
+
36
+ ### 说明
37
+
38
+ - 纯本地:无额外模型调用、无网络请求、不保存聊天原文
39
+ - 社区插件,非 DeepSeek 官方项目
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GIT121995
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,161 @@
1
- # Temporary Holding Version
1
+ # 🐋 大肥鱼衣橱 · dsh-feiyu-wardrobe
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [![npm](https://img.shields.io/npm/v/dsh-feiyu-wardrobe.svg)](https://www.npmjs.com/package/dsh-feiyu-wardrobe)
4
+ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
5
+ [![dsh](https://img.shields.io/badge/DSH-plugin-5BE7F0.svg)](https://github.com/deepseek-ai/deepseek-harness)
6
+
7
+ > 把 DSH 的 token 账单,变成一条鱼的衣柜。
8
+
9
+ 当前版本:`0.2.0`
10
+
11
+ DeepSeek Harness 插件:agent 每花掉一次 token,你的大肥鱼就**吃一顿饭**;一顿顿饭攒成**鱼粮币**,鱼粮币解锁 **21 件原创 SVG 穿搭**;`/fish report` 生成一张 **1080×1440 的饲养报告卡**,可以直接发小红书 / QQ 群。
12
+
13
+ - 🍚 **真实账本**:按 DeepSeek 官方峰谷价把每次模型调用折成人民币,再按 1 元 = 100 鱼粮币发币
14
+ - 🎨 **原创形象**:胖鲸 + 21 件手绘 SVG 单品(帽子 / 面部 / 颈部 / 身体 / 手持 / 背景),不打包任何画师二创素材
15
+ - 🔒 **纯本地**:零额外模型调用、零网络请求、不存聊天原文,只存聚合数字
16
+ - 📸 **可晒卡**:饲养天数、投喂金额、吃掉 token、亲密度、心情、近 7 天伙食、今日穿搭
17
+ - 🖼️ **可视化出图**:`/fish png` 或 `dsh-feiyu-report --png` 直接渲染 PNG(默认 768,带 repo 水印),无需浏览器,可直接发 QQ 群 / B站评论区 / 小红书
18
+
19
+ ![饲养报告示例](https://raw.githubusercontent.com/GIT121995/dsh-feiyu-wardrobe/main/docs/preview/card.png)
20
+
21
+ ![衣柜目录](https://raw.githubusercontent.com/GIT121995/dsh-feiyu-wardrobe/main/docs/preview/wardrobe.png)
22
+
23
+ ![出图示例](https://raw.githubusercontent.com/GIT121995/dsh-feiyu-wardrobe/main/docs/preview/fish-demo.png)
24
+
25
+ > 名字与形象都是原创,属于社区玩梗项目,**不是 DeepSeek 官方产品**;「大肥鱼」一词来自社区对 DeepSeek 蓝色鲸鱼标识的可爱误认。
26
+
27
+ ---
28
+
29
+ ## 安装
30
+
31
+ 需要 Node.js `>= 22.5` 和可用的 DeepSeek Harness(本版在 DSH `0.2.1-rc.2` 上实测)。
32
+
33
+ ```sh
34
+ # 装进你正在用的 profile(web / tui / headless 按需替换)
35
+ dsh plugin --profile web add dsh-feiyu-wardrobe
36
+
37
+ # 重启后生效
38
+ dsh --profile web
39
+ ```
40
+
41
+ 重启后随便让 agent 干点活,然后:
42
+
43
+ ```text
44
+ /fish
45
+ ```
46
+
47
+ ## 命令
48
+
49
+ | 命令 | 说明 |
50
+ | --- | --- |
51
+ | `/fish` | 看鱼今天的状态(投喂金额、token、亲密度、心情、穿搭) |
52
+ | `/fish list` | 逛衣柜:按部位列出全部单品、价格与拥有状态 |
53
+ | `/fish buy <名字\|id>` | 用鱼粮币买下并自动穿上 |
54
+ | `/fish wear <名字\|id>` | 换上已拥有的单品 |
55
+ | `/fish takeoff <部位>` | 脱掉某个部位(`bg` / `body` / `neck` / `face` / `hand` / `hat`) |
56
+ | `/fish rename <名字>` | 给鱼改名 |
57
+ | `/fish png [尺寸]` | 渲染当前穿搭的 PNG(默认 768;可直接发群) |
58
+ | `/fish report` | 生成饲养报告卡(HTML,1080×1440) |
59
+ | `/fish help` | 帮助 |
60
+
61
+ 不占单独模型调用,命令本身不烧 token。
62
+
63
+ ## 怎么玩
64
+
65
+ 1. **喂食**:每次模型调用按官方峰谷价折成 CNY,`1 CNY = 100 鱼粮币`(可配置)。新鱼出生送 120 币 + 小叶子一顶。
66
+ 2. **干饭 / 互动 / 连续天数** 一起涨 **亲密度**(0–100:陌生鱼 → 点头之交 → 饭搭子 → 老饭友 → 家人 → 过命交情)。
67
+ 3. **心情** 由「今天吃了几顿 + 聊了几句 + 距上一顿多久 + 连续天数」决定:饿晕了 / 有点饿 / 悠哉 / 满足 / 撑到翻肚。表情会跟着变。
68
+ 4. **衣柜** 21 件单品、三个稀有度:普通 / 稀有 / 史诗(王冠 600 币,慢慢攒)。
69
+ 5. **晒卡**:`/fish report` 或 `dsh-feiyu-report` 生成竖版卡片,浏览器打开直接截图。
70
+
71
+ ## 报告卡 CLI
72
+
73
+ ```sh
74
+ dsh-feiyu-report # 用本机 state 生成 HTML 卡片
75
+ dsh-feiyu-report --png fish.png # 直接出 PNG(QQ 群 / 评论区可用)
76
+ dsh-feiyu-report --png fish.png --size 1024
77
+ dsh-feiyu-report --demo --png demo.png
78
+ dsh-feiyu-report --open # 生成后用默认浏览器打开
79
+ dsh-feiyu-report --out card.html # 自定义 HTML 输出路径
80
+ dsh-feiyu-report --sheet # 渲染整个衣柜目录页
81
+ ```
82
+
83
+ 出图是纯本地 SVG → PNG(`@resvg/resvg-js`,预编译二进制),不调用浏览器、不联网。
84
+
85
+ ## 配置
86
+
87
+ 在 profile 的 `cordis.patch.yml` 里覆盖(都是可选项):
88
+
89
+ ```yaml
90
+ - id: feiyu-wardrobe
91
+ name: dsh-feiyu-wardrobe
92
+ config:
93
+ fishName: 大肥鱼 # 初始鱼名,之后也能 /fish rename
94
+ statePath: "" # 默认 <DSH_HOME>/feiyu-wardrobe/state.json
95
+ timezoneOffsetMinutes: 480 # 北京时间
96
+ coinPerCNY: 100 # 1 元 token 花费 = 多少鱼粮币
97
+ birthGiftCoins: 120 # 出生礼
98
+ dailyRetentionDays: 120 # 每日台账保留天数
99
+ holidays: [] # 法定节假日(峰谷价用),YYYY-MM-DD
100
+ ```
101
+
102
+ ## 隐私与版权
103
+
104
+ - **只存聚合数字**:金额、token 数、次数、日期、穿搭状态;不存任何聊天原文、模型输出、工具参数。
105
+ - **不联网**:插件和报告卡都不发请求;卡片是自包含 HTML,没有远程字体/图片/脚本。
106
+ - **原创美术**:默认胖鲸与全部 21 件单品均为本项目手绘 SVG;**不包含**画师「溟月」等社区二创素材,也不冒充官方形象。
107
+ - **非官方**:本项目是社区插件,不属于 DeepSeek 官方项目;「大肥鱼」相关梗的归属属于社区。
108
+ - 后续开放「皮肤包」格式时,同样只支持**本地加载**用户自己的素材,不代分发未授权作品。
109
+
110
+ ## 接 QQ / 聊天机器人(出图能力)
111
+
112
+ 「换装」是视觉性的,所以核心能力是**出图**而不是出文字:
113
+
114
+ - 任何能执行命令的 QQ 机器人(LangBot、DSH + QQ 适配器等)都可以在 `wear` 之后调一次
115
+ `dsh-feiyu-report --png /tmp/fish.png`,把 PNG 直接发到群里;
116
+ - DSH 内也可以用 `/fish png` 生成文件,再由机器人发送;
117
+ - 图片带仓库水印,别人转发一次就是一次曝光。
118
+
119
+ > 注意:本项目只负责「渲染并给出 PNG 文件」,QQ 平台的接入、账号风控由你选用的机器人框架负责。
120
+
121
+ ## 兼容性与测试
122
+
123
+ - DSH `>= 0.1.0`(本版在 `0.2.1-rc.2` 实测)
124
+ - Node.js `>= 22.5`,零运行时依赖
125
+ - `npm run verify` = `tsc --checkJs` 类型检查 + 53 个单元/集成测试(定价、经济、状态迁移、渲染、PNG、命令、CLI)
126
+
127
+ ```sh
128
+ npm run verify
129
+ ```
130
+
131
+ ## 路线图
132
+
133
+ - **v0.3**:DSH Web 面板(页内衣橱 UI)、皮肤包格式(`.dshskin`,本地加载)、心情联动穿搭
134
+ - **v0.3**:多鱼塘(多会话鱼)、每日小任务、社区衣服交换码
135
+ - 更远:把 `dsh-memory-gate` 的记忆做成「鱼记得你说过什么」,但依然只读聚合摘要
136
+
137
+ ## 开发
138
+
139
+ ```sh
140
+ git clone https://github.com/GIT121995/dsh-feiyu-wardrobe && cd dsh-feiyu-wardrobe
141
+ npm install
142
+ npm test # node --test
143
+ npm run typecheck # tsc --checkJs
144
+ node bin/feiyu-report.mjs --demo --out card.html # 预览报告卡
145
+ ```
146
+
147
+ 结构:
148
+
149
+ ```text
150
+ lib/catalog.js 21 件原创 SVG 单品 + 稀有度/价格
151
+ lib/render.js 360×360 场景与 1080×1440 报告卡
152
+ lib/economy.js 鱼粮币 / 亲密度 / 心情 / 连续天数
153
+ lib/pricing.js DeepSeek 官方峰谷价计费
154
+ lib/runtime.js 会话事件 → 经济系统,买/穿/改名
155
+ lib/commands.js /fish 命令
156
+ bin/ dsh-feiyu-report CLI
157
+ ```
158
+
159
+ ## License
160
+
161
+ MIT。见 [LICENSE](LICENSE)。
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * dsh-feiyu-report — render the 1080×1440 share card for the local fish.
4
+ *
5
+ * Usage:
6
+ * dsh-feiyu-report # card from the real state file
7
+ * dsh-feiyu-report --demo # preview with a demo fish
8
+ * dsh-feiyu-report --out card.html # custom output path
9
+ * dsh-feiyu-report --open # open the card in the default browser
10
+ * dsh-feiyu-report --sheet # render the full wardrobe catalog sheet
11
+ */
12
+
13
+ import { existsSync, readFileSync } from 'node:fs';
14
+ import { spawn } from 'node:child_process';
15
+ import { dirname, join, resolve } from 'node:path';
16
+ import { renderFishPng } from '../lib/image.js';
17
+ import { renderWardrobeSheetHtml } from '../lib/render.js';
18
+ import { createDemoState } from '../lib/demo.js';
19
+ import { validateConfig } from '../lib/config.js';
20
+ import { loadState } from '../lib/state.js';
21
+ import { defaultReportPath, writeReportCard } from '../lib/report.js';
22
+ import { atomicWriteBuffer, atomicWriteFile } from '../lib/util.js';
23
+
24
+ const PACKAGE = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
25
+ const VERSION = PACKAGE.version ?? '0.0.0';
26
+
27
+ const HELP = `dsh-feiyu-report — 大肥鱼衣橱饲养报告卡
28
+
29
+ 用法:
30
+ dsh-feiyu-report 从本机 state 生成报告卡
31
+ dsh-feiyu-report --demo 用演示鱼生成一张预览卡
32
+ dsh-feiyu-report --sheet 渲染整个衣柜目录页
33
+ dsh-feiyu-report --png <path> 渲染当前穿搭的 PNG(可直接发 QQ 群)
34
+ dsh-feiyu-report --size <像素> PNG 边长(256–1600,默认 768)
35
+ dsh-feiyu-report --out <path> 指定 HTML 输出路径
36
+ dsh-feiyu-report --state <path> 指定 state.json
37
+ dsh-feiyu-report --open 生成后用默认浏览器打开
38
+ dsh-feiyu-report --version 版本号
39
+ dsh-feiyu-report --help 本说明
40
+ `;
41
+
42
+ /**
43
+ * @param {string[]} argv
44
+ */
45
+ function parseArgs(argv) {
46
+ const options = {
47
+ demo: false,
48
+ sheet: false,
49
+ open: false,
50
+ help: false,
51
+ version: false,
52
+ out: null,
53
+ png: null,
54
+ size: null,
55
+ state: null,
56
+ };
57
+ for (let index = 0; index < argv.length; index += 1) {
58
+ const arg = argv[index];
59
+ switch (arg) {
60
+ case '--demo':
61
+ options.demo = true;
62
+ break;
63
+ case '--sheet':
64
+ options.sheet = true;
65
+ break;
66
+ case '--open':
67
+ options.open = true;
68
+ break;
69
+ case '--help':
70
+ case '-h':
71
+ options.help = true;
72
+ break;
73
+ case '--version':
74
+ case '-v':
75
+ options.version = true;
76
+ break;
77
+ case '--out': {
78
+ options.out = argv[index + 1] ?? null;
79
+ index += 1;
80
+ break;
81
+ }
82
+ case '--png': {
83
+ options.png = argv[index + 1] ?? null;
84
+ index += 1;
85
+ break;
86
+ }
87
+ case '--size': {
88
+ options.size = argv[index + 1] ?? null;
89
+ index += 1;
90
+ break;
91
+ }
92
+ case '--state': {
93
+ options.state = argv[index + 1] ?? null;
94
+ index += 1;
95
+ break;
96
+ }
97
+ default:
98
+ throw new Error(`未知参数:${arg}(--help 查看用法)`);
99
+ }
100
+ }
101
+ return options;
102
+ }
103
+
104
+ /**
105
+ * @param {string} path
106
+ */
107
+ function openInBrowser(path) {
108
+ const command =
109
+ process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'cmd' : 'xdg-open';
110
+ const args = process.platform === 'win32' ? ['/c', 'start', '', path] : [path];
111
+ try {
112
+ const child = spawn(command, args, { detached: true, stdio: 'ignore' });
113
+ child.on('error', () => undefined);
114
+ child.unref();
115
+ } catch {
116
+ // opening is a convenience; the printed path is the contract
117
+ }
118
+ }
119
+
120
+ function main() {
121
+ const options = parseArgs(process.argv.slice(2));
122
+ if (options.help) {
123
+ process.stdout.write(HELP);
124
+ return;
125
+ }
126
+ if (options.version) {
127
+ process.stdout.write(`${VERSION}\n`);
128
+ return;
129
+ }
130
+ const config = validateConfig(options.state ? { statePath: options.state } : {});
131
+ if (options.sheet) {
132
+ const outPath = resolve(options.out ?? join(dirname(config.statePath), 'wardrobe.html'));
133
+ atomicWriteFile(outPath, renderWardrobeSheetHtml());
134
+ process.stdout.write(`${outPath}\n`);
135
+ if (options.open) openInBrowser(outPath);
136
+ return;
137
+ }
138
+ let state;
139
+ if (options.demo) {
140
+ state = createDemoState(config);
141
+ } else {
142
+ if (!existsSync(config.statePath)) {
143
+ process.stderr.write(
144
+ `还没有鱼:找不到 ${config.statePath}\n先在 DSH 里和它说句话(或运行 dsh-feiyu-report --demo 看预览)。\n`,
145
+ );
146
+ process.exitCode = 1;
147
+ return;
148
+ }
149
+ const loaded = loadState(config.statePath, config);
150
+ state = loaded.state;
151
+ }
152
+ if (options.png) {
153
+ const sizeValue = options.size == null ? undefined : Number(options.size);
154
+ if (sizeValue !== undefined && (!Number.isFinite(sizeValue) || sizeValue < 256 || sizeValue > 1600)) {
155
+ throw new Error('--size 需要 256–1600 之间的整数');
156
+ }
157
+ const png = renderFishPng(state, config, {
158
+ ...(sizeValue === undefined ? {} : { size: sizeValue }),
159
+ });
160
+ const pngPath = resolve(options.png);
161
+ atomicWriteBuffer(pngPath, png);
162
+ process.stdout.write(`${pngPath}\n`);
163
+ if (options.open) openInBrowser(pngPath);
164
+ return;
165
+ }
166
+ const outPath = writeReportCard(state, config, {
167
+ ...(options.out ? { outPath: resolve(options.out) } : {}),
168
+ });
169
+ process.stdout.write(`${outPath}\n`);
170
+ if (options.open) openInBrowser(outPath);
171
+ }
172
+
173
+ try {
174
+ main();
175
+ } catch (cause) {
176
+ process.stderr.write(`${cause instanceof Error ? cause.message : String(cause)}\n`);
177
+ process.exitCode = 1;
178
+ }
@@ -0,0 +1,21 @@
1
+ # Bundle patch for dsh-feiyu-wardrobe.
2
+ # Values below are the defaults; omit any key to keep the built-in default.
3
+ - insert:
4
+ - id: feiyu-wardrobe
5
+ name: dsh-feiyu-wardrobe
6
+ inject:
7
+ - commands
8
+ config:
9
+ # Display name of your fish. /fish rename also works at runtime.
10
+ fishName: 大肥鱼
11
+ # Empty string means <DSH home>/feiyu-wardrobe/state.json
12
+ statePath: ""
13
+ timezoneOffsetMinutes: 480
14
+ # 1 CNY of token spend = 100 fish-food coins by default.
15
+ coinPerCNY: 100
16
+ # Coins granted when the fish is born (so the first outfit is reachable).
17
+ birthGiftCoins: 120
18
+ # Keep the daily ledger for this many days (used by streak/report).
19
+ dailyRetentionDays: 120
20
+ # Statutory holidays (Asia/Shanghai dates, YYYY-MM-DD): off-peak pricing.
21
+ holidays: []
@@ -0,0 +1,188 @@
1
+ <!doctype html>
2
+ <html lang="zh-CN"><head><meta charset="utf-8">
3
+ <title>干饭鲸 · 大肥鱼衣橱 饲养报告</title>
4
+ <style>
5
+ * { box-sizing: border-box; margin: 0; padding: 0; }
6
+ html, body { width: 1080px; height: 1440px; overflow: hidden; }
7
+ body {
8
+ background: #0D1524;
9
+ font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Noto Sans CJK SC", "Microsoft YaHei", sans-serif;
10
+ color: #F5F7FF;
11
+ }
12
+ .card {
13
+ position: relative; width: 1080px; height: 1440px; padding: 44px 60px;
14
+ display: flex; flex-direction: column; gap: 18px;
15
+ background:
16
+ radial-gradient(900px 520px at 82% -8%, rgba(91,231,240,0.16), transparent 62%),
17
+ radial-gradient(760px 480px at 6% 16%, rgba(142,207,245,0.14), transparent 60%),
18
+ linear-gradient(180deg, #101A2C 0%, #0C1420 58%, #0A111B 100%);
19
+ }
20
+ .card::after {
21
+ content: ""; position: absolute; inset: 22px; border: 1px solid rgba(245,247,255,0.10);
22
+ border-radius: 30px; pointer-events: none;
23
+ }
24
+ .header { display: flex; align-items: baseline; justify-content: space-between; }
25
+ .brand { font-size: 26px; font-weight: 800; letter-spacing: 1px; color: #F5F7FF; }
26
+ .brand span { color: #5BE7F0; }
27
+ .date { font-size: 18px; color: #93A4BC; letter-spacing: 2px; }
28
+ .scene {
29
+ height: 496px; border-radius: 30px; padding: 16px;
30
+ background: linear-gradient(180deg, #F7FBFF, #E8F4FF);
31
+ box-shadow: 0 24px 60px rgba(0,0,0,0.35), inset 0 0 0 1px rgba(255,255,255,0.6);
32
+ display: flex; align-items: center; justify-content: center;
33
+ }
34
+ .scene svg { display: block; border-radius: 22px; overflow: hidden; }
35
+ .identity { display: flex; align-items: flex-end; justify-content: space-between; gap: 20px; }
36
+ .name { font-size: 52px; font-weight: 800; letter-spacing: 1px; line-height: 1.1; }
37
+ .sub { margin-top: 8px; font-size: 20px; color: #9FB0C8; }
38
+ .mood {
39
+ display: flex; align-items: center; gap: 12px; padding: 12px 22px; border-radius: 999px;
40
+ background: rgba(91,231,240,0.10); border: 1px solid rgba(91,231,240,0.35);
41
+ font-size: 22px; color: #CFFAFF; white-space: nowrap;
42
+ }
43
+ .mood b { font-size: 26px; }
44
+ .quote { font-size: 19px; color: #8FA3BE; margin-top: -4px; }
45
+ .stats {
46
+ display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
47
+ }
48
+ .stat {
49
+ background: rgba(255,255,255,0.045); border: 1px solid rgba(245,247,255,0.08);
50
+ border-radius: 20px; padding: 16px 20px; min-height: 96px;
51
+ }
52
+ .statValue { font-size: 34px; font-weight: 800; color: #F5C542; letter-spacing: 0.5px; }
53
+ .statLabel { margin-top: 4px; font-size: 17px; color: #9FB0C8; }
54
+ .statHint { margin-top: 2px; font-size: 14px; color: #6E819C; }
55
+ .week { display: flex; align-items: center; gap: 22px; padding: 6px 2px 0; }
56
+ .weekLabel { font-size: 17px; color: #9FB0C8; white-space: nowrap; }
57
+ .weekChart { flex: 1; }
58
+ .howto {
59
+ margin-top: 4px; padding: 16px 22px; border-radius: 20px;
60
+ background: rgba(91,231,240,0.06); border: 1px dashed rgba(91,231,240,0.35);
61
+ }
62
+ .howtoTitle { font-size: 15px; color: #8FA3BE; letter-spacing: 1px; }
63
+ .howtoCmd { margin-top: 6px; font-size: 22px; font-weight: 700; color: #F5C542; letter-spacing: 0.4px; }
64
+ .howtoHint { margin-top: 4px; font-size: 15px; color: #9FB0C8; }
65
+ .wardrobe { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
66
+ .wardrobeLabel { font-size: 17px; color: #9FB0C8; margin-right: 4px; }
67
+ .chip {
68
+ display: inline-flex; align-items: baseline; gap: 8px;
69
+ padding: 8px 16px; border-radius: 999px; font-size: 18px; font-weight: 700;
70
+ background: rgba(255,255,255,0.05); border: 1px solid rgba(245,247,255,0.16);
71
+ }
72
+ .chip em { font-style: normal; font-size: 13px; font-weight: 500; color: #7C8DA6; }
73
+ .footer {
74
+ margin-top: auto; display: flex; align-items: center; justify-content: space-between;
75
+ gap: 20px; font-size: 14px; color: #6E819C; letter-spacing: 0.3px; white-space: nowrap;
76
+ }
77
+ .footer b { color: #AFC1DA; font-weight: 700; }
78
+ </style></head>
79
+ <body><div class="card">
80
+ <div class="header">
81
+ <div class="brand">🐋 大肥鱼衣橱 <span>·</span> 饲养报告</div>
82
+ <div class="date">2026.10.30</div>
83
+ </div>
84
+ <div class="scene"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 360" width="100%" height="100%" role="img" aria-label="大肥鱼">
85
+ <g>
86
+ <defs><linearGradient id="feiyu-grad-tank" x1="0" y1="0" x2="0" y2="1">
87
+ <stop offset="0" stop-color="#EAF8FF"/><stop offset="1" stop-color="#C9EBFF"/>
88
+ </linearGradient></defs>
89
+ <rect width="360" height="360" fill="url(#feiyu-grad-tank)"/>
90
+ <path d="M20 316 C60 296 120 312 180 300 C240 288 300 306 340 296 L340 360 L20 360 Z" fill="#F2E3C8"/>
91
+ <path d="M56 316 C48 278 64 250 58 218 C72 252 74 286 70 316 Z" fill="#A8D8B9"/>
92
+ <path d="M86 316 C80 286 92 264 86 240 C102 268 100 294 96 316 Z" fill="#8FCCA6"/>
93
+ <g fill="#FFFFFF" opacity="0.75">
94
+ <circle cx="300" cy="110" r="9"/><circle cx="318" cy="88" r="5"/><circle cx="286" cy="80" r="4"/>
95
+ <circle cx="70" cy="150" r="6"/><circle cx="54" cy="182" r="4"/>
96
+ </g>
97
+ </g>
98
+ <g>
99
+ <g stroke="#8ECFF5" stroke-width="5" stroke-linecap="round" fill="none">
100
+ <path d="M170 108 C166 92 156 84 148 78"/>
101
+ <path d="M170 108 C174 92 184 84 192 78"/>
102
+ </g>
103
+ <path d="M268 196 C300 168 316 150 322 142 C336 168 334 214 322 240 C310 226 292 206 268 196 Z" fill="#8ECFF5"/>
104
+ <path d="M62 196 C62 140 112 108 172 108 C236 108 282 142 282 196 C282 252 236 286 172 286 C108 286 62 250 62 196 Z" fill="#8ECFF5"/>
105
+ <path d="M95 238 C120 276 224 276 249 238 C240 272 212 286 172 286 C132 286 104 272 95 238 Z" fill="#EAF8FF"/>
106
+ <path d="M112 204 C92 208 82 224 86 238 C102 242 118 232 124 220 Z" fill="#6DB8E6"/>
107
+ </g><g>
108
+ <path d="M128 190 C134 178 146 178 152 190" stroke="#1B2A3A" stroke-width="5" fill="none" stroke-linecap="round"/>
109
+ <path d="M192 190 C198 178 210 178 216 190" stroke="#1B2A3A" stroke-width="5" fill="none" stroke-linecap="round"/>
110
+ <ellipse cx="116" cy="214" rx="15" ry="9" fill="#FFB3C7" opacity="0.95"/>
111
+ <ellipse cx="228" cy="214" rx="15" ry="9" fill="#FFB3C7" opacity="0.95"/>
112
+ <path d="M158 212 C166 230 180 230 186 212" stroke="#1B2A3A" stroke-width="4" fill="#FF8FA3" stroke-linecap="round"/>
113
+ <path d="M292 118 l5 10 10 5 -10 5 -5 10 -5 -10 -10 -5 10 -5 z" fill="#FFD27A"/>
114
+ </g>
115
+ <g>
116
+ <path d="M150 236 L138 200 M192 236 L204 200" stroke="#C9D6E3" stroke-width="5" fill="none" stroke-linecap="round"/>
117
+ <path d="M130 236 C140 250 202 250 212 236 L222 300 C190 312 150 312 118 300 Z" fill="#FFFFFF" stroke="#C9D6E3" stroke-width="3"/>
118
+ <path d="M150 260 L150 296" stroke="#E3E9EF" stroke-width="2"/>
119
+ <path d="M192 260 L192 296" stroke="#E3E9EF" stroke-width="2"/>
120
+ <path d="M158 272 C162 266 172 266 176 272 C180 266 190 266 194 272 C190 282 176 288 176 288 C176 288 162 282 158 272 Z" fill="#FFB3C7" opacity="0.85"/>
121
+ </g>
122
+ <g>
123
+ <path d="M120 232 C150 246 194 246 224 232 L228 250 C196 262 148 262 116 250 Z" fill="#FF6B6B" stroke="#E05555" stroke-width="2"/>
124
+ <path d="M228 244 L262 262 L252 278 L218 256 Z" fill="#FF8A8A" stroke="#E05555" stroke-width="2"/>
125
+ <path d="M254 270 L248 282 M260 266 L256 278 M246 276 L240 286" stroke="#E05555" stroke-width="2" stroke-linecap="round"/>
126
+ </g>
127
+ <g>
128
+ <g fill="#FFFFFF" opacity="0.28" stroke="#33415C" stroke-width="4">
129
+ <rect x="118" y="174" width="42" height="28" rx="9"/>
130
+ <rect x="186" y="174" width="42" height="28" rx="9"/>
131
+ </g>
132
+ <path d="M160 188 L186 188" stroke="#33415C" stroke-width="4"/>
133
+ <path d="M118 184 L104 176 M228 184 L242 176" stroke="#33415C" stroke-width="4" stroke-linecap="round"/>
134
+ </g>
135
+ <g>
136
+ <path d="M120 300 C120 286 160 280 180 280 C200 280 240 286 240 300 Z" fill="#FFFFFF" stroke="#C9D6E3" stroke-width="3"/>
137
+ <ellipse cx="180" cy="282" rx="58" ry="12" fill="#FFF6E5" stroke="#C9D6E3" stroke-width="3"/>
138
+ <ellipse cx="180" cy="280" rx="44" ry="8" fill="#FFFFFF"/>
139
+ <g fill="#FFFFFF" stroke="#E3E9EF" stroke-width="1.5">
140
+ <ellipse cx="166" cy="276" rx="7" ry="5"/><ellipse cx="180" cy="272" rx="7" ry="5"/>
141
+ <ellipse cx="194" cy="276" rx="7" ry="5"/><ellipse cx="174" cy="282" rx="7" ry="5"/>
142
+ <ellipse cx="188" cy="282" rx="7" ry="5"/>
143
+ </g>
144
+ <g stroke="#C68A4A" stroke-width="5" stroke-linecap="round"><path d="M236 258 L262 276"/><path d="M244 252 L270 272"/></g>
145
+ </g>
146
+ <g>
147
+ <ellipse cx="172" cy="138" rx="80" ry="17" fill="#F5C542" stroke="#D9A62E" stroke-width="3"/>
148
+ <path d="M118 136 C118 104 226 104 226 136 Z" fill="#F5C542" stroke="#D9A62E" stroke-width="3"/>
149
+ <path d="M120 128 C140 120 204 120 224 128" stroke="#FF6B6B" stroke-width="8" fill="none"/>
150
+ <path d="M118 140 C140 148 204 148 226 140" stroke="#D9A62E" stroke-width="2" fill="none" opacity="0.6"/>
151
+ </g>
152
+ </svg></div>
153
+ <div>
154
+ <div class="identity">
155
+ <div>
156
+ <div class="name">干饭鲸</div>
157
+ <div class="sub">第 13 天 · 🍱 老饭友 · ★★★★★</div>
158
+ </div>
159
+ <div class="mood">😊 <b>满足</b></div>
160
+ </div>
161
+ <div class="quote">吃饱喝足,心情不错。</div>
162
+ </div>
163
+ <div class="stats">
164
+ <div class="stat"><div class="statValue">¥2.44</div><div class="statLabel">投喂金额</div><div class="statHint">今日 ¥0.068</div></div>
165
+ <div class="stat"><div class="statValue">2.91M</div><div class="statLabel">吃掉 Token</div><div class="statHint">干饭 30 顿</div></div>
166
+ <div class="stat"><div class="statValue">12</div><div class="statLabel">互动次数</div><div class="statHint">连续 5 天</div></div>
167
+ <div class="stat"><div class="statValue">56/100</div><div class="statLabel">亲密度</div><div class="statHint">下一档:家人</div></div>
168
+ <div class="stat"><div class="statValue">187.5</div><div class="statLabel">鱼粮币</div><div class="statHint">token 换的</div></div>
169
+ <div class="stat"><div class="statValue">2 顿</div><div class="statLabel">今日干饭</div><div class="statHint">¥0.068</div></div>
170
+ </div>
171
+ <div class="week">
172
+ <div class="weekLabel">近 7 天伙食</div>
173
+ <div class="weekChart"><svg viewBox="0 0 502 80" width="100%" height="80" preserveAspectRatio="xMidYEnd meet" role="img" aria-label="近七天伙食"><rect x="0" y="64" width="46" height="16" rx="8" fill="#F5C542" opacity="0.50"/><rect x="76" y="42" width="46" height="38" rx="8" fill="#F5C542" opacity="0.71"/><rect x="152" y="12" width="46" height="68" rx="8" fill="#F5C542" opacity="1.00"/><rect x="228" y="58" width="46" height="22" rx="8" fill="#F5C542" opacity="0.56"/><rect x="304" y="48" width="46" height="32" rx="8" fill="#F5C542" opacity="0.66"/><rect x="380" y="34" width="46" height="46" rx="8" fill="#F5C542" opacity="0.79"/><rect x="456" y="66" width="46" height="14" rx="8" fill="#F5C542" opacity="0.48"/></svg></div>
174
+ </div>
175
+ <div class="wardrobe">
176
+ <span class="wardrobeLabel">今日穿搭</span>
177
+ <span class="chip" style="border-color:#7A8CA355;color:#7A8CA3">鱼缸<em>背景</em></span><span class="chip" style="border-color:#7A8CA355;color:#7A8CA3">白围裙<em>身体</em></span><span class="chip" style="border-color:#7A8CA355;color:#7A8CA3">红围巾<em>颈部</em></span><span class="chip" style="border-color:#7A8CA355;color:#7A8CA3">圆框眼镜<em>面部</em></span><span class="chip" style="border-color:#7A8CA355;color:#7A8CA3">饭碗<em>手持</em></span><span class="chip" style="border-color:#7A8CA355;color:#7A8CA3">草帽<em>头部</em></span>
178
+ </div>
179
+ <div class="howto">
180
+ <div class="howtoTitle">怎么养出同款</div>
181
+ <div class="howtoCmd">dsh plugin --profile web add dsh-feiyu-wardrobe</div>
182
+ <div class="howtoHint">照常让 agent 干活 → token 自动变成鱼粮 → /fish list 换装 · /fish report 出卡</div>
183
+ </div>
184
+ <div class="footer">
185
+ <div><b>github.com/GIT121995/dsh-feiyu-wardrobe</b></div>
186
+ <div>原创形象 · 非官方二创 · 数据只在本机</div>
187
+ </div>
188
+ </div></body></html>
Binary file
Binary file