# dsh-web-ui

> dsh Skin Center for web: 15 built-in skins with instant switching, try-on preview, Wallpaper Engine bridging, and first-screen anti-flicker. The only skin loader and renderer in the plugin marketplace.

## Metadata

- Author: [@zhu1090093659](https://github.com/zhu1090093659)
- Repo: <https://github.com/zhu1090093659/dsh-web-ui.git>
- GitHub: [zhu1090093659/dsh-web-ui](https://github.com/zhu1090093659/dsh-web-ui)
- Stars: 5,128
- Language: TypeScript
- License: [Apache-2.0](https://spdx.org/licenses/Apache-2.0.html)
- Homepage: <https://gallery.dsh-market.com>
- Topics: `deepseek-harness`, `dsh`, `dsh-plugin`, `web-ui`
- Forks: 311
- Open Issues: 51
- Last push: 2026-08-20T14:37:38.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:zhu1090093659/dsh-web-ui/packages/skins/skin-center
```

## Wiki

## 一句话定位
dsh 网页端的皮肤中心，把皮肤列表、试穿、应用做进设置里的一级页面，并作为插件市场唯一的皮肤加载器与渲染器。它既能切换内置皮肤主题，也能让你把本地视频或 Wallpaper Engine 壁纸直接铺到聊天窗口后面。

## 核心能力
- 在设置里集中管理皮肤：内置 15 款皮肤（蓝色幻想、赛博夜城、初音未来、Minecraft、芙宁娜、Windows XP Luna 等）加上放进 `$DSH_HOME/skins/<id>/` 的用户皮肤同台展示，当前应用目标带「使用中」标记。
- 原子切换引擎：试穿与应用共用一套切换逻辑，切换是浏览器侧的事，不刷新页面、不改写 `cordis.patch.yml`、不重建启动图；最新请求永远胜出，失败或被淘汰的请求会完整保留上一套皮肤。
- 防闪屏首屏：host 半区在 `webServer.tapIndex` 注册一个适配模块，向每份 `index.html` 盖 `html[data-dsh-skin]` 并注入样式表链接，刷新后直接以当前皮肤启动；任何异常都 fail-closed 回退到官方原貌。
- 主页背景控制：背景遮罩滑杆（0–100%）与两枚按状态的高斯模糊滑杆（0–20 px）独立调节，0 时不渲染元素、不消耗 GPU；只对画了背景的皮肤生效，官方默认不受影响。
- Wallpaper Engine 桥接：自动定位 Steam 安装（仅 Windows），扫描项目与创意工坊内容；macOS / Linux 可添加手动文件夹（单项目目录、项目合集或纯 `.mp4`/`.webm` 文件夹），`~` 展开为主目录。视频用 `<video>` 渲染，web 壁纸用沙箱 `<iframe>`，场景壁纸经内置 WebGL 播放器实时回放。
- 旧版迁移兼容：升级到 v2 后首次启动会自动读取已退役的 `dsh-skin` 受管段，把当前皮肤 id 迁进新存储并清除旧行，迁移幂等且 fail-closed。

## 技术实现
- **语言**: TypeScript + React 18（jsx: react-jsx，target es2024）
- **关键依赖**: `@deepseek-ai/cordis`（插件运行时）、`@deepseek-ai/dsh-client-runtime` / `dsh-client-locale` / `dsh-client-ui-theme` / `dsh-client-ui-settings`（浏览器半区 SDK）、`lightningcss`（host 侧 CSS 安全管线，含 native binding）、`schemastery`（设置命名空间的 Schema 定义）
- **架构模式**: cordis bundle 双半区包，`src/index.ts` 是 host 半区（注册 `/api/skin-center/v2/*` 与 `/api/skin-center/we/*` 路由、`tapIndex` 适配器、一次性的 v1→v2 迁移桥），`src/client/index.ts` 是浏览器半区（注册一级 settings.section、运行 effect ledger、原子切换控制器、语义适配器、Wallpaper Engine 桥）。所有官方 DSH 耦合由皮肤中心吸收，皮肤作者只对 `contracts/` 契约负责。
- **入口文件**: `src/index.ts`（host apply）+ `src/client/index.ts`（browser apply）；皮肤作者契约为 `contracts/skin-manifest-v2.schema.json` + `contracts/hooks-api.d.ts` + `contracts/semantic-attrs-v1.md`；CSS 安全管线入口为 `src/core/css-safety/transform.ts`。

## 适用场景
觉得 dsh 网页端的浅色/深色官方原貌不够个性、想换一套配色或加点插画背景的人：内置 15 款皮肤覆盖二次元、像素风、商务、海港、XP 复古等常见偏好。如果你已经在用 Wallpaper Engine，把 Steam 库里的视频/网页/场景壁纸直接铺到聊天窗口后面，免去再开一层桌面壁纸。开发者想给团队定制一套专属皮肤，只需要按 `contracts/` 的 v2 契约丢一个目录到 `$DSH_HOME/skins/`，就能进卡片列表被使用。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| @deepseek-ai/dsh-* | ^0.1.0-rc.8 | host/client 半区都通过 SDK 注入服务；皮肤中心把对官方 DSH 的耦合吸收在契约之后 |
| React | ^18.2.0 | peerDependency，浏览器半区 `SkinCenter.tsx` 使用 React hooks |
| Node | ^22.19 \|\| >=24 | 仓库根 AGENTS.md 强制要求；package.json 未声明 engines，但 host 侧使用 `node:fs` / `node:child_process` / `node:os` |
| 平台 | 跨平台 | 皮肤切换、用户皮肤目录、手动壁纸目录都跨平台；Wallpaper Engine 自动发现仅支持 Windows（注册表 + `libraryfolders.vdf`），macOS/Linux 通过「手动文件夹」兜底 |
| 原生模块 | lightningcss | host 侧 CSS 安全管线；已显式 external 在 `tsdown.config.ts`，不出现在浏览器 bundle |

## 安装方式
```bash
dsh plugin --profile web add github:zhu1090093659/dsh-web-ui/packages/skins/skin-center
```

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| skin-background.enabled | boolean | 整张皮肤中心卡片总开关；关闭后停用试穿、应用、背景控制 | true |
| skin-background.backgroundOpacity | 0–100 | 主页背景遮罩强度（仅作用于画背景的皮肤） | 0 |
| skin-background.backgroundBlurEmpty | 0–20 px | 空对话状态下的高斯模糊半径 | 0 |
| skin-background.backgroundBlurContent | 0–20 px | 有对话内容时的高斯模糊半径 | 0 |
| skin-wallpaper.enabled | boolean | Wallpaper Engine 桥的总开关 | true |
| skin-wallpaper.weLibraryDirs | string[] | 手动壁纸库目录列表（每个是项目文件夹、项目合集或纯媒体文件夹） | [] |
| skin-wallpaper.selection | string | 当前应用的壁纸 id（空字符串 = 不应用） | "" |
| skin-wallpaper.mode | 'live' \| 'frame' | 实时播放或钉一张静态帧 | 'live' |
| skin-wallpaper.pauseOnHidden | boolean | 窗口隐藏时暂停视频，节省 GPU | true |
| skin-wallpaper.dim | 0–90 | 壁纸之上的压暗层百分比 | 25 |
| skin-wallpaper.wallpaperBlur | 0–60 px | 壁纸本身的高斯模糊半径 | 0 |
| skin-wallpaper.fit | 'cover' \| 'contain' \| 'fill' | 实时壁纸的填充方式 | 'cover' |
| $DSH_HOME / ~/.dsh | 路径 | DSH 主目录根，用于皮肤目录、当前选择状态、迁移桥 | ~/.dsh |
| $DSH_SKINS_HOME | 路径 | 覆盖用户皮肤目录根，开发与测试用 | 未设置 |
| $DSH_HOME / $DSH_SKIN_PROFILE / $DSH_PROFILE | 环境变量 | 决定迁移桥读写哪个 profile 的 `cordis.patch.yml` | 默认 profile=web |

## 常见问题

**Q: 安装完为什么设置里看不到皮肤中心？**

A: 皮肤中心以一级 settings.section 形式挂载在「设置」里，需要刷新页面并打开「设置」才能看到「皮肤中心」入口。卡片默认开启（`SkinBackgroundConfigSchema.enabled` 默认 `true`），打开后立即列出所有内置与用户皮肤。

**Q: 切换皮肤需要重启 DSH 吗？**

A: 不需要。皮肤切换完全在浏览器侧完成（`src/client/runtime/skin-controller.ts`），不刷新页面、不重写 `cordis.patch.yml`、不重建启动图。首屏由 `tapIndex` 适配器预先盖好 `html[data-dsh-skin]` 并注入样式表链接，刷新后直接以当前皮肤启动，没有官方原貌闪屏。

**Q: 用户自己做的皮肤怎么放进去？**

A: 把符合 v2 契约（`contracts/README.md`）的皮肤目录丢进 `$DSH_HOME/skins/<id>/`（`DSH_SKINS_HOME` 环境变量可改根目录），重开卡片或刷新页面就会出现在列表里。同 id 的用户皮肤会遮蔽内置皮肤；`skin.json` 校验失败会被 fail-closed 排除并在目录诊断里给出原因。

**Q: 试穿和应用有什么区别？**

A: 两者走同一个原子切换引擎（`src/client/runtime/skin-controller.ts`），区别只在是否落盘：试穿不持久化，「退出试穿」恢复到上次应用的状态；应用会调用 `POST /api/skin-center/v2/active`，把选择写到 `$DSH_HOME/skin-center-active.json`。

**Q: macOS / Linux 上能用 Wallpaper Engine 吗？**

A: Wallpaper Engine 自动发现仅支持 Windows（通过 Windows 注册表读 `SteamPath`，`src/we-library.ts:145`）。macOS 和 Linux 可在卡片「手动文件夹」行添加任意 `.mp4`/`.webm` 文件夹、单项目目录或项目合集目录作为媒体库，路径中的 `~` 会展开为主目录。

**Q: 自定义皮肤的 `hooks.mjs` 有什么风险？**

A: `hooks.mjs` 是受信代码逃逸舱（`contracts/README.md` 安全模型节），与本仓库同审同发，仅同源 serve。它拥有完整 DOM 与样式能力，导入或执行错误被 try/catch 隔离但不会拖垮静态皮肤——只在你信任该皮肤的作者时使用。

**Q: 怎么临时关掉皮肤中心？**

A: 卡片自带总开关（`SkinBackgroundConfigSchema.enabled`），关闭后会停用试穿、应用、背景控制，持久化在 `skin-background` 命名空间。壁纸部分另有独立的总开关（`SkinWallpaperConfigSchema.enabled`），持久化在 `skin-wallpaper` 命名空间。彻底卸载用 `dsh plugin --profile web remove @linxin666/dsh-client-ui-skin-center`。

**Q: 自定义皮肤会被上传或外发吗？**

A: 不会。所有 `/api/skin-center/*` 路由同源服务，写操作通过 Sec-Fetch-Site / Origin 围栏拦截跨站请求；皮肤 CSS 在服务前经白名单净化（`src/core/css-safety/transform.ts`）。壁纸导入仅复制到本机 harness-home 目录，从不上传或再分发，创意工坊内容归原作者所有。

## 上手难度
入门 — 装好后在设置里点开皮肤中心就能立即试用，一键应用即生效；如果只想用内置皮肤，零配置门槛。

## 已知问题与限制
- 插件运行时通过 inline style 写入的样式只能经 L3 `patches.css` 用 `!important` 覆盖（README.md:43）。
- 不输出语义属性（`data-dsh-surface` / `data-dsh-part` / `data-dsh-plugin`，枚举见 `contracts/semantic-attrs-v1.md`）且无稳定 DOM 锚点的插件只享受 L1 token 基础覆盖，无法获得完整换肤（README.md:44）。
- 皮肤的视频背景不受壁纸「隐藏时暂停」设置影响；该设置仅作用于 Wallpaper Engine 桥（README.md:45）。
- 语义适配器依赖的官方 shell 锚点（三列容器本体、侧栏导航 list slot、设置模态专属标识）目前缺少稳定选择器，作者已在 `contracts/semantic-attrs-v1.md` 列出对上游主题缝 PR 的四点诉求。
- `patches.css`（L3）按设计就是任意 CSS，与 `hooks.mjs` 一样被官方明确告知为高敏感、不是安全边界（README.md:38-39）。

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [dsh-web-ui](https://deepseek-plugin.org/plugins/zhu1090093659/dsh-web-ui/packages/skins/skin-center)
Wiki generated by AI (model: `MiniMax-M3`)
