1015677515/dsh-theme-holo ↗★ 0

dsh-theme-holo

《狼与香辛料》赫萝主题:浅色「麦秋晨光」与深色「星夜麦田」两套暖色皮肤,附带开场动画、动态档案卡、日志标签分类、右栏待机动画与可拖动探头。 适合喜爱《狼与香辛料》、想要个性化暖色调界面的用户。

패키지
dsh-theme-holo
호환성
미검증
버전
1.0.4
라이선스
MIT
최근 업데이트
2026. 10. 25.

설치

$npx -p @deepseek-ai/dsh dsh plugin --profile web add github:1015677515/dsh-theme-holo

dsh-theme-holo — 赫萝主题

dsh-theme-holo

《狼与香辛料》赫萝主题 —— 给 DeepSeek Harness Web GUI 的一层暖纸皮肤。

羊皮纸底色、麦金强调色、一段 12 秒实时渲染的开场动画、趴在输入框边偷看的她、 一张画像式的账户小卡、一枚可以自己摆位置的「狼与香辛料」字标, 以及只在你开始页亮着的右栏待机画面。

license version node dsh platform


目录

章节功能详解的十个小节
这是什么两套配色
界面预览开场动画
功能一览浮动字标
环境要求偷看的她
安装动态档案卡
功能详解日志标签
插件设置项侧栏脚下的麦田
目录结构与素材插件详情页横幅
常见问题右栏待机画面
实现要点小鲸鱼挂件联动
已知边界
许可证与版权
出处声明
相关链接
English

关于这个目录的方框:GitHub 的 Markdown 渲染器会剥掉所有 style 与 color, 没法给目录加自定义底色的圆角外框。表格是唯一既自带底色与边框、又保留可点击链接 的结构,所以这里用表格来画这个框——底色与线条是 GitHub 主题给的灰调, 不是插件的米色,这点无法改变。


这是什么

《狼与香辛料》赫萝主题:本插件为 DeepSeek Harness 的《狼与香辛料(狼と香辛料)》主题插件。装上之后,Web GUI 会从出厂的中性灰变成暖纸色,并且多出若干装饰性组件 —— 它们全部可以单独关掉。

说明:上方这张横幅是图片,配色取自插件浅色「麦秋晨光」——米黄 #FBF7EF 底、 深米色 #DCC9A8 双线圆角外框、金色 #A2701F 分隔线,文字 #6E5D46。 GitHub 会剥掉 README 里所有的 style 与 color 属性,页面本身的底色和文字颜色改不了, 能承载配色的只有图片。

项说明
形态正规 DSH 插件:index.js(宿主半)+ client.js(浏览器半)+ assets/ + 素材/ + cordis.patch.yml
插件大小约 16 MB(client.js 与 index.js 合计约 198 KB,其余全是素材;docs/ 的 1.7 MB 配图不参与运行时)
素材图片 9 张、视频 6 组、音频 3 件,由宿主侧的 HTTP 路由送出
配色浅色「麦秋晨光」与深色「星夜麦田」(开发中,测试功能)
依赖Node ≥ 22;无第三方运行时依赖

设计上有两条原则:

  1. 不改宿主布局。 所有装饰要么是挂在 `` 上的独立浮动层,要么是纯 CSS 规则, 不改宿主的 flex 盒、尺寸与 overflow。
  2. 全部可关。 每个组件在插件设置里都有开关,关掉即彻底移除,不留残余节点。

界面预览

装上之后,整个 Web GUI 长这样(为保护隐私,余额、今日消耗金额与账号名已遮去,其余为原始截图):

dsh-theme-holo 装到 DeepSeek Harness 后的界面全貌:左侧羊皮纸色侧栏、顶部「狼与香辛料」字标、右上角右栏待机画面、输入框边偷看的她、侧栏脚下麦田

一眼能认出的几处:

位置看到什么
顶部中间「狼与香辛料」浮雕字标,可拖动、可关
右上右栏待机画面(只在右栏自己的开始页亮)
输入框右侧偷看的她,只露兜帽和一双眼
左下角侧栏脚下的麦田,宽度随侧栏走
整页羊皮纸底色 + 麦金强调色,所有文字转暖棕

更多细节图见下方各功能小节。


功能一览

功能一句话
两套配色浅色羊皮纸 / 深色暖墨(深色为测试功能)
开场动画12 秒 canvas 实时绘制:暗里的红眼 → 狼影描红 → 光炸开 → 标题解码 → 就绪
浮动字标「狼与香辛料」字标,位置 / 大小 / 不透明度可调,可整个关掉
偷看的她输入框边只露兜帽和一双眼,指针靠近会升起;可左右拖动
探头语音点她会「疑惑」一声(可关)
动态档案卡悬停左下账户行,升起一张 Steam 式小卡
日志标签「思考 / 读取 / 运行命令」等行内标签各一档暖色
侧栏麦田侧栏脚下的一片麦穗,宽度跟着侧栏走,高度锚在账号行
插件详情页横幅插件管理器里点进本插件时,内容顶部一张 1920×620 的封面
右栏待机画面只在右栏自己的开始页亮的一段动画,六片可换,一进去干活就熄
小鲸鱼联动一键把两个角色 + 一条语音装进 dsh-whale-widget

环境要求

项要求说明
DeepSeek Harness>=0.2.0-rc.1 =22DSH 自带运行时即满足
操作系统Windows / macOS / Linux已在 Windows 11 + DSH 0.2.1-rc.2 实测
磁盘空间约 16 MB其中素材约 13 MB(素材/动画/ 六段视频占 13.2 MB)
第三方依赖无没有 npm 依赖,安装后不需要 pnpm install
网络安装时需要从 GitHub 取包;运行时不联网

这些版本约束同时写进了 package.json:

"engines": { "node": ">=22", "dsh": ">=0.2.0-rc.1 =0.2.0-rc.1  **【未验证】** 这条 `github:` 路径没有在隔离环境里逐步实测过。若解析失败
> (提示找不到包、或装完不出现在列表里),改用下面这条一定可用的本地安装。

本地安装的核心是三行:profile 的 `package.json` 里加 `link:` 依赖、在
`dsh.profile.bundles` 里登记插件名、再到 `node_modules` 下建一个目录链接。

**完整的三种安装方式、自检步骤、卸载与故障排查,都在 [INSTALL.md](https://github.com/1015677515/dsh-theme-holo/blob/dc1878fa2a6173fa6ff4ace8bbe49355af08554c/INSTALL.md)。**

装好之后:开场动画播完、界面变成羊皮纸色就是生效了。如果检测到小鲸鱼挂件,
会弹一次「要不要把赫萝装进挂件」的对话框;不想装就选「暂不安装」,之后不再弹
(见[小鲸鱼挂件联动](#小鲸鱼挂件联动))。

---

## 功能详解

### 两套配色

浅色「麦秋晨光」与深色「星夜麦田」(**开发中,测试功能**),两套值键一一对应。

- 浅色规则挂在 `html body:not([data-ds-dark-theme])` 下;
- 深色规则挂在 `html body[data-ds-dark-theme]` 下。

两套值分别在 `client.js` 顶部的 `PALETTE` 与 `PALETTE_DARK` 两张表里,由同一个循环展开成 CSS 变量。
**两张表的键名与顺序必须完全一致**,改了一个就要改另一个。

**黑夜模式开关**走的是主题服务的 `setTheme('dark' | 'light')`,和「设置 → 外观」用的是同一个
偏好字段,所以两处是同一个状态,不会出现「设置里是深色、插件里写着浅色」的分裂。
宿主没有 theme 服务时回退为直接切 `body[data-ds-dark-theme]`。

**首次安装默认浅色**:DSH 的外观偏好出厂值是「跟随系统」,系统本身是深色的机器,一装好就落在
深色 GUI 上,再叠上「星夜麦田」很容易被误读成「装了插件就被切成黑夜模式」。所以插件在**首次
运行**(`localStorage['dsh-theme-holo.dark-defaulted']` 尚未落闩时)若发现宿主已解析为深色,
会通过主题服务把偏好改回 `light` 一次并落闩;此后只有设置卡片里的开关能再打开深色,插件不会
跟你后来的选择对着干。本来就是浅色的机器不会被碰,只落闩。

**黑夜模式尚未完全适配**:深色下仍有若干细节是按浅色调的,观感不如浅色完整。设置卡片里为此
加了一行提示——「黑夜模式未完全做好适配,请谨慎打开」。

**深色下暖色装饰整体收起**:麦穗纹、飘落的麦粒、偷看的她、连接线这些按浅色羊皮纸调的装饰,
压到深色上会脏,所以用一条规则统一隐藏,只留深色外壳与星夜麦田的 token 值。
浮动字标与联动弹窗不在其列——字标是品牌标识,两套配色下都该在。

### 开场动画(12 秒,实时渲染)

![开场动画末帧](https://raw.githubusercontent.com/1015677515/dsh-theme-holo/dc1878fa2a6173fa6ff4ace8bbe49355af08554c/docs/intro-final.webp)

不是视频,是 canvas 2D 逐帧绘制,用 `requestAnimationFrame` 按真实时间推进。
画布固定 1920×1080,帧率 30 fps,总时长 12 秒。

时间轴:

| 秒 | 画面 |
|---|---|
| 0.8 | 全黑,闭着的眼睑先透出红光 |
| 1.15 – 1.95 | 缓缓睁眼(先半睁,再完全睁开) |
| 2.45 / 2.92 | 两次眨眼,每次 0.2 秒 |
| 3.25 – 3.6 | 视线移向左边的狼影 |
| 3.4 – 6.1 | 镜头在黑暗中后拉 |
| 3.75 – 5.15 | 狼影轮廓被红光从背脊描到吻部 |
| 4.85 | 狼影的眼睛亮起 |
| 5.2 – 7.0 | 狼嚎 |
| 6.35 | 她眨一只眼 |
| 6.55 – 7.95 | 光从双眸炸开,照亮整张画 |
| 7.9 / 8.45 | `DEEPSEEK` 逐字解码出现,`HARNESS` 字距收拢 |
| 8.55 – 9.25 | 拉出一根「缰绳」,线头一颗红点 |
| 9.05 – 9.85 | 三行启动日志逐字打出 |
| 9.9 – 10.45 | 进度条走满 |
| 10.5 / 10.75 | 就绪闪光、标语 |
| 11.3 – 12 | 只淡出声音,画面停住 |

**操作**

- **任意点击 / 按键立刻结束**,0.55 秒淡出后交还屏幕。
- 右下角有 `跳过动画` 按钮,效果等同于点画面任意处。
- 系统开了「减少动态效果」(`prefers-reduced-motion: reduce`)时直接停在收尾帧。
- **音轨默认关闭**,右下角开关是 `♪ 音效 开` / `♪ 音效 关`。打开后会立刻播放并**自动对齐当前画面时间**,
  选择记在本地,下次启动沿用。点开关**不会**跳过片头。
- 插件设置里可以永久关闭开场动画(见[插件设置项](#插件设置项))。关掉后连 canvas 都不创建,
  下一帧就把屏幕交回。

**调试入口**(写在 URL 里)

- `#boot-hold` 把片头停在关键帧;`#boot-hold=11.4` 可指定任意秒数,缺省停在 10.2 秒。
- `#videocap` 停在片头供录屏,`#videocap=tail` 额外多留 5 秒画面。

### 浮动字标

「狼与香辛料」字标(`assets/logo.png`,591×125 透明 PNG)是一块**自己定位的图**:
`position: fixed` + 视口百分比,挂在 `` 上,位置和大小由插件说了算。

**为什么不做成标题栏里的水印**:尺寸和位置会被宿主的 flex 盒、容器单位与 `overflow` 规则牵着走,
插件改不动;而且一开插件设置页(宿主会换掉主面板),整棵会话连同标题栏被卸载,水印得靠常驻观察器
才能回来。挂在 `` 上这两个问题都不存在。

**位置以视口百分比存储**(`xPct` / `yPct` / `wPct`),渲染时用 `vw` / `vh` 单位,
所以窗口缩放、最大化、换分辨率都不需要监听 `resize`,字标自动等比跟随。

**日常不拦点击**:图层常驻 `pointer-events: none`、`aria-hidden="true"`,不挂任何监听。
只有打开「更改 logo 位置」时才变成 `pointer-events: auto`,那时才能拖动。

**调位置、调大小**

1. 插件设置里点「更改 logo 位置」,字标出现一圈细线框、右下角小方块和实时坐标读数;
2. 拖图片移动,拖右下角小方块改大小,读数会实时显示 `x, y · 高 Npx`;
3. 按 `Esc` 也能退出;点「完成调整(固定下来)」把位置写进本地存储。

同一节里还有:

- **关闭 logo**:整个图层收掉(不是把不透明度降到 0——隐藏的东西不该还能接点击)。
  位置和大小原样保留,再点「显示 logo」就回到刚才停的地方。
- **恢复默认位置**:位置、大小、不透明度、显隐四项一起回到出厂值。

**不透明度**:10%–100% 的滑块,出厂 50%,拖动即时生效、松手即存。
下限是 10% 而不是 0:一个几乎透明的字标等于一件找不回来的东西。

**图层高度**:`z-index: 2`。这个数字是调出来的——`-1` 会被宿主的 `.BynINW_frame`
(不透明背景)整个吞掉;`0` / `auto` 会和它同趟按文档序绘制,而插件在宿主渲染外框之前就挂载了,
反过来被盖住。`2` 压得过外框,但低于宿主自己浮起来的控件(缩放手柄、overlay 层等)。
编辑态会升到很高的 z-index 并开启 `pointer-events`。

> 代价是它**会压在别的东西上**——它本来就在 GUI 之上。这是有意的取舍:字标是一块可以挪的图,
> 不是垫在纸下面的水印。想让它让开就把图拖走,或者在设置里「关闭 logo」。

### 偷看的她

输入框边上只露兜帽和一双眼,指针靠近会升起。所有动作由一个状态机驱动:
**露出多少、倾角、让位、点头**四个量,行为只写目标值,循环以 0.14 的系数缓动过去,
所以永远不会「跳」。

| 状态 | 触发 | 表现 |
|---|---|---|
| 常态 | 无输入 | 露出 32%,只到眼睛;整体再下沉 10px,底边被输入框卡片裁掉 |
| 正在打字 | 输入框有内容 | 露出 58%,朝文字倾,并从她手边拉出一根金线接到输入框 |
| 生成中 | 出现「停止」按钮 | 露出 62%,朝文字方向倾,盯着看 |
| 长文看累 | 输入 > 420 字 | 沉下去、透明度降到 55%,歪头表示嫌弃 |
| 打瞌睡 | 空闲 170 秒(23:00–05:00 为 75 秒) | 只留帽檐,鼠标一动就醒 |
| 打开菜单 / 弹窗 | 有 `[role=menu/dialog/listbox]` 或 `aria-modal` | 往右让开自身宽度的 55% 并透明到 0 |
| 靠近 | 指针在 96px 内但没落在她身上 | 往下缩 5px、歪头 |
| 指针移动 | 以她自己的中心算方向 | 整颗头朝指针倾斜,位移上限 ±10px / ±3px,倾角上限 ±2.2° |
| 点击她 | 点 | 纵向压扁一下 + 6 粒金麦从卡片后面飘起,并播一句应答语音 |
| 悬停 5 秒 | 一直指着她 | 一枚小苹果从帽檐后滚出来(纯 CSS 画) |
| 发送 | 点发送或回车 | 往下点一下头(320ms) |

麦粒和苹果都是临时节点,动画结束即移除;金线是 SVG 路径,只在「打字且没有弹窗」时出现。
「减少动态效果」时所有缓动系数置 1,麦粒和苹果直接不出现。

**她可以左右拖**:位置是**输入框宽度的分数**(不是像素),默认 `0.72`。
位移不到 4px 不算拖动,照常当成「点她」;拖过了就把这次抬手产生的 click 吃掉,不会误触发语音。
位置夹在她的中心可达范围内,插图不会跑到输入框两端之外。

**点她会说话**:`assets/peek-voice.wav`(「赫萝疑惑」)复用同一个 `Audio` 元素,
每次点击先 `pause()` 再把 `currentTime` 归零,所以连点不会互相打断、也不会叠音轨。
浏览器不给自动播放权限时静默失败——视觉反馈照常,不弹错。

**关掉她**:插件设置里的「探头的赫萝」开关,关掉后彻底不显示。语音可以单独关:
「探头的她说话」关掉后,点她只有动作,没有声音。

### 动态档案卡

悬停左下角账户行时升起,指针离开 **180ms** 后收起。卡片是纯 DOM + inline style,
**不是** `[role=dialog]`,所以不抢焦点、不锁指针;账户菜单本身完全不动。

结构是横幅图(`intro.jpg` 裁切放大)+ 渐变压暗 + 骑在横幅下沿的圆形头像(`avatar.jpg`)
+ 名字与一行小字。名字取自被悬停那一行的文本,所以换账户会跟着变。

只有侧栏内部滚动会让它收起——消息列表在生成时滚动极频繁,跟着收会让卡片闪一下就没了。

### 日志标签

「思考 / 读取 / 运行命令…」是 Harness 自己的行内标签,类名是哈希过的、所有类型共用一套,
没有 CSS 能直接区分它们。插件里加了一个很轻的观察器:

- 监听 body 的 childList(防抖 180ms),只扫 `span[class*="_title_"]`
- 文本以那几个词开头(长度 ≤ 8)时打上 `data-holo-kind="think|read|run|tool|write"`
- 样式全部挂在 `[data-holo-kind]` 上,卸载时把属性一起清掉

对应关系:思考→think;读取 / 图片 / 搜索→read;运行命令→run;工具调用→tool;写入 / 编辑→write。
开销可以忽略:一轮对话里这些 span 不过几十个,打过标记的不会重复处理。

### 侧栏脚下的麦田

`assets/wheat.png` 贴在左边栏最下面。它是一个挂在 `` 上的**独立浮动层**
(`position: fixed`、`pointer-events: none`),只做一件事:测量侧栏列的矩形,
把 `left` / `width` / `bottom` / `height` 写成视口像素。
**不往宿主元素里插任何节点,也不改宿主元素的任何样式。**

| 项目 | 默认 | 说明 |
|---|---|---|
| 整体不透明度 | `.75` | `#holo-wheat` 的 `opacity` |
| 两侧淡出到 | `.4`(叠 75% 后为 30%) | 横向 `mask-image` |
| 上边缘淡出到 | `.4`(同上,30%) | `#holo-wheat i` 的纵向 `mask-image` |
| 高度 | 侧栏底部 → 账号行垂直中线 | `createWheatLayer()` 的 `place()` |

**边缘的 30% 不是一个独立的数**:两层是相乘关系,`0.75 × 0.4 = 0.30`。所以改整体浓度只动
`opacity` 一行,边缘会按比例跟着走。

**宽度跟侧栏、高度不变形**:图是 `background-repeat: repeat-x` + `background-size: auto 100%`,
宽度由 JS 写成侧栏列的像素宽,高度单独写成固定像素,所以侧栏变宽只是多铺几段,麦秆不会被拉胖。
图本身是 `素材/小麦.png`(452×146)左右**镜像拼接**成 904×146 的无缝片——原图左右缘 alpha
不一致,直接平铺会有一道断口。

高度锚在「账号菜单」行的垂直中线;找不到这行时退回列高的 18%,并夹在 `[24px, 列高]` 之间防呆。
窗口缩放、侧栏折叠、会话列表把账号行挤走,都由 `ResizeObserver` 重算,不轮询。

> 它压在宿主的 `.BynINW_frame` 之上,所以跨过名字那条带会有少量穗尖。
> 靠素材本身消化——`wheat.png` 顶部 0–20% 有 93.8% 完全透明,遮罩又降到 40%,几乎看不出;
> `pointer-events: none` 保证账号行仍可点。

### 插件详情页横幅

插件管理器里点进「赫萝主题」的详情页,内容顶部会有一张 1920×620 的横幅(`assets/cover.webp`)。

它是**正常文档流里的一个块**,不是浮动层,用 `::before` 伪元素实现——那页不归本插件所有,
伪元素不占位、不与标题图标打架、也不用往宿主的 DOM 里塞东西。
选择器用的是插件管理器自己打的 `[data-plugin-detail="dsh-theme-holo"]` 属性,
名字里没有哈希,宿主重建样式表也不会失效。

`cover.webp` 是**已经烘好浓度的版本**——75% 的整体场与 50% 的边缘淡出烤进了 WebP 的 alpha 通道。
CSS `opacity` 会把整个元素(含边框)一起淡掉,而背景图自身没有透明度旋钮,所以这一步在导出时做完。
要调浓淡就重新导出这张图;未压缩原件 `素材/横板封面.jpg` 留在作者本地备查(未随仓库发布)。

### 右栏待机画面

一段只在**右栏自己的开始页**亮着的动画。右栏里一开文件、终端或浏览器,开始页就被替换掉,
整层立刻撤掉——连 `` 都从文档里摘掉、`src` 也丢掉,解码器随之释放。
这是刻意的:待机画面是气氛,不该在干活的时候压在栏底下耗显存。

| 项 | 做法 |
|---|---|
| 容器 | `#holo-scene`(`position: fixed; inset: 0; z-index: -1; pointer-events: none`),由 `html[data-holo-scene="on"]` 打开 |
| 切片 | 宽度取 `min(右栏宽, 608px)`,左边缘对齐画面,`overflow: hidden` 负责裁 |
| 视频 | 固定 **608×1080** 的盒子,**1:1 不缩放**。素材本身就是 608×1080 的竖裁,所以画面里的她是真实尺寸 |
| 渐隐 | 视频顶部 58% 不透明、78% 降到 55%、底部到全透明 |
| 左右边缘 | 各 10% 区域做模糊 + 透明度淡到 50%,中间保持清晰 |
| 深色 | 底色渐变 `#14100B → #100D09`,视频 `opacity: .94`,另叠 scrim 与 veil 两层压暗 |
| 浅色 | 底色渐变 `#FBF7EF → #F6EEDF`,视频 `opacity: .82` + 暖色滤镜 + `mix-blend-mode: multiply`——不是加一层暖色,而是把它**印进纸里** |

**为什么必须清掉宿主的底色**:视频垫在 `z-index: -1`,比宿主外框和右栏自己的不透明背景都要靠后,
不清就是「什么都没发生」。所以亮着的时候,插件会给**内联**加 `background-color: transparent`
并打上标记:右栏面板、栏里每个铺满的大盒子、以及列的祖先链(到 `body` 为止)。
收盘面时把那些内联值 `removeProperty` 掉。**只碰这条已知的祖先链和栏里的大盒子,不做全文档扫描**
——扫一遍会把界面扒光。判断「大盒子」用的是面积阈值(宽 ≥ 栏宽 85%、高 ≥ 栏高 50%),
所以开始页那几个入口胶囊不会被动。

**开始页怎么认**:不认哈希类名,认宿主自己写的三个 `data` 属性——
`[data-sidebar-right-panel]`(栏本身)、`[data-sidebar-right-open]`(展开态)、
`[data-sidebar-right-guide]`(栏自己的开始页)。三个条件同时满足才亮。
一个会话一份面板,被搁置的会话节点还留在文档里,所以查面板和开始页都只在**可见的那一个**里找。

**六段可换,名称就是文件名**。`素材/动画/` 下六个 `.webm` 对应设置页里的六个选项:

| 选项名 | 文件 |
|---|---|
| 赫萝抱臂 | `素材/动画/赫萝抱臂.webm` |
| 赫萝开心(默认) | `素材/动画/赫萝开心.webm` |
| 缪莉开心1 | `素材/动画/缪莉开心1.webm` |
| 缪莉开心2 | `素材/动画/缪莉开心2.webm` |
| 赫萝叉腰 | `素材/动画/赫萝叉腰.webm` |
| 缪莉挥手 | `素材/动画/缪莉挥手.webm` |

选项名与文件名严格一致,**换片只要同名覆盖文件,不用改一行代码**。

下拉框末尾还有第七项 `关闭动画`:它不是文件,选中后右侧栏开始页不显示待机画面,
进入开始页时连视频都不加载(连解码器都不占用)。选回任意一段即可恢复,不用重启。

六段各取一帧,从左到右:

![六段待机动画](https://raw.githubusercontent.com/1015677515/dsh-theme-holo/dc1878fa2a6173fa6ff4ace8bbe49355af08554c/docs/scene-grid.png)

**它看起来糊,通常不是它自己的问题**。素材是 608×1080 的竖裁,按 1:1 显示,**没有上采样**。
真正把画面变糊的是**装了 wallpaper 插件(`dsh-plugin-wallpaper-engine`)并开着液态玻璃 /
磨砂效果**:那一层用 `backdrop-filter: blur()` 把背后的一切——包括这段待机动画——一起雾化。
本插件对视频只写 `opacity`、`object-fit`、`mask-image`、色相滤镜与 `mix-blend-mode`,
**没有任何 `blur()`**。

判断方法:把 wallpaper 插件的雾化强度**调低**(或直接关掉液态玻璃)再看这一栏,糊度随之下降
即为其所致。想让画面清楚又保留玻璃质感,把雾化调到最低档通常就够了。

> 注意别和「小鲸鱼挂件」(`dsh-whale-widget`)搞混:那是角色与语音的挂件,不碰背景滤镜。
> 这里说的雾化只来自 wallpaper 插件。

### 小鲸鱼挂件联动

装了小鲸鱼挂件(`dsh-whale-widget`)的人,可以不动手多出两个可替换角色和一条语音。

| 装进挂件的名字 | 来源文件 | 类型 |
|---|---|---|
| 赫萝 | `素材/holo-clean.png` | 角色 |
| 赫萝Q版 | `素材/holo-Q-clean.png` | 角色 |
| 赫萝震惊 | `素材/赫萝语音.WAV` | 音效组(按下音) |

**什么时候问**:片头播完、页面加载完之后,前端先探一次挂件的 `/dsh-whale/roles.json`:

- 挂件没装 → 路由不存在,`fetch` 失败,安静跳过,什么都不弹;
- 挂件装了、且三个名字里缺任何一个 → 弹一次羊皮纸对话框,说明会装什么,
  给「立即安装」和「暂不安装」两个选择;
- 已经齐了 → 不弹。

「问过了」这件事记在本地,无论选了哪个都记下来,**所以只弹一次**。

**之后想补装**:插件页(插件 → 已安装 → 赫萝主题)的包详情页里有一块「赫萝 × 小鲸鱼挂件」,
常驻显示当前状态,缺什么就列出什么,按钮「一键导入联动内容」。

| 状态 | 显示 |
|---|---|
| 没装挂件 | 「没有检测到小鲸鱼挂件。」,按钮不可用 |
| 检查中 | 「正在检查小鲸鱼挂件…」 |
| 缺内容 | 「还缺:角色 X;语音片段;音效组。」,按钮「一键导入联动内容」 |
| 齐了 | 「已写入小鲸鱼挂件的数据目录:角色「赫萝」「赫萝Q版」,语音组「赫萝震惊」。」 |

导入成功后还会多出一个「刷新页面」按钮——**小鲸鱼挂件只在页面加载时读一次角色列表**,
导入后要点「刷新页面」(或按 Ctrl+R)才会在它的「角色」里出现。不给这个按钮,
导入看起来就像失败了。

**装的时候做了什么**:对每个缺的角色,`fetch` 一次 `/holo-theme/link/` 拿到字节 →
转成 `data:` URL → `POST /dsh-whale/roles.json`;语音同理,先上传片段拿回 `id`,
再用 `save-group` 建音效组。**按名字比对,已有的不动**,所以重复点是安全的。

> 挂件的路由受宿主鉴权保护,所以联动只在浏览器里跑得通,命令行侧没法代劳。
> 这也意味着**必须重启一次 Harness**,新的 `/holo-theme/link/` 路由才会存在。

---

## 插件设置项

插件页(插件 → 已安装 → `dsh-theme-holo`)的包详情页里,卡片最上面是联动区块,
下面依次是六组开关。组件行页也有同一块。

| 小节 | 控件 | 存哪 |
|---|---|---|
| 开场动画 | `关闭开场动画` / `开启开场动画` | `localStorage['dsh-theme-holo.skip-boot']` |
| 探头的赫萝 | `不启用探头的赫萝` / `启用探头的赫萝` | `localStorage['dsh-theme-holo.peek-off']` |
| 探头的她说话 | `关闭探头语音` / `开启探头语音` | `localStorage['dsh-theme-holo.peek-voice-off']` |
| 黑夜模式 | `开启黑夜模式` / `关闭黑夜模式` | 主题服务的 `preference` 字段(同「设置 → 外观」) |
| 右侧待机动画 | 下拉框,前六个选项就是六个动画文件名,末尾另有一项 `关闭动画` | `localStorage['dsh-theme-holo.scene-name']` |
| 更改 logo 位置 | `更改 logo 位置` / `完成调整`,另有 `关闭 logo` / `显示 logo`、`恢复默认位置`,以及一条 10%–100% 的不透明度滑块 | `localStorage['dsh-theme-holo.logo-place']` |

首次安装时,若宿主外观已解析为深色,插件会自动改回浅色一次并把
`localStorage['dsh-theme-holo.dark-defaulted']` 置为 `1`,之后不再干预。想主动用深色,
点「开启黑夜模式」即可。

> **黑夜模式未完全做好适配,请谨慎打开。** 深色下仍有若干细节按浅色调过,观感不如浅色完整。

各开关的状态行文案:

- **开场动画**——关:「已关闭:启动时直接进入界面。」;开:「已开启:每次启动播放约 12 秒。」
- **探头的赫萝**——关:「已关闭:输入框边上不再出现探头。」;开:「已开启:鼠标移到输入框边上时她会探出头来。」
- **探头的她说话**——关:「已关闭:点她只有动作,没有声音。」;开:「已开启:点她会「疑惑」一声。」
- **黑夜模式**——开:「已开启:界面使用「星夜麦田」深色配色。」;关:「已关闭:界面使用「麦秋晨光」浅色配色。」
- **右侧待机动画**——「当前:赫萝开心(默认)。只在右侧栏的开始页显示;左右边缘渐变到 50% 不透明度。」;选 `关闭动画` 时:「已关闭:右侧栏的开始页不再显示待机动画,进入开始页时也不会加载任何视频。」
- **更改 logo 位置**——编辑中显示实时坐标;关闭时「已关闭:logo 停在原处,不会挡住任何点击。」

---

## 目录结构与素材

dsh-theme-holo/ ├── index.js 宿主半:注册三条只读文件路由 ├── client.js 浏览器半:配色、组件与全部交互 ├── cordis.patch.yml bundle 补丁:向 profile 插入一行宿主行 ├── package.json 清单(dsh.bundle / dsh.client / icon) ├── locale/ zh.json、en.json —— 插件列表里的标题与描述 ├── assets/ 主题自己渲染的 9 件素材 ├── docs/ 本 README 用的配图(不参与运行时) └── 素材/ 源料与联动画材(9 件运行时需要,其余是设计稿,不进仓库)


### `assets/` —— 主题自己渲染的图

| 文件 | 字节 | 尺寸 | 用途 |
|---|---:|---:|---|
| `avatar.jpg` | 11,700 | 160×160 | 档案卡的圆形头像 |
| `intro.jpg` | 85,210 | 1920×1080 | 片头底图,也是档案卡的横幅源 |
| `intro.mp3` | 241,004 | — | 片头音轨(12 秒) |
| `peek.png` | 316,083 | 575×560 | 偷看的她:兜帽抱面包,已抠成透明 |
| `peek-voice.wav` | 130,090 | — | 点她时的应答语音 |
| `logo.png` | 45,916 | 591×125 | 浮动字标,已裁掉透明留白 |
| `icon.jpg` | 4,516 | 64×64 | 插件列表图标。**不经过 HTTP 路由**,由 DSH 从清单 `icon` 字段读取 |
| `wheat.png` | 84,582 | 904×146 | 侧栏脚下的麦田,`素材/小麦.png` 镜像拼接成的无缝片 |
| `cover.webp` | 205,082 | 1920×620 | 插件详情页顶部的横幅 |

合计约 1.07 MB。改素材直接替换同名文件即可,**不需要任何构建步骤**。

### `docs/` —— 本 README 的配图