Skip to content
dsh.fish
Bundle

dsh-background-by-model

Appearance plugin for DeepSeek Harness: an ordered list of model rules, each carrying its own wallpapers — every image with its own framing and theme color — plus layout mode, opacity, brightness and blur; the background follows the model you switch to, a

Source
Tkingxiao
License
MIT
Updated
Updated 2 days ago

Readme

# dsh-background-by-model

<p align="center">
  <a href="https://github.com/HarmlessFunny/dsh-background-by-model"><img src="https://img.shields.io/github/stars/HarmlessFunny/dsh-background-by-model?style=social" alt="GitHub stars"></a>
  <a href="https://www.npmjs.com/package/dsh-background-by-model"><img src="https://img.shields.io/npm/v/dsh-background-by-model" alt="npm version"></a>
</p>

[English](README.md) | 中文

> 派生自 [`Tkingxiao/dsh-any-background`](https://github.com/Tkingxiao/dsh-any-background),并重命名为 `dsh-background-by-model`。

一个 **DeepSeek Harness** 外观插件,核心是一份**有序的模型规则列表**:每条规则自带壁纸(可多张)、透明度、亮度与模糊度,**每张图各有自己的布局模式、取景与主题色**。切换模型即切换背景,切换过程走你在「配置」页选定的全局[切换效果](#切换效果全局)。

> **v0.3.0 是破坏性更新** —— 视频背景、生成式背景与全局主题色均已被移除。详见 [CHANGELOG.zh.md 的 v0.3.0 条目](./CHANGELOG.zh.md#v030)。

---

## 模型规则如何工作

一条规则 = 一个**匹配串** + **一整套背景外观**。切换模型时,插件读取当前会话的模型名,自上而下扫描列表,使用**第一条**「匹配串出现在模型名里」的规则(忽略大小写)—— 都没命中时用**第 1 条**兜底。

示例列表:

| # | 匹配串 | 背景图 |
| --- | --- | --- |
| 1 | `deepseek` | 图 1 |
| 2 | `flash` | 图 2 |
| 3 | `glm` | 图 3 |

| 当前模型 | 结果 | 原因 |
| --- | --- | --- |
| `DeepSeek-Flash` | 规则 1 → 图 1 | `deepseek` 先命中 |
| `GLM-Flash` | 规则 2 → 图 2 | `flash` 比 `glm` 更靠前 |
| `Qwen-Flash` | 规则 2 → 图 2 | `flash` 命中 |
| `GLM-Turbo` | 规则 3 → 图 3 | 只有 `glm` 命中 |
| `Kimi-K3` | 兜底 → 规则 1 → 图 1 | 都没有命中 |

- **顺序即优先级** —— 先命中者胜,而不是最精确者胜;需要时拖动规则调整顺序。
- **匹配串留空**表示该规则不参与匹配、只作兜底,所以「单规则 + 空匹配串」就是一张图到处用。
- 匹配串会同时比对 **provider、模型 id 与模型显示名**拼接出的字符串,三者任一都能用来选中规则。
- 当前模型取自**本会话的持久化模型选择**(输入框上模型选择器读的同一个 `modelSelection` 投影),所以会话内切换模型会立即生效;页面会显示读到的是哪个模型,只读到宿主全局默认时额外标注**宿主默认**。

> 上面的示例表里**没有 `kimi`**,所以切到 Kimi 会走到兜底 = 规则 1 = 图 1,看起来像「没反应」—— 想给 Kimi 单独配图就加一条匹配串为 `kimi` 的规则。

## 截图

同一套界面、同一份配置,只因为当前模型不同:

<p align="center">
  <img src="https://cdn.jsdelivr.net/gh/HarmlessFunny/assets@v0.1.0/dsh-background-by-model/wallpaper-deepseek.webp" alt="DeepSeek 下的外观" width="880">
  <br/>
  <em>DeepSeek V4.1 Flash · 命中匹配串含 <code>deepseek</code> 的规则:浅色壁纸 + 与图相配的主题色</em>
</p>

<p align="center">
  <img src="https://cdn.jsdelivr.net/gh/HarmlessFunny/assets@v0.1.0/dsh-background-by-model/wallpaper-kimi.webp" alt="Kimi 下的外观" width="880">
  <br/>
  <em>Kimi K2.7 Code · 命中匹配串含 <code>kimi</code> 的规则:深色壁纸 + 深色主题,整个界面跟着换肤</em>
</p>

<p align="center">
  <img src="https://cdn.jsdelivr.net/gh/HarmlessFunny/assets@v0.1.0/dsh-background-by-model/rule-editor.webp" alt="单条规则的编辑器" width="660">
  <br/>
  <em>「模型背景」页的单条规则 · 壁纸、透明度、亮度与模糊度属于这条规则;布局模式、取景与主题色属于它正在编辑的那张图</em>
</p>

<p align="center">
  <sub>示例壁纸素材来源于 bilibili <a href="https://space.bilibili.com/4168597">ZipZipPipe</a></sub>
</p>

## 功能特性

### 模型规则

一份有序的规则列表,按当前模型名先命中者胜,第 1 条兼任兜底。

- **规则** —— 增删、排序、命名;每条自带匹配串、透明度、亮度与模糊度。
- **每条规则多张图** —— 胶片条可用文件选择、拖放或一行一个网址填入;可排序、设为第一张、或原地替换(替换会保住它在轮换里的位置)。规则也可以一张图都没有,而只要它还有自己的主题色,空规则依旧参与匹配,所以「清空」是一个看得见的状态,而不是一个陷阱。
- **实时匹配状态** —— 「模型背景」页会显示读到的是哪个模型、落在哪条规则上。
- **导入 / 导出** —— 整套规则导出为 `dsh-background-by-model-theme.json`,图片全部内联;旧版本写出的文件仍可导入。
- **存在磁盘上,不在 `localStorage`** —— 一切都在 `~/.dsh/.dsh-background-by-model-data/` 下,旧的单图配置在第一次读取时就地迁移。
- **中英双语**,自动识别语言环境;宿主重置主题时由守护逻辑重新施加。

### 多图轮换

按规则开启,**默认关闭** —— 轮换真的要花流量、内存和电,所以没有东西会替你打开它。

- **停留时长** —— 10 秒 / 30 秒 / 1 分钟 / 5 分钟 / 30 分钟,或任意自定义秒数(5 秒 – 24 小时)。
- **顺序** —— **按顺序**走完列表后环绕;**随机**在除当前这张之外的所有图片中等概率挑选,所以不会出现「像没触发」的一跳。
- **切换模型时也换一张** —— 第二种触发,完全不排定时器。
- **下一张** —— 随时手动换图,与定时器在不在跑无关。
- **只有生效的那条规则在轮换**,全插件只有一个定时器;标签页隐藏时轮换跟着画面一起停。

### 切换效果(全局)

壁纸**切换**时的样子 —— 「配置」页上的一个设置,所有规则共用,覆盖切模型、轮换一步、手动**下一张**与节日接管。

- **四种效果** —— **淡入淡出**(默认)、**直接切换**、**缩放淡入**、**平移推入**;后两种只对进来的那一层做 `transform`,所以一个字节的额外传输都不花。
- **缓动与同一个时长** —— 标准 / 线性 / ease-out / ease-in-out,以及 `0`–`3000 ms`,其中 `0` 是硬切而不是「没设置」。它取代了 `rotate.fadeMs` 这个没有任何控件能到达的逐规则字段,手调过的值会在第一次读取时折算进来。
- **「减少动态效果」是否决**,而不是把动画缩短。
- **界面配色和壁纸走同一个时钟** —— 只有浅↔深互切立即切换,因为两套调色板之间插值会走过两个方向都读不清的中间调。
- **预览色块**会重放这个效果,因为壁纸淡入它自己是什么都看不见的。

### 节日特殊背景

「配置」页上一个开关,别的什么都没有:中秋与国庆当天壁纸换成该节日自己的画与固定主题色,第二天早上换回来。它出厂是**关**的,[推荐配置](#推荐配置)会替你打开。

- **中秋是农历八月十五**,按**北京时间**从中国农历解析,所以每年都动(2024-09-17、2025-10-06、2026-09-25 …);**国庆是 10 月 1–7 日**;两者撞上时中秋优先。
- **没有图的节日会顺延**给模型规则,而不是把背景刷白。
- **画是下载的,不随包发布** —— 每个节日一张压缩后的壁纸,钉在项目 [assets 仓库](https://github.com/HarmlessFunny/assets)的一个发行 tag 上,当天第一次读取时缓存到 `holiday-cache/<tag>/`。下载由日历把关,所以平常的日子一个字节都不取,此后的每一次启动都直接读盘。
- **画和它的配色都不可以换** —— 节日槽位只读,颜色与满幅的「填充」都取自定义,主题导出也只带你的规则。

### 规则与图片各自的设置

- **壁纸** —— 每条规则一张或多张图;不轮换时规则画的是第一张。
- **主题色** —— HSL 色轮、数值输入、**从本图提取**与吸管。它属于**图片**,没有自己颜色的图跟随系统主题,而不是继承规则色。
- **布局模式** —— 适应 / 填充 / 拉伸 / 平铺 / 居中,逐图保存;规则没有图片时这排是禁用而不是隐藏。
- **取景** —— 拖动平移、滚轮缩放,只在适应模式下可编辑,逐图保存,窗口缩放后保持一致。
- **背景透明度** `0–100%`、**背景亮度** `0–200%`(`100%` 即原图)与**背景模糊** `0–60 px`,三者都按规则。它们只作用于壁纸层;「界面」页的透明度作用于界面各区域。

### 全局设置(「界面」页)

- **每个界面部件各自的透明度** —— 主背景、左侧栏、右侧栏、卡片与菜单、输入框与控件、设置面板、对话文本框、轨迹页与每一个插件页,各有一条滑块。
- **新装出来就已经是作者本人那套外观**,所以第一次运行不需要下载任何东西。
- **与主题色无关** —— 规则没有主题色时,这些滑块全部照常可用。

### 推荐配置

「配置」页点一下就下载作者本人的整套配置 —— 规则、壁纸与界面设置 —— 来自项目的 assets 仓库。

- **托管在数据目录自己的形状里**(`preset/preset.json`、`preset/theme-config.json`,每张壁纸一个 `modelbg-<slot>` 文件),所以它能在 GitHub 上直接编辑,发布它就是一次 `cp`。
- **里面每一个界面数字都是插件本来就用着的值**,所以在新装上是「加上规则和图片」;而在你已经调过的数据目录上,它把这些也一起重置 —— 它是一整份配置,不是一个补丁。
- **先下载、后提问**,所以确认框能如实说出手里有什么 —— 而清空在下载**之后**,绝不在之前。它是面板里唯一会销毁东西的操作。
- **少一张壁纸就整体失败并报出是哪个槽位**,而且每个文件各自重试,已经下到的部分留给下一次。

## 设置界面

设置的**「主题」**分类下现在有三个选项卡:

| 选项卡 | 作用范围 | 内容 |
| --- | --- | --- |
| **界面** | 全局,所有模型共用 | 主背景、左侧栏、右侧栏、卡片面板、输入框与控件、设置面板、对话文本框、轨迹页与每一个插件页的透明度 |
| **模型背景** | 每条规则、每张图片 | 有序规则列表、实时匹配状态,以及每条规则的图片(胶片条)、**逐图布局模式 / 取景 / 主题色**,加上规则自己的透明度、亮度、模糊度与[多图轮换](#多图轮换) |
| **配置** | — | 全局[切换效果](#切换效果全局)、整套规则的进出 —— [推荐配置](#推荐配置)与导入 / 导出(`dsh-background-by-model-theme.json`)—— 外加[节日特殊背景](#节日特殊背景)那一个开关 |

原先的**「色彩」**选项卡已删除 —— 主题色改为规则与图片各自的属性 —— 原**「背景」**选项卡改造成**「模型背景」**。

## 存储位置

数据目录:`~/.dsh/.dsh-background-by-model-data/`(Windows:`C:\Users\<你>\.dsh\.dsh-background-by-model-data\`)

| 文件 | 内容 |
| --- | --- |
| `theme-config.json` | 规则列表(每条规则含图片列表与轮换设置)+ 全局「界面」设置 + 全局切换效果 + 节日覆盖配置 |
| `modelbg-<slot>` | 一张图片,保存为原始字节、无扩展名 —— 一张图一个文件,所以一条有三张图的规则占三个槽位 |
| `holiday-cache/<tag>/<asset>` | 从 CDN 下载的节日画,一个节日一个文件(`mid-autumn.webp`、`national-day.webp`),装在一个以**插件所钉的 assets 发行版**命名的目录里(`v0.1.0`)。tag 进了路径,所以钉了新 tag 的构建从一个空目录开始,而不是被告知上一代的字节就是答案;目录里的文件名仍然是**素材名**,刻意放在槽位命名空间之外,这正是节日槽位只读的原因。被取代的旧代会在新图落盘之后被清掉。删掉这里的文件也没关系,下次那个节日生效时会重新下载 |

## 安装

### 方式一:npm 安装(推荐)

```sh
dsh plugin --profile web add dsh-background-by-model
```

只有这一个来源 —— `github:` 装法拉到的树里没有 `lib/`,也没有任何东西会去构建它。

装完需要重启 `dsh web`。

插件会出现在设置面板的 **“主题”** 分类中。

### 方式二:npx(无需全局安装)

```sh
npx @deepseek-ai/dsh plugin --profile web add dsh-background-by-model
npx @deepseek-ai/dsh web
```

### 方式三:本地构建(开发)

`lib/` **不在仓库里** —— 它由 `src/` 构建而来:打包 tarball 时由 `prepack` 钩子构建,工作副本则由你自己构建。先 clone、安装,再构建:

```sh
git clone https://github.com/HarmlessFunny/dsh-background-by-model.git
cd dsh-background-by-model
pnpm install
pnpm test            # 构建 lib/、类型检查、跑十道检查
```

`pnpm run bundle` 只重建 `lib/`。两者都必须在插件能加载之前先跑一次:新 clone 出来没有 `lib/`。

想在 profile 里挂载一份工作副本,就把它加进 profile 的 `package.json` 并注册这个 bundle:

```jsonc
{
  "dependencies": {
    "dsh-background-by-model": "link:E:/DeepSeek/dsh-background-by-model"
  },
  "dsh": {
    "profile": {
      "bundles": ["dsh-background-by-model"]
    }
  }
}
```

改完 `src/` 必须重新执行 `pnpm run bundle` 才会生效 —— 挂载的 profile 加载的是 `lib/`。

`pnpm test` 会构建、类型检查并跑十道校验,十道都不需要依赖、不需要转译器、也不需要浏览器。也可以单独跑:`pnpm check:holiday` / `pnpm check:rotation` / `pnpm check:transition` / `pnpm check:repaint` / `pnpm check:code-plate` / `pnpm check:image-mode` / `pnpm check:rules` / `pnpm check:preset` / `pnpm check:ui` / `pnpm check:node`:

- **`check:holiday`** —— 两个节日窗口、北京时间的跨日边界、1900–2100 年间的闰八月,以及 `pickHoliday` 的四道闸门。
- **`check:rotation`** —— `nextIndex` / `isRotating`:不走越界、随机不重复当前这张、没有可轮换的东西时绝不报「正在轮换」。
- **`check:transition`** —— `resolveFadeMs` / `transitionPlan`:出厂默认仍然产出与旧版本逐字节相同的过渡串、每一条硬切路径都确实是硬切、「减少动态效果」是否决而非缩短,以及每种效果结束时都完全可见且没有残留缩放。
- **`check:repaint`** —— `shouldRepaint`,包括那条**制造**赢家的编辑,以及任何一条写入路径不再询问、或轮换步骤不再重发界面调色板时报错。
- **`check:code-plate`** —— 代码块底板:token 在 `:root` 与 `body` 上都有声明、浅色分支发出 banner、两块表面各读自己的插件变量。
- **`check:image-mode`** —— 布局模式下放到图片上的那次抬升,以及某个控件编辑的是哪张图、渲染层读的又是哪张图。
- **`check:rules`** —— 选项卡背后那两个住在 `src/client/rules-view.ts` 的判定,以及布局所依赖的页面结构。
- **`check:preset`** —— 推荐配置的重试策略与失败那一次给下一次留下什么,并验证两侧真的在用它们。
- **`check:ui`** —— 两本字典键集一致、每个 `dab-…` 类都有样式、没有死键,以及每个 `var(--dsw-…)` 都是已安装主题发布过的 token。
- **`check:node`** —— 把构建好的 node 半边通过真实的 RPC 处理器跑一遍(`DSH_HOME` 指向临时目录、`fetch` 换成桩):节日配置块、节日画的缓存与清理、镜像回落、逐图颜色抬升、全局切换效果,以及推荐配置的整条链路。

## 常见问题

**所有模型看起来都一样,为什么?**
多半是第 1 条规则的匹配串是空的,它成了纯兜底、把整个列表兜住了。给它填一个匹配串,或把更具体的规则加到它**上面**。

**`GLM-Flash` 命中了不是我想用的规则。**
匹配是先命中者胜,而不是最精确者胜:把更具体的规则往上拖,或调整顺序。

**图片存在哪?**
在 `~/.dsh/.dsh-background-by-model-data/`:每张图一个 `modelbg-<slot>` 文件,外加 `theme-config.json`。

**我开了轮换,背景却一直没变。**
有三件事会拦住它:规则至少要有两张图;标签页必须可见;只有当前模型解析出的那条规则在轮换。

**轮换有代价吗?**
有,所以默认关闭:每张图都按原始保真度保存,每次换图还会重画整个界面。一组控制在两到五张最合适 —— 启动时只读每条规则的第一张,所以代价落在内存和磁盘上,而不是启动时间上。

**删掉规则里的图片之后,主题色为什么不起作用了?**
这是已经修掉的旧行为:现在只要规则**有图、或者有自己的主题色**就仍然生效,照旧匹配、照旧当兜底,只是不铺壁纸、只给界面配色。

**我更新了插件,面板说我的改动没有保存。**
浏览器半边和宿主半边是分开加载的,所以刷新后的新客户端可能正对着仍在跑上一个 node 半边的 DSH 进程,而它读不懂新的配置格式。在你重启 DSH 之前,客户端会扣住所有写入。

**我给一张图设了颜色,其它图片却没跟着变。**
这是设计如此:从 0.7.1 起主题色属于**图片**,所以一组图可以依次是不同调性。唯一例外是**一张图都没有**的规则,那时控件编辑的是规则自己的主题色。

**更新之前我设的主题色去哪了?**
哪儿也没去:在「逐图主题色」之前写下的图片条目**根本没有** `color` 键,而这正是加载时区分「从来没有自己的颜色」和「被主动清空过」的依据 —— 前者会把规则色抬升到每一张这样的图上。

**能分享整套配置吗?**
可以,在**「配置」**页导出即可;导出的 JSON 会把每条规则的图片内联进去。

**支持视频或生成式背景吗?**
不支持。两者都在 0.3.0 中移除,每条规则使用一张静态图片。

**把主题色切回「系统主题」后,界面和设置弹窗为什么不是一套配色?**
这是已经修掉的一个 bug:现在所有表面由同一个调色板来源驱动,清空主题色时会读回宿主自己的令牌、套上你的透明度重发。

**为什么「自定义颜色」点下去就有颜色了?**
因为按下它就等于离开「跟随系统主题」,必须给出一个起始色 —— 它先跑一次「从本图提取」,取不到鲜明颜色时才退回默认色。

**切回「系统主题」后一开始还是浅色,拖一下滑块才变深,为什么?**
同一个 bug 的另一半,也已经修掉:插件在持有主题色时会强改 `body[data-ds-dark-theme]`,而宿主只在主题快照变化时才重写这个标记。现在切换时同步交还标记,每秒的守护定时器也会重读一次宿主调色板。

**我换了新的切换效果,壁纸还是直接跳过去。**
效果是**「直接切换」**,或者时长是 `0` —— 效果和时长是同一个硬切的两种说法,而效果优先。不在插件里的第三种:系统开了**「减少动态效果」**时完全不做动画。

## 近期优化

> 这里只列最近两个版本;更早的版本见 [CHANGELOG.zh.md](./CHANGELOG.zh.md)。

### v0.8.2

- **dsh 依赖下界跟着宿主走** —— `engines.dsh`、5 个 `dsh-client-*` peer 与 `dsh-home-paths` 从 0.1.7 那一代改成声明 `>=0.2.1-alpha.2`,装出来的插件不会再被配上上一代客户端包。`dsh-invariants` 与 `@deepseek-ai/cordis` 各有理由,保持不动。

### v0.8.1

- **壁纸层多了亮度滑块**,夹在透明度与模糊之间(`0–200%`,`100%` 即原图,双击复位),和另外两条一样按规则保存。它们能把画面压暗、能起雾,却没有任何东西能把一张曝光不足的图提亮。
- **亮度与模糊共用一个 `filter`,只在唯一的函数里合成** —— 第二处赋值会让其中一个被静默丢掉,所以完整应用与拖动时的实时更新都走同一个函数。
- **主区里的每一个整页现在是一行(插件页面)**,只做透明度:插件、自动化任务,以及任何插件自己注册的页,都按它挂载的槽来认而不是按名字,所以一个还不存在的页也已经被覆盖。它出厂就是 0,此时插件什么都不写。
- **界面各分区按名字找,不按位置找** —— 框架在覆盖层之后又长出了行,「覆盖层之前的那三个子元素」悄悄变成了错的列,分区滑块一直在往没人看的地方写。
- **「界面」页的模糊度滑块删掉了,连同它们底下那套能力** —— 被雾住的那一列,磨的其实是它背后的壁纸(这件事壁纸层自己的模糊早就按规则在做);被雾住的面板,雾的是一块一旦半透明就没人再看的底色。这一页现在只剩透明度。

## Star History

[![Star History Chart](https://api.star-history.com/chart?repos=HarmlessFunny/dsh-background-by-model&type=timeline&legend=bottom-right)](https://www.star-history.com/?repos=HarmlessFunny%2Fdsh-background-by-model&type=timeline&legend=bottom-right)

## 许可

MIT

Install

dsh plugin --profile web add dsh-background-by-model@0.8.2

Profile: web

Source