dsh-web
zhu1090093659/dsh-webDeepSeek Harness(DSH)Web 插件聚合生态包 · 一切皆插件,创意工坊分发(dsh-market.com)
Liquid-glass Wallpaper Engine backdrop for the DeepSeek Harness Web GUI
A DSH Web GUI plugin that reads your local Wallpaper Engine library and renders the wallpaper as a full-viewport liquid-glass backdrop behind the harness: frosted diffusion, a specular sheen, a color vignette and a film-grain layer, all tunable live from a settings card.
你的壁纸是你自己的本地文件,插件只在本机读取和播放,不会上传、不会分发。 Workshop 内容版权归原作者所有。
431960) through the registry, every libraryfolders.vdf entry and the durable
appmanifest_431960.acf, then enumerates Workshop content, myprojects and
defaultprojects. Extra folders can be added manually.backdrop-filter: blur() saturate() frost,localStorage
and are restored on boot.206 so large 4K files seek and loop
without buffering the whole thing.| Type | Rendering | Notes |
|---|---|---|
video | <video> loop, muted, autoplay | The best liquid-glass result, and the sharpest: 4K sources decode natively. A still preview is painted underneath so the backdrop is never black while decoding. |
image | <img> | Direct render at the source resolution. |
web | sandboxed same-origin <iframe> (allow-scripts) | Web wallpapers run their own JS same-origin. Only install ones you trust. |
They were tried and removed. A scene's real content lives in a scene.pkg, and this
plugin cannot replay it — the only usable still is the project's own preview.jpg,
which in a real library is 1:1 and at most 1080×1080. Filling a 16:9 window with
that means a median 1.56× and a worst-case 11× upscale, so every scene looked soft
no matter how the glass settings were tuned.
The .pkg itself could not be read either. The index format was recovered
(u32 pathLen | path | u32 offset | u32 length, contiguous, no padding) and validates
against all 45 projects, but the payload bytes do not map to their declared filenames,
so a further layer of structure remains unknown. resourcecompiler64.exe,
resourceutil64.dll and FreeImage64.dll were all checked for a decoder and none
provided one.
Replaying scenes properly would need a WebGL player for layered 2D/3D scenes and WE material semantics — a project of its own. Rather than ship a type that always looks soft, the plugin skips scene projects entirely and says so here.
Windows, one command. Clone and run the installer — it finds your DSH home, detects which profile your GUI is running on, installs from GitHub with that profile's own pnpm, registers the bundle layer, and verifies the load tree:
git clone https://github.com/XINGRUYU33224/dsh-liquid-glass-wallpaper.git
cd dsh-liquid-glass-wallpaper
pwsh -File install.ps1
Then restart your GUI (for the desktop app: fully quit and reopen, not a page refresh). The section appears at 设置 → 液态玻璃壁纸.
Useful flags:
| Flag | Effect |
|---|---|
-Profile <name> | Target a specific profile instead of the detected one. |
-Local | Install from this checkout (link:) instead of GitHub — for development. |
-Ref <branch|tag|sha> | Install a specific git ref. |
-SkipVerify | Skip the post-install load-tree check. |
The installer is idempotent: re-running it is how you update.
dsh plugin forwards to pnpm, so a git spec works directly — and because the package
declares dsh.bundle, dsh adds it to the profile's bundle list automatically:
dsh plugin --profile <your-profile> add github:XINGRUYU33224/dsh-liquid-glass-wallpaper
Which profile is mine? It is the last path argument of the running host process. The
desktopprofile is refused by name from the CLI (managed exclusively by the Electron application), even though it is an ordinary cordis profile.install.ps1handles this by driving the app's bundled pnpm directly; manually, that is:cd "$DSH_HOME/profiles/desktop" "<app>/resources/runtime/bin/node/node.exe" \ "<app>/resources/runtime/pnpm/bin/pnpm.mjs" \ add github:XINGRUYU33224/dsh-liquid-glass-wallpaperthen add
"dsh-liquid-glass-wallpaper"todsh.profile.bundlesin that profile'spackage.json. Write it without a BOM — a BOM makes the boot loader fail withUnexpected token.
431960). Without it the section still
loads and explains that no library was found.libraryfolders.vdf). The backdrop
engine itself is platform-neutral; manual library folders are the fallback elsewhere.npm run verify # 85 checks: host, client, bundle, Range, lifecycle
python scripts/verify-final.py <gui-url> shots/ # live end-to-end in a real browser
python scripts/verify-coverage.py <gui-url> shots/ # media covers the viewport
The browser suites need Playwright (pip install playwright && playwright install chromium); the plugin itself needs nothing beyond Node's standard library.
The card writes to localStorage["liquid-glass-wallpaper/v1"]:
| Key | Default | Meaning |
|---|---|---|
enabled | true | Master switch for the whole backdrop layer. |
activeId | null | Selected wallpaper id (workshop:<id> / local:<id> / manual:<path>). |
blur | 28 | Frost radius, 0–60 px. |
saturation | 118 | Backdrop saturation, 60–220 %. |
tint | 12 | Dark tint over the glass, 0–60 %. |
vignette | 34 | Corner falloff, 0–80 %. |
grain | true | Film-grain overlay. |
parallax | true | Pointer-driven parallax. |
fit | cover | cover or contain. |
Manual library folders can also be passed as plugin config (manualDirs: string[]).
All routes are under /api/liquid-glass/, same-origin fenced
(cross-site Sec-Fetch-Site/Origin is rejected with 403; non-GET with 405).
| Route | Purpose |
|---|---|
GET /api/liquid-glass/inventory[?refresh=1] | Library inventory with tokenized media URLs. |
GET /api/liquid-glass/media/<token> | Range-streamed video/image. |
GET /api/liquid-glass/preview/<token> | Preview still. |
GET /api/liquid-glass/web/<token>/ | Web wallpaper document. |
Opaque tokens, never paths. Media is addressed by random 144-bit tokens minted per inventory response and resolved through an in-memory, capped map (4096 entries, oldest evicted). Two properties matter:
/inventory into the user's local
directory layout;A client-supplied path can never reach the filesystem in any case.
Accept-Ranges: bytes with correct 206/416 behaviour, verified across 17 cases:
open-ended (bytes=500-), suffix (bytes=-500 → the last 500 bytes, per RFC 9110),
clamped ends, 416 with Content-Range: bytes */N when unsatisfiable, and multi-range or
unknown-unit requests falling back to a full 200 rather than a misleading truncated
206. Video seeking depends on this.
lib/
index.js host entry: inject ["webServer"], registers the route family
we-library.js Steam/WE discovery + project.json enumeration (dependency-free)
routes.js opaque-token, same-origin-fenced, Range-capable HTTP routes
client.js BUILT bundle (window.__ModuleLoader__.load) — do not edit by hand
src/
client.js client source (plain ESM); build-client.mjs wraps it
scripts/
build-client.mjs wraps src/client.js into the loader bundle (+ --check)
verify.mjs runs every suite
test-build.mjs build integrity + proof the guards reject bad input
test-imports.mjs every module loads and exposes its contract
test-client.mjs bundle contract + apply() wiring + backdrop DOM
test-lifecycle.mjs boot safety with no <body>
test-host.mjs inventory + streaming + token opacity + fence, real library
test-range.mjs Range edge cases (suffix, clamp, 416, multi-range)
verify-*.py live Chromium checks (card, backdrop, glass levels, leaks)
The DSH client loader discovers client plugins as single self-registering bundles:
window.__ModuleLoader__.load({ id: 'dsh-liquid-glass-wallpaper', factory: (require) => { … } })
src/client.js stays readable ESM (export const name/inject, export function apply)
and scripts/build-client.mjs performs the envelope transform. Edit the source, then
run node scripts/build-client.mjs. Editing lib/client.js directly will be
overwritten.
The shell paints hardcoded rgb(255,255,255) / rgb(249,250,251) on its own
containers. Those are siblings of this layer, not ancestors, so no z-index on the
backdrop can win: at z-index: 0 it is covered, and at a negative z-index it falls
behind the document background.
So instead of fighting the paint order, the layer re-dresses the shell while it is active, in two geometry-scoped passes:
| Surface | Test | Treatment |
|---|---|---|
| Backdrop roots | covers ≥70% of the viewport | background-color: transparent |
| Chrome panels (sidebar rail, transcript column) | full height (≥80% of viewport), 120 px–75% wide | frosted glass: translucent surface + backdrop-filter |
Neither pass can touch a card, button, input or dialog: those are neither backdrop-sized
nor panel-shaped. Every element's prior inline background-color is recorded, and the
glass panels carry a single class, so teardown (disabling the layer or destroy())
restores the exact previous state. A MutationObserver re-applies after shell re-renders
(opening Settings, switching sessions), coalesced to one pass per animation frame.
This matters because a stock profile has no skin to make the shell transparent —
which is exactly the desktop case. The web profile only appeared to work because
maid-atelier was active and its skin CSS did this for us.
The media element covers the viewport exactly and lets object-fit do all aspect-ratio
handling. An earlier version also applied inset: -6% + width: 112% + scale(1.06):
three over-scales with different origins, which drifted the media off centre and left a
bare band — most visible with a 16:9 wallpaper in a wider window. Parallax is now a pure
translate over a single uniform scale(1.06), so every edge stays covered.
verify-coverage.py asserts this across three window shapes for both video and image
wallpapers.
inject must list every service you touch. Reading ctx.locale without
declaring it throws cannot get property "locale" without inject and takes the whole
plugin down at boot.settings.section needs the inject props provider. Registering without it
succeeds and returns a disposer, but the row never appears in the settings nav.!important. An active catalog skin ships L3 patches that
restyle generic selectors; a plain inline display:grid loses. All structural rules
are scoped to [data-lgw-card].dsh plugin --profile desktop … refuses (managed exclusively by the Electron application), but the profile
is an ordinary cordis profile: install with the app's own pnpm —
node <runtime>/pnpm/bin/pnpm.mjs install from $DSH_HOME/profiles/desktop.--dsw-alias-* resolve to nothing there,
so the card falls back to its literal colors; that is expected, not a bug.cordis.patch.yml entries can be missing plugins. The stock desktop patch
references ui-settings-account, which ships in @linxin666/dsh-web-all; without that
package the entry logs not found and is skipped. Harmless, pre-existing.link: installs. pnpm splits the argument and installs a
truncated path, so clone into a space-free directory./api/liquid-glass/* is fenced for a loopback CSRF threat model:
Sec-Fetch-Site must be same-origin or none when present (a cross-site page
cannot suppress it);Origin, when present, must be a loopback authority on the serving port,
checked against a server-side list. It is deliberately not compared to the
request's own Host header — that is attacker-controlled, so Origin: http://evil.test
with Host: evil.test (the DNS-rebinding case) is rejected with 403;allow-scripts) but run scripts same-origin —
treat a web wallpaper as code you are choosing to run.node scripts/verify.mjs runs 85 checks across 7 suites:
| Suite | Checks | Covers |
|---|---|---|
| build client bundle | — | generates lib/client.js |
| build integrity + guards | 18 | UTF-8 fidelity, CJK labels survive, --check staleness, guards reject no-exports / stray-export / duplicate-export |
| import contract | 4 | every module loads and exposes its API |
| client bundle contract | 20 | __ModuleLoader__ shape, apply() wiring, backdrop DOM, stylesheet injection |
| boot lifecycle safety | 4 | apply() survives a document with no <body> |
| host routes + library | 26 | real 119-wallpaper library, Range streaming, opaque non-reversible tokens, cross-site/rebound rejection |
| HTTP range edge cases | 17 | suffix, open-ended, clamp, 416, multi-range |
Live browser suites (verify-card.py, verify-final.py, verify-coverage.py,
verify-visible.py, test-leaks.py) additionally drive the real GUI: card render,
wallpaper selection, persisted restore, frost blur at 0→60 px, media coverage across
three window shapes, occlusion, and a 24-switch leak check.
The client half is built: edit src/client.js, then run npm run build. Do not edit
lib/client.js by hand — it is generated and npm run check fails when it is stale.
Before opening a PR, run npm run verify; all suites must pass.
Two traps worth knowing, both of which cost real debugging time here:
src/client.js are backtick template literals. A
backtick inside a comment or a CSS value silently ends the literal and produces a
syntax error far from the cause. The build script detects this and points at it.inject must list every client service you touch (slots, locale, …). Reading one
that is not declared throws at boot and takes the whole plugin down.No telemetry, no network egress, no analytics. The plugin reads your local Wallpaper Engine library and serves it to your own GUI over loopback. Nothing leaves the machine.
MIT — see NOTICE for the wallpaper-content boundary.
Wallpaper files are not part of this project and are never redistributed. Workshop content belongs to its authors; this plugin only reads what is already on your disk.