dsh-plugin-wallpaper
给 DeepSeek Harness Web GUI 铺一层整窗壁纸:面板变成「开向壁纸的窗」,卡片与菜单保持实心。
壁纸来源四种:浏览器实时绘制的动态场景(默认)、8 套内置渐变、你拖进来的图片,以及从本机 Wallpaper Engine 库导入的真实壁纸(视频 / 网页工程 / GIF / 静态图)。
这个插件只读你本机的 Steam 库,不联网、不上传、不复制素材;仓库里不含任何壁纸文件。
功能
- 动态壁纸(无需素材):极光 / 星尘 / 深潮三套场景由一个
<canvas>实时绘制(rAF、约 30fps、0.75× 缓冲、页面隐藏时停画、prefers-reduced-motion只画一帧)。 - Wallpaper Engine 导入:
- 自动发现所有 Steam 库(读
steamapps/libraryfolders.vdf+ 各盘常见路径),扫wallpaper_engine/projects/**与workshop/content/431960/*; - 视频壁纸播原文件(
Range→206流式); - 视频贴在
scene.pkg里的场景壁纸,直接从 pkg 内部按 Range 取字节播放(不落地、不解包); - 网页工程用
<iframe>跑真实工程目录; - 带 GIF 的壁纸直接铺 GIF;
- 其余按静态壁纸,优先用工程自带的大图。
- 自动发现所有 Steam 库(读
- 内容识别:见下文「识别流水线」——不信
project.json的type,而是探测文件本身,并把判断依据(reason)与视频编码(codec)写进接口和卡片 tooltip。 - 可调:可读性遮罩、模糊、亮度、填充方式(铺满 / 完整 / 拉伸)、缓慢漂移。
- 明暗自适应:跟随
body[data-ds-dark-theme]自动切换亮/暗素材。 - 可逆:关掉开关,样式表 /
<video>/<iframe>/<canvas>一起移除,主题原样恢复。
架构
一个插件两个半边,通过本机 HTTP 路由通信:
Client(浏览器) Host(DSH 进程)
├─ 壁纸绘制层 ├─ Steam 库发现
│ html::before 静态图 / GIF ├─ project.json 解析
│ <video> 视频(含 pkg 内嵌) ├─ 内容探测(pkg / MP4 / GIF / 图片)
│ <iframe> 网页工程 ├─ GET /wallpaper-engine/library
│ <canvas> 实时场景 ├─ GET /wallpaper-engine/media?id=&role=
├─ html::after 可读性遮罩 ├─ GET /wallpaper-engine/web/<id>/<path>
└─ Settings 页 └─ GET /wallpaper-engine/asset/<id>/<role>
客户端只拿到 16 位不透明 id,永远拿不到真实路径;路由按 id 反查扫描结果,路径始终在扫描白名单内。
识别流水线(v2 重点)
旧版按 project.json 的 type 分类,会把「视频贴图场景壁纸」误判成静态。现在每个工程都会被探测一遍,按优先级得出 motion:
| 顺序 | 探测内容 | reason |
|---|---|---|
| 1 | 工程内有独立视频文件(.mp4/.webm/.m4v/.mov) |
video-file |
| 2 | scene.pkg 里扫到 MP4 box 链(ftyp → moov/uuid/free → mdat),按 box 累加得到完整 extent |
video-packed |
| 3 | 工程内 / preview.* 是 GIF |
gif-preview |
| 4 | type: web 且工程内有可用的 index.html |
web-project |
| 5 | 工程自带最大图片(如 materials/beach.png) |
project-image |
| 6 | 最后退回 preview.* |
preview-frame |
| — | 找到视频但浏览器解不了(如 HEVC) | codec-unplayable:<codec> |
细节:
- MP4 编码探测:读
moov/trak/mdia/minf/stbl/stsd的首个 sample entry fourcc →h264/hevc/vp9/av1/mpeg4。Chromium 能解h264、vp9、av1;hevc会降级成 GIF/静态并标注,避免「黑屏壁纸」。探测失败时 fail-open(当作可播)。 - pkg 内嵌视频:先分块扫全文件找
ftyp(带 1.2s 时间预算),再走 box 链算范围;多个候选取最大的那个。结果按 pkg 的mtime+size缓存。 - Range 映射:
Content-Range: bytes a-b/<inner.size>,实际读pkg[inner.offset + a … inner.offset + b],所以浏览器拖进度、首帧加载都正常。 - 探到的依据会出现在设置页卡片的 tooltip 里:
标题 · 动态 · h264 · video-packed。
Wallpaper Engine 导入
| 判定 | 处理方式 | 角标 |
|---|---|---|
| 独立视频 | <video> 播原文件 |
动态 |
| pkg 内嵌视频 | <video>,Range 映射进 pkg |
动态 |
| 网页工程 | <iframe> 跑工程目录 |
网页工程 |
| 带 GIF | 直接铺 GIF | 动态 GIF |
| 其余 | 静态图(工程自带大图 / 预览帧) | 静态 |
「只看动态」开关默认关闭(全部条目可见);打开后只留视频、网页工程与 GIF。
路由:
| 路由 | 作用 |
|---|---|
GET /wallpaper-engine/library |
扫描结果 JSON,含 features / kind / motion / reason / codec / sources;?refresh=1 跳过 30s 缓存 |
GET /wallpaper-engine/media?id=<id>&role=media |
视频(独立文件或 pkg 内嵌),支持 Range → 206 |
GET /wallpaper-engine/media?id=<id>&role=still |
静态 / GIF 画面 |
GET /wallpaper-engine/media?id=<id>&role=preview |
卡片缩略图 |
GET /wallpaper-engine/web/<id>/<path> |
网页工程文件(prefix) |
GET /wallpaper-engine/asset/<id>/<role> |
媒体/预览的 prefix 捷径(可选) |
安装
在 DSH 里用插件管理器装本仓库(绝对路径):
plugin_manager { action: "install_bundle", target: "<本仓库绝对路径>" }
或手动:
- 把仓库路径加进 profile 的
package.jsondependencies:"dsh-plugin-wallpaper": "file:<绝对路径>"; dsh.profile.bundles数组里加"dsh-plugin-wallpaper";- 让 profile 的
node_modules/dsh-plugin-wallpaper指到本仓库(junction / symlink 均可)。
装好后刷新页面即生效。
⚠️ Host 半边只在 DSH 启动时
import,所以装好或改过 Host 代码后要重启一次 DeepSeek Harness;没重启时设置页会显示「壁纸服务还没加载」,内置壁纸与动态场景不受影响。
使用
侧边栏 → 设置 → 背景壁纸:
| 控件 | 说明 |
|---|---|
| 启用背景壁纸 | 总开关,关掉即恢复默认外观 |
| 动态壁纸 | 极光 / 星尘 / 深潮(canvas 实时绘制) |
| 内置壁纸 | 8 套渐变,亮/暗各一张 |
| 自定义图片 | 选图或拖图,本地压缩后存 localStorage |
| Wallpaper Engine | 本机库缩略图墙,右上「重新扫描」 |
| 只看动态 | 隐藏静态壁纸 |
| 可读性遮罩 | 15%–80%,越高越好读 |
| 壁纸模糊 | 0–30px(同时决定绘制层为模糊留的边) |
| 填充方式 | 铺满 / 完整 / 拉伸 |
| 壁纸亮度 | 50%–130% |
| 缓慢漂移 | 极慢缩放呼吸感 |
| 恢复默认 | 清空自定义与导入,回到动态壁纸 |
偏好存在浏览器本地(dsh-plugin-wallpaper:v8)。
开发
仓库自带几个离线工具(不需要 DSH 也能跑,用来验证 Host 与页面渲染):
# 1. 列一遍本机 WE 库:类型 / 文件 / 预览 / 最大视频
node tools/scan-library.mjs "D:/SteamLibrary/steamapps/common/wallpaper_engine/projects" \
"D:/SteamLibrary/steamapps/workshop/content/431960"
# 2. 直接驱动 Host 半边:打印路由、库 JSON、预览/视频/静态 字节数与 Range 响应
node tools/host-check.mjs lib/host.js
# 3. 离线渲染 Settings 页,确认 N 个按钮都出来了(不需要浏览器)
node tools/render-client.mjs lib/client.js dark video
隐私与边界
- 只读:不写 Steam 目录、不复制素材、不联网。
- 客户端拿不到文件路径,只能按不透明 id 请求,且 id 必须在本次扫描结果里。
- 网页壁纸的
<iframe>用sandbox="allow-scripts allow-same-origin"且pointer-events:none,不抢输入。 - 所有资源在插件卸载 / 关闭开关时移除。
已知限制
scene.pkg是 Wallpaper Engine 的私有格式,没有浏览器端渲染器:本插件只能取出其中的视频(很多动态壁纸正是这么做的),纯粒子 / 着色器场景无法还原,只能 GIF 或静态一帧。- 网页壁纸依赖作者自己的运行时,部分工程调用 Wallpaper Engine 专属 API(音频响应、属性)会退化。
- 首次进入大视频(几十 MB)有几秒缓冲;pkg 扫描首次约 1–2s,结果有缓存。
- 大结构面透明后,少数直接拿
bg-base当底色的弹层也会变透明(菜单/卡片走bg-layer-*,不受影响)。
License
MIT · 本项目与 DeepSeek 官方无关,Wallpaper Engine 是其版权方的商标。
No comments yet. Be the first to write one.