# dsh-miaomiaopaper (喵喵壁纸管理器 🐾)

> **本项目 Fork 自 [elysia395/dsh-wallpaper-engine](https://github.com/elysia395/dsh-wallpaper-engine)，由 @moshe233 二次开发与优化；已基于上游干净源码 v1.2.0 重建。** 感谢原作者 elysia395 的杰出工作！

![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg) ![node: >=18](https://img.shields.io/badge/node-%3E%3D18-5fa04e.svg)

[English](README.en.md) | [中文](README.md) | [小白向指南](README.beginner.md)

> 🆕 **没用过命令行？先看这里：[小白向使用指南（新手快速上手）→](README.beginner.md)** —— 给完全没接触过命令行的用户准备的简化说明。

一个 DSH bundle，把你电脑上的 **Wallpaper Engine** 壁纸变成 **DSH 网页界面（`dsh web`）的背景**。

![主界面效果展示](docs/images/main-interface.gif)

> 壁纸 + 磨砂遮罩 + iOS 液态玻璃，渲染在 DSH 界面后方。

## 目录

- [能做什么](#能做什么) · [更新前置条件](#更新前置条件) · [支持哪些壁纸类型](#支持哪些壁纸类型) · [工作原理](#工作原理)
- [安装](#安装) · [使用](#使用) · [配置](#配置) · [与 dsh-better-sidebar 的兼容适配](#与-dsh-better-sidebar-的兼容适配) · [已知限制](#已知限制) · [开发 / 重建](#开发--重建) · [联系方式](#联系方式) · [致谢](#致谢)
- 版本号、issue 号与性能数字见 [`docs/CHANGELOG.md`](docs/CHANGELOG.md)；升级前置条件见 [`docs/UPGRADING.md`](docs/UPGRADING.md)。
- 📦 npm 包**不带 `docs/`**（随包的是运行期文件：`lib/**`、`cordis.patch.yml`、`scripts/prepare.mjs` 与三份 README）⇒ 上面这些 `docs/…` 链接在 npm / 插件市场里点不开，请到**源码仓库** <https://github.com/moshe-233/dsh-miaomiaopaper> 的同名路径阅读（本 fork 的源码与完整文档都在那里；上游为 elysia395/dsh-wallpaper-engine）。

## 能做什么

它会自动发现你本机的 Wallpaper Engine 安装，列出你的壁纸，并把*可移植*的类型渲染到 DSH 对话界面**后方**的固定图层，配以 iOS 风格的**液态玻璃**界面改造。
> 版本号、issue 号与性能数字一律记在 [`docs/CHANGELOG.md`](docs/CHANGELOG.md)。

**壁纸渲染（核心）**

- **三类壁纸，三条渲染路径**：**Video** 直接播放；**Web / HTML** 走内置 WebWallGL 的网页挂载（宿主注入 WE API + 严格沙箱隔离）；**Scene（场景）** 由内置 **WebWallGL** 实时 WebGL 引擎渲染 —— 粒子系统、puppet 骨骼模型、SceneScript 脚本、鼠标视差与点击交互、包内音频与音频反应。
- **实时优先、逐级降级**：场景 / 网页壁纸由内置渲染器**实时**渲染；渲染页有**心跳看护**，真的出不了帧就按一条**降级链**逐级回退，**首帧之前不留黑屏**，最后一级允许**诚实留空**。
  > 降级链的**顺序、看护判据、失败记忆分层与垫底画面来源**只在
  > [`docs/HOW-IT-WORKS.md`](docs/HOW-IT-WORKS.md) 定义一处 —— 本文只承诺"不会黑屏、不会被一张坏帧永久卡住"，
  > 不重复它的步骤（重复一份就会在下一次改动时漏改一处）。
- **高帧率源可降载**：**帧率上限**把 4K120 这类源一次性转成上限帧率（4K 保留 + AV1），**显著降低 GPU 占用**；**遮挡暂停**三档在最小化 / 失焦 / 电池供电时直接停解码。
- **能搬的都搬**：本地 JPG / PNG / MP4 可直接上传当壁纸；自定义轮播列表按各自的间隔与顺序自动换壁纸（就绪后才切，不黑屏）。

**界面改造（核心）**

- **跟随 DSH 的界面语言**：插件界面接进宿主的语言设置（设置 → 通用 → 语言）—— **语言目录与 dsh web 完全一致**（内置 `中文` / `English`，装了语言包也一并跟随）；切换即时生效，不需要重载页面，设置页、选择器、右栏 / 抽屉、吉祥物、字体集与更新说明全部跟着换。
- **整个设置窗口液态玻璃**：DSH 原生设置窗口整体（对话框 + 左导航 + 全部原生分区）换成液态玻璃，配色、玻璃底色、透明度、雾化都可调。
- **文字面保底**：承载文字的面固定压一层主题底色，最坏情况正文对比度 **4.63:1** —— 滑条调到极端也不会把字压得看不清。
- **字体与光标可细调**：字体按**颜色角色 / 排版角色 / 组件**三层细化（字号、字重、字族各自可设）；输入光标独立取色。整套外观可存成**字体集**（随包自带预设，可新建 / 重命名 / 删除 / 恢复原样，也能**导出导入** `.json` 分享）。
- **壁纸与界面融合可细调**：壁纸模糊、亮度 / 对比度 / 饱和度、壁纸透明度、暗化、边框、雾化，全部即时生效。

**特色功能**

- **吉祥物**：聊天顶部一条可拖拽的**拉绳**，向下拉出**壁纸仓库**抽屉（两套立绘、可缩放），快捷调节随身可用。
- **侧边栏液态玻璃**：为 `dsh-better-sidebar` 的侧边栏专门适配（毛玻璃、高光与层级统一），另有一组独立的侧栏玻璃控制。

## 更新前置条件

> ⚠️ 更新本插件前，**先把 DSH 内核与 `dsh-better-sidebar` 更新到最新**，**顺序不能反**（先更新插件会遇到不兼容的 API）。完整的版本矩阵、三步顺序与「顺序反了怎么恢复」见 [`docs/UPGRADING.md`](docs/UPGRADING.md)。

## 支持哪些壁纸类型？

Wallpaper Engine 本体把壁纸分四种类型；本插件支持其中的三类：

| 类型 | 由谁渲染 | 能否搬到 DSH |
|---|---|---|
| **Scene（场景）** | Wallpaper Engine 自带的 3D 引擎 | ✅ 实时渲染 — 内置 WebWallGL WebGL 引擎（粒子 / 脚本 / 视差 / 包内音频）；失败按出图来源链降级 |
| **Web（网页）** | Wallpaper Engine 内置的 HTML/JS 运行时 | ✅ 实时渲染 — 内置 WebWallGL 的网页挂载 + **注入 WE API**（音频监听/属性/媒体），严格沙箱隔离；失败自动回退兼容 iframe |
| **Video（视频）** | Wallpaper Engine 内置播放器 | ✅ 直接播放 — 走上传视频同一套硬化管线（转码、解码帧率上限、遮挡暂停、倍速/翻转） |
| **Application（应用）** | Wallpaper Engine 启动第三方可执行程序 | ❌ **不支持** —— 它要宿主直接运行外部程序，本插件不提供该能力 |

> **四类壁纸各自的渲染路径、优雅降级、出图来源链与空帧门禁、以及排查用的诊断行**，
> 见 [`docs/HOW-IT-WORKS.md`](docs/HOW-IT-WORKS.md)。

## 工作原理

一句话：**宿主**（`lib/index.js` + `lib/routes/*.js`）负责找到 Wallpaper Engine 与你的壁纸库、
把媒体按需喂给浏览器；**客户端**（`lib/client.js`）负责把选中的壁纸挂到应用三列**后方**的固定图层，
并在「设置」里注册一个一级页签「Wallpaper Engine」。

> 出图来源链（实时渲染 → 内嵌 MP4 → 实时抓帧 → 自定义画面 → 空态）、宿主/客户端分工、
> 全部 HTTP 路由表、以及"为什么没有 CPU 兜底出图"的设计理由，都在
> [`docs/HOW-IT-WORKS.md`](docs/HOW-IT-WORKS.md)。**实现细节以代码注释为准**（本仓「代码即真相」）。

## 安装

### 普通用户（安装已发布版本，推荐）

如果你只是想用这个插件，直接装 npm 上已发布的包即可：

```sh
dsh plugin --profile web add @moshe233/dsh-miaomiaopaper
```

装完重启 `dsh web`，打开 **设置 → Wallpaper Engine** 就能用。

> **macOS / Linux 用户**：本插件在 Windows / macOS / Linux 上**原生可用** —— 三平台装的是**同一个包、同一条命令**（媒体链路也各自原生：GSMTC / MediaRemote / MPRIS）。
>
> macOS 没有 Wallpaper Engine 客户端，因此扫不到 Steam 壁纸库：把「自定义壁纸」的**存储位置**指到一个装着 WE 工程目录的文件夹（`project.json` + `scene.pkg` / `index.html` / `*.mp4`），里面的场景 / 网页 / 视频壁纸会照常收录、场景同样实时渲染；也可以直接上传图片 / 视频。

### 开发者（运行你本地的一份代码）

用 `link:` 装本地一份代码、构建与验证、热挂载与编码铁律（含 **`lib/client.js` 到底是什么**）见
[`CONTRIBUTING.md`](CONTRIBUTING.md)。**宿主端改动要重启 DSH 才生效**（CLI 装的走 `--profile web`，桌面端走 `--profile desktop` 且**必须先完全关闭应用**）。

### 安装失败排查

装不上（`ERR_PNPM_UNEXPECTED_VIRTUAL_STORE` 等）的逐步处置，见
[`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md)。

## 使用

1. 打开 `dsh web`，进入 DSH 界面。
2. 打开 **设置**，左侧导航里找到 **Wallpaper Engine**（一级设置页，侧边栏独立入口）；聊天顶部的**拉绳吉祥物**也能拉出「壁纸仓库」抽屉，两处共用同一套页签与调节项。
3. 点 **选择壁纸** 打开弹窗，在缩略图网格里点选一张（**Application（应用）**类壁纸不支持，不显示在网格中）；点遮罩、按 ESC 或点「关闭」收起弹窗。
4. 用 **暂停/播放** 控制视频壁纸，用 **关闭** 清除壁纸。全部选择与调节都会即时生效并持久保存（见 [配置](#配置)）。

![设置界面功能展示](docs/images/settings-ui.gif)

> 设置界面：液态玻璃卡片，五个页签（壁纸库 / 外观 / 播放 / 系统 / 关于）。

![壁纸选择弹窗与壁纸仓库](docs/images/wallpaper-library.gif)

> 选择弹窗：浏览全部壁纸缩略图，支持批量隐藏与已隐藏恢复。

### 设置的页签

设置页分**五个页签** —— **壁纸库**（选择 / 轮播 / 自定义上传）· **外观**（配色 / 玻璃 / 字体 / 侧栏）· **播放**（效果 + 声音）· **系统**（吉祥物 + 高级）· **关于**（项目简介 / 仓库与实时 Star 数 / 交流群二维码 / 贡献者致谢），每页只保留与它相关的控件，不再是一列三十项的长滚动。页签指示胶囊随选中项平滑滑动，长说明一律收进控件悬停提示（tooltip），行内只保留一句话简述。「关于」不读面板状态、不写设置：文案 + 两张二维码（随包 PNG，走插件自己的路由，离线也显示得出来），外部输入只有那行 **star 数**与这两张图 —— 切进本页时由宿主代取 GitHub API（带缓存，拉不到就显示上一次的值）。**一键 Star 不做**：GitHub 点星必须有你的凭据，插件不存 token —— 按钮打开仓库页，旁边另有可复制的地址。

### 选择与过滤

- **隐藏 / 恢复**：卡片右上角的「隐藏」只把壁纸从列表移除，**不删除源文件**；弹窗的「已隐藏」标签可单张**恢复**或**全部恢复**，「批量」进入多选模式。隐藏当前壁纸不会打断播放，自动轮播也会跳过它。
- **内容分级**：按壁纸的 `contentrating` 字段（WE 壁纸读 `project.json`，自上传内容读 `uploads/.meta.json`）分 **全部 / Everyone（默认）/ PG13 / Mature / 未分级**；自上传内容未标注时按 **Everyone** 处理。这个字段由插件直接扫盘读取，**不跟随 WE 客户端里的成人内容开关**。
- **类型**：按可内嵌类型筛选 —— **全部 / 视频 / 网页 / 图片（自上传）/ 场景**。
- 每个选项都带当前可播放数量；被过滤掉的壁纸会从网格、轮播编辑器与轮播候选中**整体剔除**，也不会被自动选中或轮换。

### 卡片样式与播放控制

- **紧凑布局**（「高级」页签开关）：开启即 **CD 架效果** —— 卡片纵向层叠、悬停放大置顶、一页到底不翻页；关闭为常规网格（默认）。
- **黑胶唱片**：选择界面旁旋转的黑胶把当前壁纸封面当唱片标签，播放时旋转、暂停即停；经典与紧凑两种卡片样式下都显示。
- **倍速**：视频壁纸可选播放倍速档位，基于浏览器原生 `playbackRate`，即时生效、不重载不黑屏。
- **水平翻转**：视频、网页与上传的图片 / 视频都生效（CSS `scaleX(-1)`，零主线程开销）。
- **切换过场**：换壁纸（手动点选与自动轮播共用）可选的转场动画 —— **硬切（默认）** / 交叉淡化 / 推移 / 擦除 / 光圈 / 缩放 / 条带，每种自带基准时长，再乘「快 / 标准 / 慢」三档，方向型过场另有方向可选；系统开启「减少动态效果」时一律按硬切处理。

### 适配目标（宿主形态）

「高级」页签的**适配**段自动识别插件跑在 **原生浏览器 / 非官方桌面端 / 官方桌面端** 哪一种里，并显示「检测到：… · 有 / 无能力头栅栏」；检测不准时可手选覆盖 —— **手选优先于检测**。判定与操作系统无关：宿主按**请求头与 UA** 观测（能力头 `x-dsh-desktop-renderer` ⇒ 非官方桌面端，UA 含 `Electron/` ⇒ 桌面壳，两者皆无 ⇒ 原生浏览器），观测结果用只增不减的闩锁记住。它同时决定四件事：**网页壁纸载荷**走独立媒体源还是应用源（原生浏览器没有栅栏，就不再多开一个 loopback 监听）、**桌面壳材质规则**是否生效（一律经 `[data-we-adapter^="desktop-"]` 门控，浏览器形态不吃壳层材质）、**「窗口失焦时暂停」是否提供**（见下），以及**面板各行的显隐与警示**（手选与检测冲突时直接说明后果，例如手选浏览器却观测到栅栏 ⇒ 网页壁纸会 403）。

### 省电与降载

「高级」页签的**遮挡暂停**三档（最小化 / 切页、窗口失焦、使用电池；各档默认值见控件本身）：命中时机时视频壁纸**直接停解码**（不靠浏览器节流，解码引擎归零），场景实时渲染同时暂停渲染循环；回到界面 / 接通电源自动继续（手动暂停过的不会被自动恢复）。其中**「窗口失焦时暂停」只在适配目标为「原生浏览器」时提供** —— 桌面壳失焦时壁纸多半仍整块可见，按失焦暂停会定格**可见**画面；该档的值不会被删掉，切回浏览器目标即恢复生效。

「效果」页签的**帧率上限**（可选档位见控件本身）针对高帧率源：宿主用 ffmpeg **一次性**把源转成上限帧率（时间线保持**正常速度**、与倍速完全解耦），输出 **4K 保留 + AV1**，缓存后同一张壁纸只付一次成本。播放时**先播原片、转好自动切换**，设置页有**实时进度条**；源帧率已在上限内会自动跳过，转码失败自动回退原片。

> ffmpeg 三档供给：**显式指定**（`DSH_WE_FFMPEG` 或插件目录下的 `ffmpeg/`）→ **自动下载**（npmmirror + GitHub 双源竞速，校验后缓存）→ **系统 PATH**。编码器优先 **NVENC**（`av1_nvenc` → `h264_nvenc`），无 NVIDIA 显卡时回落 **libx264 软件编码**（慢，但能出片）；只有**连 ffmpeg 都拿不到**时该功能才自动关闭，壁纸保持原片，不影响其它任何功能。

### 画面调节

「效果」页签（壁纸激活后）与「外观」页签的「细节」段提供八个滑动条：**壁纸模糊** · **亮度 / 对比度 / 饱和度**（壁纸媒体滤镜）· **壁纸透明度**（整层淡出、融向页面底色，与**暗化**互补）· **暗化**（加深壁纸与文字之间的遮罩）· **边框**（边框 / 分割线对比度）· **雾化**（玻璃面板模糊半径）。全部即时生效、持久保存，**无需刷新页面**；每个控件的取值范围与默认值直接看控件本身。

> **浅色 / 深色由壁纸自己决定** —— 换壁纸后插件会自动切到与壁纸相配的那一侧（取色顺序：作者的 `schemecolor` → 画面占比最大色（作者预览图与真实渲染帧**各判一次，不一致时取深色**）→ 取不到就保持不动；判定按颜色深浅，**只有明显偏亮**才用浅色。作者填的**恰好纯黑**算"没填"，会改用画面主色）。你也可以随时在 DSH 里手动改主题 —— 改过之后**本张壁纸不再自动**，换下一张恢复。偏亮或花纹复杂的壁纸看不清字时调高 **暗化 / 边框**（必要时加一点 **壁纸模糊**），嫌壁纸抢眼则调高 **壁纸透明度**。滑条再怎么调也不会把正文压到看不清 —— 承载文字的面都有**可读性下限**（见上）。

### 实时渲染与壁纸属性

场景 / 网页壁纸默认走内置 **WebWallGL** 实时渲染（`lib/webwallgl/`，MIT，源自 [webwallgl](https://github.com/oneincase/webwallgl)）：粒子系统、puppet 骨骼模型、SceneScript 脚本、鼠标视差 / 点击交互、包内音频与音频反应完整还原。渲染页跑在**同源隔离 iframe** 里并有**心跳看护**，失败按壁纸记住并自动降级（设置里重开开关即重试）。网页壁纸另有**注入的 WE API**（音频监听 / 属性 / 媒体），并强制 `sandbox="allow-scripts"` —— 第三方 HTML 拿不到 DSH 的 origin。

当前壁纸是**场景**或**网页**时，「当前壁纸」卡片上会出现绿色的 **壁纸属性** 按钮：列出作者在 WE 编辑器里定义的可调属性（颜色 / 开关 / 滑块 / 下拉 / 文本 / 文件），改一下**立刻生效**并**按壁纸记住**，「恢复默认」一键清掉这张壁纸的全部改动；面板显示的是**真正生效**的值（从渲染页读回）。

### 自定义壁纸与自动轮播

- **自定义壁纸**：上传本地 **JPG / PNG / MP4** 当壁纸（浏览器与宿主端双重校验）。**存储位置**默认 `~/.dsh-wallpaper-engine/uploads`，可改到任意盘符（绝对路径，支持 `~`）并自动迁移已有文件；**适配模式**有覆盖 / 填充 / 居中 / 拉伸四种。上传的 MP4 按需抽帧生成缩略图；重复上传同一文件按内容识别、直接复用已有的那张。
- **WE 项目目录**：存储位置里含 `project.json` 的壁纸项目目录（含 `scene.pkg` / `index.html` / `*.mp4`）会被自动收录成对应类型，场景壁纸同样走实时渲染；这些目录**只读**，不参与上传管理，也不会被删除。
- **自动轮播**：轮转基于**自定义轮播列表** —— 用 **新建** 建任意多个列表，从库存勾选壁纸加入，每个列表单独设**切换间隔**（按分钟，范围与默认见控件本身）与**播放顺序**（顺序 / 随机），再勾选 **自动轮转** 只在该列表内循环。每个列表至少需要 2 张可播放壁纸；首次使用时插件会把第一个可播放的 WE 播放列表导入成一个列表，编辑时也可用 **从 WE 播放列表导入**。
- **就绪后切换**：到点先在后台把下一张准备到**完全就绪**（实时渲染首帧 / 视频可播放 / 图片解码完成）才落实切换 —— 旧壁纸在准备期间原样保持，就绪瞬间新旧两层交叉淡化，上屏即是活画面、不黑屏闪烁；准备失败的候选自动跳过、链式尝试下一张。

### 液态玻璃外观（整个设置窗口 + 配色 + 透明度）

「外观」页签控制**整个 DSH 原生设置窗口**的观感（参照 dsh-web-ui-all 皮肤中心的设计）：

| 控件 | 作用 | 默认 |
|---|---|---|
| **设置窗口液态玻璃** | 总开关：把设置窗口整体（对话框 + 左导航 + 全部原生分区）换成液态玻璃 | 开 |
| **配色** | 主题色：窗口内的按钮、开关、链接、导航选中、滑块与玻璃高光统一跟随（6 预设 + 自定义取色） | 经典蓝 `#4f8cff` |
| **玻璃颜色** | 设置窗口玻璃的**底色色调**（6 预设 + 自定义取色） | 浅色白 / 深色深夜蓝 |
| **玻璃透明度** | 玻璃面板（设置窗口、输入栏、气泡、侧边栏）的透明度，越高越透 | 见控件本身 |
| **左侧栏覆盖** | 让宿主原生**左侧栏**（会话列表 / 工作区那一列）也跟随「配色 / 玻璃颜色 / 玻璃透明度 / 雾化 / 边框」—— 默认关时那一列直接透出**原样**壁纸（无霜、无底色） | 关 |
| **雾化** | 玻璃模糊半径 —— 设置窗口与输入栏 / 气泡**共用同一套调节参数** | 见控件本身 |
| **文字面可读性下限** | 承载文字的面在玻璃色之下固定压一层主题底色（正文保持 ≥4.5:1），**默认开启且不提供开关** | 开 |
| **主题随壁纸** | **开关，默认关**。开启后换壁纸时按壁纸自动切全局深 / 浅（作者配色 → 画面占比最大色（预览图与真实帧不一致时取深色）→ 取不到则不动；作者填的恰好纯黑按"没填"处理；只有明显偏亮才切浅色。面板「外观 → 主题」那一行会显示最近一次判决的来源与亮度）；在 DSH 设置里手动改过主题则本张不再自动、换下一张恢复 | 关 |

所有控件即时生效并持久保存；不支持 `backdrop-filter` 的浏览器自动回退到高不透明实色，保证文字可读。

> **默认值与取值范围以控件本身为准**。设置的唯一真源是 [`lib/settings-schema.js`](lib/settings-schema.js)（`DEFAULTS` 默认值 / `KINDS` 校验范围 / 枚举表），宿主与客户端都从它派生，面板直接读它渲染 —— 因此本文与其它文档**一律不抄写这些数值**：抄一份就等于多一个会腐化的副本。

### 吉祥物（聊天顶部拉绳）

「吉祥物」页签控制聊天的**拉绳吉祥物** —— 一条可拖拽的拉绳沿顶部吸附，向下拉即拉出**壁纸仓库**抽屉（当前壁纸黑胶、轮播与自定义壁纸管理随手可及）。**形态**以卡片呈现，卡片直接渲染当前形态的立绘并按「吉祥物大小」实时缩放，选形态与看大小在同一处完成：

| 控件 | 作用 | 默认 |
|---|---|---|
| **显示吉祥物** | 是否显示拉绳吉祥物与其壁纸仓库抽屉 | 开 |
| **吉祥物形态** | 切换立绘：**小女仆**（近方形 chibi）或 **鲸御姐**（竖版 2:3 全身体） | 小女仆 |
| **吉祥物大小** | 缩放吉祥物（拉绳盒尺寸随比例变化，拖拽 / 吸附几何自动适配） | 见控件本身 |

![吉祥物快捷调节页面](docs/images/mascot-drawer.png)

> 点击顶部拉绳吉祥物即可拉出「壁纸仓库」抽屉。两幅立绘在打包时都已内联为 base64（透明背景），单文件客户端资源依然自包含；**大小**只改变拉绳自身的盒尺寸，不影响下方的抽屉。

### 字体与输入光标

「外观」页签下两个互不依赖的分区：

- **全局字体** —— **总开关默认关闭**（即 dsh 原生外观）。开启后**按角色 / 按组件**细化（**没有全局字重、也没有全局字体族** —— 一个全局值会把 DSH 的粗细与字族层次压成一档）：
  - **文字颜色角色**：按 DSH 的**颜色角色**分别上色（未设置 = 用 DSH 默认色）；
  - **排版角色**：一行一个角色，列出**字号 / 字重 / 字体**三项 —— 字号是**绝对值 px**（输入框直接显示 DSH 官方字号，留空 = 不改），字重 100–900，字族 7 选 1（「跟随」= 不覆盖），另有「只看改过的」过滤器；
  - **高级字体设置**（子开关）：**按组件**细化 **代码块 / 终端 / markdown / 表格** 四项 —— 只对**启动自探测命中**的组件生效（DSH 改名即整条降级，不误伤）。
  - **字体集预设**：把整套字体外观存成一份**字体集** —— 随包自带预设，可**新建（以当前外观）/ 重命名 / 删除**；改任何一项都只落到**当前这一套**，随时可以「恢复原样」回到它本来的样子；也能**导出 / 导入** `.json`（导出走系统「另存为」）。它是「字体自定义」的附属：关掉总开关即整块收起。
  报错 / 危险 / 警告语义元素强制保留系统红字；「恢复默认」一键清掉全部字体自定义项（**不**影响「只看改过的」这类视图开关）。
- **输入光标** —— 壁纸透过液态玻璃输入框衬在光标后面、两者颜色相近时光标会「隐形」（[#83](https://github.com/elysia395/dsh-wallpaper-engine/issues/83)），这里给光标一个独立颜色：**自动**（默认，恢复 dsh 原生）/ 6 种预设 / 自定义取色，经 `caret-color` 作用于所有文本输入位。

### 系统音频反应与歌曲信息（Now Playing）

「声音」页签三项（前两项默认开启，第三项默认关闭）：

- **系统音频反应** —— 把**系统正在播放的声音**（任何 App，不只是浏览器标签）做成频谱喂给壁纸的音频反应效果。采集的是**系统输出回环**、不是麦克风，macOS / Windows / Linux 三平台都内置（Windows 走 WASAPI 回环，**不再需要「立体声混音」或虚拟声卡**）；拿不到音频时壁纸自动回落内置的模拟频谱。
- **媒体信息** —— 把系统 **Now Playing**（歌名 / 歌手 / 专辑 / 播放态 / 进度 / 时长 / **封面**）交给壁纸：依赖 WE 官方 `wallpaperRegisterMediaPropertiesListener` / `…ThumbnailListener` / `…PlaybackListener`（以及 `…TimelineListener`），识别这些 API 的工坊网页壁纸会自动显示歌曲信息与封面。
- **在线歌词** —— 优先取本地的（音频同目录的 `.lrc` 与已缓存歌词）；开启后本地没有才向 [lrclib.net](https://lrclib.net) 查一次 —— 那次请求会把歌名 / 歌手 / 专辑发出去，所以**默认关闭**。

**反向控制（随「媒体信息」生效）**：场景壁纸里 Now Playing 组件自带的 **▶ / ⏸ / ⏮ / ⏭** 按钮，点击会控制**系统真实播放器**（播放 / 暂停 / 上下曲）—— 只对带该组件按钮的壁纸生效（全库同组件共三张）；控制面与数据面同源：中间件不可用时按钮落到渲染器自己的模拟源，内置实现（纯读取）不提供控制。

> 这些数据由宿主侧自带的 Rust 中间件 [media-bridge](https://github.com/oneincase/media-bridge) 子进程提供（随插件按需下载、校验 sha256 后执行，缓存在 `~/.dsh-wallpaper-engine/bin/`）：macOS 用 MediaRemote、Windows 用系统媒体会话（GSMTC）、Linux 用 MPRIS over D-Bus。因此**不再需要** `brew install media-control`、`playerctl` 或 VB-Cable，macOS 也不再需要 Xcode Command Line Tools；中间件取不到或起不来时自动回落到内置实现，原因写在 `GET /wallpaper-engine/media-status` 的 `fallback` 字段里。

## 配置

本插件不会向模型暴露任何工具或提示文本，对 agent **零 token 开销**，也不写入任何 DSH 自身的设置。本地落盘只有三类：宿主端配置文件 `~/.dsh-wallpaper-engine/config.json`（选择、隐藏、轮播、配色、字体等全部设置，以及你选的上传目录）、**自定义壁纸文件**本身，以及 `~/.dsh-wallpaper-engine/` 下的**缓存与按需下载的运行时**（抽帧转码 / 实时抓帧 / 视频缩略图缓存、ffmpeg 与媒体中间件的二进制）。

**环境变量**：

| 变量 | 作用 |
|---|---|
| `DSH_WE_FFMPEG` | 指定 ffmpeg 可执行文件（解析链最高优先） |
| `DSH_WE_FFMPEG_URL` | 替换自动下载源（自建镜像 / 代理加速） |
| `DSH_WE_CACHE_DIR` | 覆盖缓存根目录（抽帧转码缓存 / 实时抓帧缓存） |
| `DSH_WE_STEAM_ROOT` | 显式指定 Steam 根目录（逗号/分号分隔，Windows 或 `/mnt` 路径；注册表/自动探测失效时的兜底） |
| `DSH_WE_MEDIA_BRIDGE` | 指定媒体中间件的可执行文件（开发/自备产物；解析链最高优先） |
| `DSH_WE_MEDIA_BRIDGE_URL` | 替换中间件下载源（自建镜像 / 代理加速；支持 `{tag}` / `{asset}` 占位符） |
| `DSH_WE_MEDIA_BRIDGE_TAG` / `DSH_WE_MEDIA_BRIDGE_SHA256` | 换用其它版本的中间件（自定义版本必须同时给出 sha256，否则拒绝执行） |
| `DSH_WE_MEDIA_LEGACY` | `=1` 强制使用内置实现（对比排查用） |
| `DSH_WE_MEDIA_NO_AUDIO` | `=1` 只取歌曲信息、**永不碰系统音频采集**（不申请授权） |
| `DSH_WE_MEDIA_PROVIDER` | `=mock` 用中间件自带的假播放器联调（不需要真播放器） |
| `DSH_WE_MEDIA_IDLE_MS` | 空闲多少毫秒后停掉中间件子进程（`0` = 不停；缺省值见实现） |
| `DSH_WE_MEDIA_DEBUG` | `=1` 把中间件的 stderr 与启动参数打到宿主日志 |
| `DSH_WE_DATA_DIR` | 覆盖插件数据目录（默认 `~/.dsh-wallpaper-engine`；自检脚本用它隔离，避免写到你真实的 `config.json`） |
| `DSH_WE_UPLOAD_DIR` | 覆盖自定义壁纸的存储位置（优先于设置里的「更改」与默认目录） |
| `DSH_WE_ASSETS_DIR` | 覆盖「官方资源路径」（WE 的 `assets` 树；优先于设置里那一项） |
| `DSH_WE_TRANSCODE_TIMEOUT_MS` | 覆盖单次转码的墙钟预算（毫秒；缺省值见实现） |

**设置存在哪**：从 v0.4.0 起全部设置存在宿主端文件 `~/.dsh-wallpaper-engine/config.json`（与浏览器端口无关，
重启 / 换端口 / 清浏览器数据都不会丢；老版本的 localStorage 配置会自动迁移）。文件位置、多设备共享与读写行为见
[`docs/UPGRADING.md`](docs/UPGRADING.md) 的「设置持久化」。

## 与 dsh-better-sidebar 的兼容适配

本插件的液态玻璃效果对 dsh-better-sidebar 的侧边栏面板做了专门适配（毛玻璃、高光与层级统一），让侧边栏与对话区共享同一套「壁纸 + 遮罩」背景，三列视觉一致、不再割裂。

「外观」页签还提供一组独立于会话玻璃和当前壁纸的**侧栏玻璃**细粒度控制：即使没有启用 Wallpaper Engine 壁纸，也可以在普通 DSH 背景或其他背景来源上调整侧栏。它只作用于 dsh-better-sidebar 的侧边栏子树；不支持 `backdrop-filter` 的浏览器会自动回退到高不透明实色。

| 控件 | 作用 | 默认 |
|---|---|---|
| **侧栏液态玻璃** | 总开关：把侧边栏面板换成液态毛玻璃 | 开 |
| **侧栏模糊** | 侧边栏毛玻璃的模糊半径 | 见控件本身 |
| **侧栏透明度** | 侧边栏玻璃的浓淡（**越大越透**） | 见控件本身 |
| **侧栏玻璃颜色** | 侧边栏玻璃的**底色色调** | `#ffffff` 白 |

> 侧栏玻璃与设置窗口玻璃是两套独立参数：会话玻璃的「玻璃」滑杆只管输入栏/气泡，侧栏玻璃滑杆管侧边栏。关闭「侧栏液态玻璃」会连同编辑器/终端内容面一起恢复原生样式。侧边栏默认较透（与背景观感一致、避免面板发白）；编辑器/终端等内容面另有独立的近不透明底色 + 透明度控制，保证窄面板里文字可读。

![dsh-better-sidebar 兼容适配与字体自定义](docs/images/better-sidebar-font.png)

> 侧边栏液态玻璃适配与「外观」页签的字体自定义（行楷）同时生效的实际观感。

## 已知限制

- **Application（应用）**类壁纸不支持 —— 它要宿主直接运行第三方可执行程序，本插件不提供该能力，因此不显示在缩略图选择器和轮播候选中。**Scene（场景）**壁纸由内置 WebWallGL 引擎实时渲染，不需要 Wallpaper Engine 在后台运行。
- 浏览器需能自动播放静音 `<video>`（DSH 跑在 loopback，现代浏览器允许静音自动播放）。
- 媒体从你本机的 Wallpaper Engine 安装路径提供；host 只提供它已枚举过的文件，不会暴露任意文件系统。自定义上传的文件同样只存在于本机，不上传任何服务器。
- **抽帧转码依赖 ffmpeg**：编码器优先 NVENC（`av1_nvenc` → `h264_nvenc`），无 NVIDIA 显卡时回落 **libx264 软件编码**（慢但可用）；只有拿不到 ffmpeg（含自动下载不可用，如 musl/Alpine 等未覆盖平台）时，帧率上限功能才自动关闭，壁纸保持原片播放，不影响其它任何功能。
- **桌面端最小化 / 还原时仍可能有极短的白帧（壳侧）**：壁纸激活期间插件会给根元素垫一层不透明的**壁纸代表色**，于是「壁纸层的像素没送到屏上」这一类会退化成同色底而不是白闪；但窗口**一帧都没有可提交**的那一瞬，露出的是桌面壳的窗口底板（Windows 上 `BrowserWindow` 用的是默认底板色 = 白；壳侧只给 macOS 设了透明底板）。这一条要壳侧配合，插件侧改不动。
- **遮挡暂停对视频壁纸与场景实时渲染生效**：视频壁纸直接暂停解码；场景实时渲染经控制面暂停渲染循环（GPU 占用随之回落）。纯网页（iframe）壁纸无法从外部暂停，只能随页面隐藏被浏览器节流。
- 选择器文案为中英混合（本 bundle 尚未接入 DSH 的 locale 命名空间）。

## 开发 / 重建

想跑本地一份代码（`link:` 安装、构建与验证、热挂载与编码铁律、以及 **`lib/client.js` 到底是什么**）见
[`CONTRIBUTING.md`](CONTRIBUTING.md)。

## 联系方式

有问题、想反馈，或者想第一时间拿到新版本，欢迎加入交流群（插件里 **设置 → 壁纸引擎 → 关于** 页显示的就是下面这两张码）：

| 🐧 QQ 群 | 🎵 抖音群 |
|---|---|
| <img src="lib/about/qq-group.png" alt="QQ 群二维码" width="260"> | <img src="lib/about/douyin-group.png" alt="抖音群二维码" width="260"> |
| **DSHWE \| LLM 讨论群** | **dsh 交流群**（群号 252729465001） |

> 图片用的是随包资源 `lib/about/*.png`（插件运行时由自己的路由提供同一份字节）；源截图与派生口径见 [`assets/about/README.md`](assets/about/README.md)。

## 致谢

本插件是许多人贡献的成果，感谢他们：

- **[oneincase](https://github.com/oneincase)** —— 内置 [WebWallGL](https://github.com/oneincase/webwallgl) 实时渲染引擎与 [media-bridge](https://github.com/oneincase/media-bridge) 媒体中间件的作者（[#103](https://github.com/elysia395/dsh-wallpaper-engine/pull/103)、[#104](https://github.com/elysia395/dsh-wallpaper-engine/pull/104)）：场景 / 网页壁纸的实时渲染与 Windows / macOS / Linux 三平台原生媒体链路都建立在它们之上。
- **[YV3507](https://github.com/YV3507)** —— 提交量最大的贡献者：从早期场景渲染器起步，到静态帧系列修复、液态玻璃令牌体系、live 帧链路与多轮大型重构与文档 / 守卫体系，几乎每个里程碑都有他。
- **[yuxilao](https://github.com/yuxilao)** —— scene-gl Linux 实时渲染管线（WebGL2 官方 shader 驱动 + 多轮性能优化）与轮换交接 / GPU 帧回填 / 官方资源路径（[#65](https://github.com/elysia395/dsh-wallpaper-engine/pull/65)、[#108](https://github.com/elysia395/dsh-wallpaper-engine/pull/108)）。
- **[Jerry](https://github.com/ruijiaang-lab)** —— 在三平台原生支持落地之前，macOS 侧的适配与贡献路径由他维护（WaifuX 工坊目录扫描、黑胶缩略图兜底、上游移植与 macOS 贡献路径梳理，[#44](https://github.com/elysia395/dsh-wallpaper-engine/pull/44)、[#45](https://github.com/elysia395/dsh-wallpaper-engine/pull/45)、[#52](https://github.com/elysia395/dsh-wallpaper-engine/pull/52)、[#54](https://github.com/elysia395/dsh-wallpaper-engine/pull/54)）。
- 还有 [SiriLee](https://github.com/SiriLee)（壁纸亮度 / 对比度 / 饱和度调节、吉祥物拉绳开关、WSL 下探测 Steam 根目录）、[libiwolve](https://github.com/libiwolve)（内容分级与类型过滤）、[0-007pro](https://github.com/0-007pro)（自动轮播）、[jujubaoj646-star](https://github.com/jujubaoj646-star)（字体与气泡样式自定义面板）、[xiahou001](https://github.com/xiahou001)（壁纸音轨音量控制）、[wilianyichen](https://github.com/wilianyichen)（MP4 按需缩略图与自上传内容分级）、[hecoococ](https://github.com/hecoococ)（侧栏玻璃与活动壁纸解耦）、[ShamSky88](https://github.com/ShamSky88)（玻璃模糊定位修复）、[Rekk0](https://github.com/Rekk0)（玻璃透明度令牌化、注册表定位 Steam）、[Y1X1n](https://github.com/Y1X1n)（小白向使用指南），以及所有通过 issue 反馈与 PR 参与改进的朋友 —— 谢谢你们！
