wallpaper-engine-dsh 0.1.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/README.md ADDED
@@ -0,0 +1,107 @@
1
+ # wallpaper-engine-dsh
2
+
3
+ [English](README.md) | [中文](README.zh.md)
4
+
5
+ A DSH bundle that renders your local **Wallpaper Engine** Video/Web wallpapers as the **live background of the DSH web GUI** (`dsh web`) — with crossfade transitions, an iOS-style liquid-glass treatment, four tuning sliders, and user-defined rotation lists.
6
+
7
+ Built with a security-first, test-backed architecture:
8
+
9
+ - **Pure logic layer** (`lib/core.js`) — VDF parsing, discovery, containment — covered by unit tests.
10
+ - **Host layer** (`lib/index.js`) — Cordis plugin serving inventory + media over same-origin HTTP.
11
+ - **Browser layer** (`src/client.js` → `lib/client.js`) — behind-body rendering + settings UI.
12
+ - **Zero model tokens** — no tools, no prompt text; pure UI bundle.
13
+
14
+ ## Why only Video and Web wallpapers?
15
+
16
+ | WE type | Rendered by | Portable to DSH? |
17
+ |---|---|---|
18
+ | **Scene** | WE's own 3D engine | ❌ native shaders/objects |
19
+ | **Video** | a plain media file | ✅ plays in `<video>` |
20
+ | **Web** | HTML + assets | ✅ loads in a sandboxed `<iframe>` |
21
+ | **Application** | an injected external window | ❌ |
22
+
23
+ Unlike simpler integrations, **multi-file Web wallpapers work here**: the host serves a wallpaper's bundled sub-assets (`js`/`css`/images) from inside its project directory, with strict containment checks.
24
+
25
+ ## Architecture
26
+
27
+ ```
28
+ ┌───────────────────────────── DSH web ─────────────────────────────┐
29
+ │ Browser half (lib/client.js) │
30
+ │ settings.general.item slot → picker UI (grid, sliders, lists) │
31
+ │ fixed layer behind the app frame → <video> / sandboxed iframe │
32
+ └──────────────▲────────────────────────────────────────────────────┘
33
+ │ same-origin HTTP
34
+ ┌──────────────┴────────────────────────────────────────────────────┐
35
+ │ Host half (lib/index.js, Cordis plugin, inject: ['webServer']) │
36
+ │ GET /we-background/inventory[?refresh=1] JSON + cached 30 s │
37
+ │ GET /we-background/media/<token>[/asset…] Range + containment │
38
+ │ GET /we-background/preview/<token> preview image │
39
+ └──────────────▲────────────────────────────────────────────────────┘
40
+ │ pure functions
41
+ ┌──────────────┴────────────────────────────────────────────────────┐
42
+ │ Core (lib/core.js) — tested │
43
+ │ VDF parser · Steam discovery · project validation · playlists │
44
+ │ Range parsing · path containment · MIME │
45
+ └───────────────────────────────────────────────────────────────────┘
46
+ ```
47
+
48
+ ## Security model
49
+
50
+ - **Random tokens, not encoded paths.** Media URLs carry a 72-bit random token minted per inventory build; knowing a filesystem path grants nothing. Rebuilding the inventory re-mints every token.
51
+ - **Double containment.** `project.json`-declared files must resolve inside their project directory, and web-wallpaper sub-assets must resolve inside the project dir (`..` → 403).
52
+ - **Sandboxed web wallpapers.** Third-party wallpaper JS runs in an iframe with `sandbox="allow-scripts"` (no `allow-same-origin`) and `referrerpolicy="no-referrer"` — an opaque origin that cannot touch DSH storage, cookies, or APIs.
53
+ - **Loopback + nosniff.** All responses are same-origin with `X-Content-Type-Options: nosniff`.
54
+ - Only enumerated files are ever served; there is no arbitrary-file route.
55
+
56
+ ## Install
57
+
58
+ ```sh
59
+ dsh plugin --profile web add wallpaper-engine-dsh
60
+ ```
61
+
62
+ or from a checkout:
63
+
64
+ ```sh
65
+ git clone https://github.com/Weilv-D/wallpaper-engine-dsh.git
66
+ dsh plugin --profile web add link:<absolute path to the cloned folder>
67
+ ```
68
+
69
+ Restart `dsh web`, then open **Settings → General → 壁纸背景 (Wallpaper Engine)**.
70
+
71
+ ## Usage
72
+
73
+ 1. Pick a Video/Web wallpaper from the thumbnail grid — it crossfades in behind the app. Scene/Application wallpapers are not embeddable and are hidden.
74
+ 2. **暂停/播放** pauses a video wallpaper; **关闭** clears it; **刷新** forces the host to rescan (new Workshop subscriptions appear without a page reload).
75
+ 3. Four sliders tune the blend live: **壁纸模糊** (blur the wallpaper itself), **暗化** (scrim), **边框** (hairline contrast), **玻璃** (frosted-glass panels).
76
+ 4. **轮播列表**: create any number of rotation lists, each with its own wallpapers, interval (1–120 min) and order (顺序/随机); enable **自动轮转** on one. On first run, your first playable WE playlist is imported automatically; **从 WE 播放列表导入** pulls any other playlist into the editor.
77
+ 5. The choice persists in `localStorage`. Switch DSH between light/dark themes freely — every surface reads design tokens and follows along; on busy wallpapers raise **暗化/边框** until text is comfortable.
78
+
79
+ `prefers-reduced-motion` is respected: video wallpapers start paused.
80
+
81
+ ## Limitations
82
+
83
+ - Scene and Application wallpapers cannot be embedded in a browser (they stay WE's desktop job) — hidden from picker and rotation.
84
+ - Sandboxed web wallpapers get an opaque origin: wallpapers that need `localStorage`/IndexedDB persistence across loads won't persist. (Deliberate — same-origin wallpaper JS could otherwise drive the DSH API.)
85
+ - Steam discovery covers Windows (registry + libraryfolders.vdf + probes), macOS and Linux (standard Steam roots). Exotic layouts may not be found.
86
+ - The glass effect rides DSH design tokens; a shell redesign that renames tokens degrades the frosting gracefully (transparency stays, blur may drop).
87
+
88
+ ## Development
89
+
90
+ ```sh
91
+ npm install # prepare hook builds lib/client.js automatically
92
+ npm test # unit tests for the pure core (node:test)
93
+ npm run build # regenerate lib/client.js from src/client.js
94
+ npm run verify # boot the emitted bundle in a vm sandbox and assert behaviour
95
+ ```
96
+
97
+ `lib/core.js` and `lib/index.js` are plain ESM — no build step. `lib/client.js` is a **compiled artifact**; edit `src/client.js` and rebuild. `npm run prepublishOnly` runs the full gate: test → build → verify.
98
+
99
+ ## Releasing
100
+
101
+ Publishing runs in GitHub Actions (`.github/workflows/publish.yml`) through npm **Trusted Publishing (OIDC)** — no npm token is stored anywhere:
102
+
103
+ 1. Bump `version` in `package.json` and push.
104
+ 2. Create a GitHub Release whose tag is `v<version>` (must match `package.json`).
105
+ 3. The workflow runs the full gate, asserts tag ↔ version, and publishes with `--provenance`.
106
+
107
+ One-time npm setup: package → **Settings → Trusted Publisher → GitHub Actions** (repo `Weilv-D/wallpaper-engine-dsh`, workflow `publish.yml`). The very first version must be published manually once (see README.zh.md §发布 for details) before trusted publishing can be linked.
package/README.zh.md ADDED
@@ -0,0 +1,109 @@
1
+ # wallpaper-engine-dsh
2
+
3
+ [English](README.md) | [中文](README.zh.md)
4
+
5
+ 一个 DSH bundle:把本机 **Wallpaper Engine** 的 Video/Web 壁纸渲染成 **DSH web GUI(`dsh web`)的实时背景**——带交叉淡入过渡、iOS 风格液态玻璃效果、四个调节滑杆和用户自定义轮播列表。
6
+
7
+ 架构安全优先、测试兜底:
8
+
9
+ - **纯逻辑层**(`lib/core.js`)—— VDF 解析、安装发现、路径约束,全部被单元测试覆盖。
10
+ - **宿主层**(`lib/index.js`)—— Cordis 插件,通过同源 HTTP 提供清单与媒体。
11
+ - **浏览器层**(`src/client.js` → `lib/client.js`)—— 界面背后渲染 + 设置面板。
12
+ - **零模型 token** —— 不注册工具、不注入 prompt,纯 UI bundle。
13
+
14
+ ## 为什么只有 Video 和 Web 壁纸?
15
+
16
+ | WE 类型 | 渲染方 | 可移植到 DSH? |
17
+ |---|---|---|
18
+ | **Scene** | WE 自有 3D 引擎 | ❌ 原生 shader/模型 |
19
+ | **Video** | 普通媒体文件 | ✅ `<video>` 直接播放 |
20
+ | **Web** | HTML + 资源 | ✅ 沙箱 `<iframe>` 加载 |
21
+ | **Application** | 注入的外部窗口 | ❌ |
22
+
23
+ 与更简单的集成不同,**多文件 Web 壁纸在这里可以正常工作**:宿主会服务项目目录内打包的子资源(`js`/`css`/图片),并做严格的路径约束检查。
24
+
25
+ ## 架构
26
+
27
+ ```
28
+ ┌───────────────────────────── DSH web ─────────────────────────────┐
29
+ │ 浏览器半端(lib/client.js) │
30
+ │ settings.general.item 槽位 → 选择器 UI(网格、滑杆、列表) │
31
+ │ 应用框架之下的固定层 → <video> / 沙箱 iframe │
32
+ └──────────────▲────────────────────────────────────────────────────┘
33
+ │ 同源 HTTP
34
+ ┌──────────────┴────────────────────────────────────────────────────┐
35
+ │ 宿主半端(lib/index.js,Cordis 插件,inject: ['webServer']) │
36
+ │ GET /we-background/inventory[?refresh=1] JSON,缓存 30 秒 │
37
+ │ GET /we-background/media/<token>[/资源…] Range + 路径约束 │
38
+ │ GET /we-background/preview/<token> 预览图 │
39
+ └──────────────▲────────────────────────────────────────────────────┘
40
+ │ 纯函数
41
+ ┌──────────────┴────────────────────────────────────────────────────┐
42
+ │ 核心层(lib/core.js)—— 有测试 │
43
+ │ VDF 解析 · Steam 发现 · 项目校验 · 播放列表 │
44
+ │ Range 解析 · 路径约束 · MIME │
45
+ └───────────────────────────────────────────────────────────────────┘
46
+ ```
47
+
48
+ ## 安全模型
49
+
50
+ - **随机 token,不是路径编码。** 媒体 URL 携带每次构建清单时铸造的 72 位随机 token;知道文件系统路径没有任何用处。重建清单会重新铸造全部 token,旧 URL 即刻失效。
51
+ - **双重路径约束。** `project.json` 声明的文件必须解析在项目目录内;Web 壁纸的子资源同样必须解析在项目目录内(`..` 穿越返回 403)。
52
+ - **Web 壁纸沙箱化。** 第三方壁纸 JS 运行在 `sandbox="allow-scripts"`(不含 `allow-same-origin`)且 `referrerpolicy="no-referrer"` 的 iframe 中——不透明源,无法触碰 DSH 的存储、Cookie 或 API。
53
+ - **回环 + nosniff。** 全部响应同源,携带 `X-Content-Type-Options: nosniff`。
54
+ - 只有被枚举过的文件可被服务,不存在任意文件路由。
55
+
56
+ ## 安装
57
+
58
+ ```sh
59
+ dsh plugin --profile web add wallpaper-engine-dsh
60
+ ```
61
+
62
+ 或从源码检出安装:
63
+
64
+ ```sh
65
+ git clone https://github.com/Weilv-D/wallpaper-engine-dsh.git
66
+ dsh plugin --profile web add link:<克隆文件夹的绝对路径>
67
+ ```
68
+
69
+ 重启 `dsh web`,打开 **设置 → 通用 → 壁纸背景 (Wallpaper Engine)**。
70
+
71
+ ## 使用
72
+
73
+ 1. 从缩略图网格选择 Video/Web 壁纸——它会在界面背后淡入。Scene/Application 类型无法嵌入,已从网格隐藏。
74
+ 2. **暂停/播放** 控制视频壁纸;**关闭** 清除壁纸;**刷新** 强制宿主重新扫描(新订阅的创意工坊壁纸无需刷新页面即可出现)。
75
+ 3. 四个滑杆实时调节融合效果:**壁纸模糊**(模糊壁纸本体)、**暗化**(文字遮罩)、**边框**(分隔线对比度)、**玻璃**(面板磨砂)。
76
+ 4. **轮播列表**:可建任意多个列表,各自拥有壁纸集合、切换间隔(1–120 分钟)和顺序(顺序/随机);在目标列表上开启 **自动轮转**。首次运行会自动导入第一个可播放的 WE 播放列表;编辑器里的 **从 WE 播放列表导入** 可拉入任意其他列表。
77
+ 5. 选择持久化在 `localStorage`。可自由切换 DSH 明暗主题——所有表面都读设计令牌,自动跟随;壁纸太花时调高 **暗化/边框** 直到文字清晰。
78
+
79
+ 尊重系统 `prefers-reduced-motion`:开启减弱动态效果时,视频壁纸默认暂停。
80
+
81
+ ## 限制
82
+
83
+ - Scene 与 Application 壁纸无法嵌入浏览器(桌面渲染仍是 WE 的本职),已从选择器和轮播中隐藏。
84
+ - 沙箱中的 Web 壁纸使用不透明源:依赖 `localStorage`/IndexedDB 跨加载持久化的壁纸无法保存状态。(刻意为之——否则同源壁纸 JS 可以驱动 DSH API。)
85
+ - Steam 发现覆盖 Windows(注册表 + libraryfolders.vdf + 探测)、macOS 与 Linux(标准 Steam 目录)。非常规安装布局可能找不到。
86
+ - 玻璃效果依托 DSH 设计令牌;若外壳重构重命名令牌,效果会优雅降级(透明度保留,模糊可能消失)。
87
+
88
+ ## 开发
89
+
90
+ ```sh
91
+ npm install # prepare 钩子自动构建 lib/client.js
92
+ npm test # 纯核心层单元测试(node:test)
93
+ npm run build # 从 src/client.js 重新生成 lib/client.js
94
+ npm run verify # 在 vm 沙箱中启动产物并断言行为
95
+ ```
96
+
97
+ `lib/core.js` 与 `lib/index.js` 是纯 ESM,无构建步骤。`lib/client.js` 是**编译产物**:请编辑 `src/client.js` 后重新构建。`npm run prepublishOnly` 会跑完整门禁:test → build → verify。
98
+
99
+ ## 发布
100
+
101
+ 发布由 GitHub Actions(`.github/workflows/publish.yml`)通过 npm **Trusted Publishing(OIDC)**完成——任何地方都不存 npm token:
102
+
103
+ 1. 提升 `package.json` 的 `version` 并推送。
104
+ 2. 创建 tag 为 `v<版本号>` 的 GitHub Release(必须与 `package.json` 一致)。
105
+ 3. 工作流自动跑完整门禁、校验 tag ↔ 版本号,并带 `--provenance` 溯源发布。
106
+
107
+ 一次性配置(npm 网页端):包页面 → **Settings → Trusted Publisher → GitHub Actions**(仓库 `Weilv-D/wallpaper-engine-dsh`,workflow 填 `publish.yml`)。
108
+
109
+ **首发引导**:Trusted Publisher 需要包已存在才能绑定,所以**第一个版本需手动发一次**——在你自己的终端里运行 `npm publish`(新版 npm 会拉起浏览器做人体验证),或在 npm 网页端创建带 publish 权限的 granular token 存入仓库密钥 `NPM_TOKEN` 并取消 `publish.yml` 末尾 env 块的注释。首发成功后绑定 Trusted Publisher,之后一切全自动。
@@ -0,0 +1,18 @@
1
+ # wallpaper-engine-dsh bundle patch.
2
+ #
3
+ # Applied over the dsh-web-app layer. This bundle contributes ONE host row
4
+ # (the plugin that discovers the local Wallpaper Engine install and serves an
5
+ # inventory + media over same-origin HTTP) and relies on its `dsh.client`
6
+ # manifest (package.json) to load the browser half that renders the wallpaper
7
+ # behind the DSH GUI and contributes the settings UI.
8
+ #
9
+ # A patch replaces a targeted row's whole `config`, so only additive `insert`
10
+ # rows appear here — no shipped row is ever overridden.
11
+
12
+ - insert:
13
+ # Host half. Hard-depends on `webServer` (declared via `inject` in
14
+ # lib/index.js) so the Loader orders it after the HTTP server mounts;
15
+ # this bundle is web-only (its dsh.client declares platform "web"), so it
16
+ # is simply not added to headless/TUI profiles.
17
+ - id: we-background
18
+ name: 'wallpaper-engine-dsh'