Install
Inside DeepSeek Harness, with dsh-market
dsh plugin --profile web add dshmarket
Or from the command line
dsh plugin --profile web add deepseek-harness-background
Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.
README
A custom background image plugin for the DeepSeek Harness Web GUI (dsh web): upload a local picture, or paste an image URL, and render it behind the whole app surface with adjustable opacity, readability scrim, panel transparency and frosted-glass blur — everything live-previewed inside the settings panel and committed automatically on release.
The look (fixed wallpaper layer + theme-aware scrim + translucent glass panels driven by --dsw-* design tokens) is modeled on the community dsh-wallpaper-engine implementation.
Screenshots
| Home | |
| Conversation | |
| Settings |
Features
- Local upload — pick a JPG / PNG / WebP / GIF from your computer; the plugin stores it under the harness home and serves it over a same-origin route (admitted only when the declared MIME, detected signature and extension all agree).
- Paste a URL — drop an
http(s)image link and press Enter. - In-panel live preview — a preview surface at the top of the row renders the image + scrim + a frosted glass bubble; dragging any slider repaints it instantly.
- Stepped sliders — ratio controls snap in 5% steps, blur radii in 1/2px steps; dragging only repaints, release commits (one write per gesture, no jank).
- Five controls — wallpaper opacity, readability scrim, panel opacity, frosted-glass blur, and wallpaper blur.
- Fit modes —
cover(fill, crop) orcontain(whole image). - Theme-aware scrim — the light theme uses a white veil (lifts the art so dark text keeps contrast); the dark theme automatically switches to a black veil (dims the art so light text keeps contrast).
- Frosted glass — while a background is active, every opaque surface turns into translucent glass over the wallpaper (specular sheen +
backdrop-filter): the composer card and message bubbles, code blocks / terminal / diff / tool cards and inline code, menus and popovers, dialogs and the settings panel, dock cards, and the chrome buttons (new session, plus, send, toasts…). The blur radius is driven by the glass-blur slider;panelOpacityat 100% restores the official opaque surfaces everywhere. Semantic alerts, masks and the boot screen keep their official look. - Conversation timeline — a DeepSeek-web-style scroll-navigation rail at the right edge of long conversations: one tick per user message on a frosted capsule; hovering expands it into a frosted panel listing every question (active one highlighted in brand blue); clicking jumps the chat to that message. Collapsed and expanded share one identical height (no jump), clipped edges get the official 32px fade veils, and both states ride the same panel-opacity/blur knobs as every other surface. Toggle it off with the timeline switch in the row. If the third-party dsh-chat-timeline plugin is also installed, this rail steps aside instead of doubling it.
- Persisted in the official settings document (
$DSH_HOME/settings.yaml), waits out restarts. - Clean teardown — disabling, clearing or uninstalling restores the original background exactly; the plugin only ever removes what it wrote.
Install
The plugin is a standard out-of-tree dsh bundle, published on npm:
dsh plugin --profile web add deepseek-harness-background
From a local checkout (development):
dsh plugin --profile web add /path/to/deepseek-harness-background
From a source checkout:
pnpm dsh plugin --profile web add /path/to/deepseek-harness-background
Or from git:
dsh plugin --profile web add github:<you>/deepseek-harness-background#<commit>
Restart to load it:
dsh --profile web
Usage
- Start the Web UI (
dsh --profile web) and open it in a browser. - Open Settings (bottom-left) → General → the Custom Background row (in the same area as the Appearance row).
- Upload an image or paste a URL — the background applies immediately and the preview surface above updates in sync.
- Tune the controls — sliders snap in steps and commit on release:
| Control | Meaning |
|---|---|
| 不透明度 / Opacity | 0..100% image opacity (5% steps); lowering it fades the wallpaper toward the surface. |
| 遮罩 / Scrim | 0..95% readability veil over the image (5% steps); white in light mode, black in dark mode. |
| 面板不透明度 / Panel opacity | 0..100% surface transparency (5% steps); at 100% the official panels stay opaque (no glass). |
| 毛玻璃模糊 / Glass blur | 0..40px backdrop-filter blur on the translucent surfaces (1px steps). |
| 壁纸模糊 / Wallpaper blur | 0..60px blur of the wallpaper image itself (2px steps). |
| 填充方式 / Fit | cover or contain. |
| 会话时间线 / Timeline | on/off switch for the conversation timeline rail (default on). |
- 清除背景 removes the background and restores the stock look.
How it works
- The settings row lives in the official General settings section (
settings.general.itemslot), next to the Appearance row. Its chrome uses only--dsw-alias-*design tokens (buttons / pills / segmented control / slider track match the official shell); sliders are nativeinput[type=range]with 5% / 1–2px steps and release-commit. - The plugin's own host routes (
/api/bg-wallpaper/*:settings,upload,image/<id>) read/write the section and serve uploads with same-origin + size caps + MIME/signature checks + a path-escape fence. A custom route family is used because the api-proxy settings allowlist does not expose third-party namespaces over the settings RPC. - The background is drawn as a fixed
z-index:-2wallpaper layer plus az-index:-1scrim onbody, toggled by thedata-dsh-bgattribute; the scrim switches white/black bydata-ds-dark-themein the injected stylesheet; the frosted-glass effect overrides the shell's surface design tokens. - The timeline rail is registered into the
conversation.input.dockslot (per-session lifecycle) and portals tobody. Its data comes from the runtime sessions service (loaded chat nodes, then a bounded loadOlder loop); its fills reuse the same overridden--dsw-*tokens as every other surface, so the glass-off state returns the official panel look. - Uploads live under
$DSH_HOME/deepseek-harness-background/(content-addressed ids). Switching to a new image or clearing the background deletes the superseded upload file, so the directory does not accumulate dead images in normal use. (An upload that is never saved into the section — e.g. the tab closes right after an upload — can leave one orphaned file behind.) Disable / uninstall leaves nothing behind.
Development
pnpm install # first time; runs prepare (build)
pnpm run typecheck # tsc
pnpm test # vitest contract tests
pnpm run build # tsdown: lib/index.js (host) + lib/client.js (browser bundle)
deepseek-harness-background/ # the plugin repo (package name stays the npm-style id)
├── package.json # dsh.bundle.patch + dsh.client.inject declarations
├── cordis.patch.yml # inserts the deepseek-harness-background row into the web roster
├── tsdown.config.ts # official clientBundle preset
├── src/
│ ├── index.ts # host half: ui-background namespace + API routes
│ ├── routes.ts # /api/bg-wallpaper/{settings,upload,image/<id>}
│ ├── schema.ts # host-side schemastery schema
│ ├── settings.ts # constants/types shared with the client
│ ├── harness-home.ts # $DSH_HOME / ~/.dsh resolution
│ └── client/
│ ├── index.ts # painter lifecycle + settings row registration
│ ├── backdrop.ts # fixed wallpaper layer + scrim + glass surface + preview vars
│ ├── background-css.ts # injected stylesheet (layers, glass, light/dark scrim, variables)
│ ├── timeline.tsx # conversation timeline rail (ScrollNav port on the glass system)
│ ├── timeline-css.ts # timeline stylesheet (dsbt- prefixed, official metrics)
│ ├── SettingsRow.tsx # the General-settings row (preview surface + stepped sliders)
│ ├── SettingsRow.module.css # row styles (official tokens)
│ ├── settings-client.ts# fetch transport (read/write/upload)
│ └── locales.ts # zh/en copy
└── tests/ # schema, routes, apply (painter), settings-row contracts
License
MIT