# dsh-chat-wallpaper **English** · [中文](README.md) > A **fullscreen intro video + custom chat wallpaper** plugin for > [DeepSeek Harness](https://github.com/deepseek-ai). > > When your boot animation finishes, a video of your choosing takes over the > whole screen as a "second act". When it ends, it fades out and hands the > screen back to the chat — over a wallpaper you pick yourself. > Swapping the wallpaper means dropping an image into a folder. ``` boot animation (your dsh-startup-screen) ↓ cross-dissolve (no hard cut, and no flash) fullscreen intro video (covering the chat window) ↓ fade out chat window + your wallpaper ``` **Panels, cards and code blocks stay fully opaque the entire time** — however busy your wallpaper is, text stays readable. --- ## Contents - [Three layers, each doing one job](#three-layers-each-doing-one-job) - [How it does "background, not overlay"](#how-it-does-background-not-overlay) - [The cross-dissolve: the hardest part of this plugin](#the-cross-dissolve-the-hardest-part-of-this-plugin) - [Install](#install) - [Swap the video / the wallpaper](#swap-the-video--the-wallpaper) - [Settings panel](#settings-panel) - [Configuration](#configuration) - [Diagnostics and tools](#diagnostics-and-tools) - [Tests](#tests) - [Pitfalls we hit (all covered by regression tests)](#pitfalls-we-hit-all-covered-by-regression-tests) - [Credits and sources](#credits-and-sources) ⭐ - [License](#license) --- ## Three layers, each doing one job ``` z-index 2147482990 ┌─ #dsh-chat-wallpaper ─ intro video (placement="front") │ the "second act" after the boot animation: │ fullscreen, covering the chat window │ finishes → fades out → removed → chat takes over └─────────────────────────────────────────────── normal flow │ chat UI / sidebar / composer └─────────────────────────────────────────────── z-index -1 ┌─ #dsh-cw-banner ─ big text banner (optional) │ one line of huge text filling the window │ (real vector text, not a stretched image) └─────────────────────────────────────────────── z-index -2 ┌─ #dsh-cw-bg ─ chat wallpaper + veil (optional) │ an image of your choosing; the chat sits on top of it └─────────────────────────────────────────────── ``` **All three are independent:** | What you configure | Result | |---|---| | Video only | boot → fullscreen intro plays once → fades out → back to the DSH default background | | Wallpaper only | no intro; the chat simply sits on your image | | Banner only | no intro; one huge line of text sits behind the chat | | Video + wallpaper + banner | **the intro plays in front, fades out, revealing the chat over your wallpaper and the banner** | > The banner lives at `z-index:-1` (above the wallpaper, below the chat) — so it > **never covers the chat text**. And it is **real text, not an image**: vector, > so it stays sharp at any size. --- ## How it does "background, not overlay" There are exactly two tricks: ```css /* 1) Make the shell's own background variables transparent. Panels, cards and code blocks use *different* variables, which we never touch — so text always lands on an opaque surface. Zero readability cost. */ html body { --dsw-alias-bg-base: transparent; --dsw-specific-sidebar-fill: rgba(255, 255, 255, .78); /* translucent sidebar */ } /* 2) Put the wallpaper at z-index:-1 — below all normal flow content, and it never intercepts clicks. */ #dsh-cw-bg { position: fixed; inset: 0; z-index: -1; pointer-events: none; } ``` On top of that sits a **veil** (`linear-gradient`): a white veil for light themes, a dark veil for dark themes. > Theme detection **never guesses DSH's internal marker names**. The JS first > scans every attribute on `html`/`body` for `dark`, then falls back to > measuring the shell's background luminance, and finally writes the result as > **its own class** (`dsh-cw-dark` / `dsh-cw-light`). The CSS only ever reads > that class — so DSH can rename its internals and nothing breaks. --- ## The cross-dissolve: the hardest part of this plugin **The problem.** The boot animation ends with a fade-out. If the intro video also fades in, then at the seam **neither layer is opaque** — and the chat window flashes through in between. **The fix.** Make *their* fade-out *our* cross-dissolve: at the exact moment they begin to fade, we are already sitting underneath at full opacity. That requires knowing precisely when they begin. We read the `dsh-startup-screen` source; its ending happens in **two steps**: ```js /* dsh-startup-screen/lib/splash.js — the reveal */ root.classList.add('dsu-handoff') // ★ step 1: the root *starts* fading out await wait(780) // a full 780 ms finish() // step 2: only now does dsu-gone appear (+620 ms) ``` ```css /* dsh-startup-screen/lib/splash.css:791 */ #dsh-startup-root.dsu-handoff { transform: scale(1.035); filter: blur(5px); opacity: 0; /* ★ it is already fading here */ transition: opacity 780ms cubic-bezier(.4, 0, .2, 1), ...; } ``` **So the timeline is:** ``` t=0 dsu-handoff → starts fading out (780 ms, with a push-in and defocus) ↘ ← we are already opaque underneath t=780 dsu-gone → (long since fully transparent by now) t=1400 root element removed ``` > ⚠️ **Watching only `dsu-gone` is 780 ms too late** — during those 780 ms the > boot animation is already fading the chat window through, which is exactly > the "flash" a user sees. **That was a real bug we hit.** The signal classes are configurable (`bootLeaveClasses`) — swap them if you use a different boot animation plugin. **The honest trade-off.** A cross-dissolve means the video is already playing while the fade is in progress, so roughly the first 0.4–0.7 s of the intro is partly covered by the outgoing boot animation. That is the price of *never flashing* — we think it is worth it. The second seam (video → your wallpaper) needs no special handling: the video layer fades out *while* the wallpaper is revealed underneath, which is already a cross-dissolve. --- ## Install ```bash # 1) Install the plugin ( = wherever you cloned it) dsh plugin --profile add link: # 2) Restart DSH (see the last pitfalls: after editing lib/*.js you must # restart — a page refresh is not enough) ``` > There is **no build step**: `lib/index.js` (host half) and `lib/client.js` > (browser half) are hand-written files that load directly. --- ## Swap the video / the wallpaper **Video** — drop files here and the newest one wins (by mtime): ``` ~/.dsh/boot-animation/videos/ ``` **Wallpaper** — drop files here and the newest one is used automatically: ``` ~/.dsh/chat-wallpaper/ ``` Supported: `jpg / jpeg / png / webp / gif / avif / bmp`. **No image at all** → after the intro fades out you get the DSH default background. Both can also be pinned to an absolute path in the config (below). --- ## Settings panel **There is a「🖼 背景」button in the bottom-left corner** — it opens everything: ``` ┌─ Chat background ───────────────────────────┐ │ Current: my-wallpaper.jpg │ │ Drop folder: …/.dsh/chat-wallpaper │ │ │ │ [thumb][thumb][thumb] │ ← click to apply │ │ │ [No image] [Open image folder] │ ← the latter opens Explorer │ │ │ Veil strength (dark theme) 50% │ │ ▬▬▬▬▬●▬▬▬▬▬ │ ← applies live, no refresh │ │ │ Big text banner (one line, fills the window) │ │ [人类与AI的日常 ] │ ← type here to change it │ Banner strength 18% │ │ ▬▬▬●▬▬▬▬▬▬▬ │ │ │ │ Intro video: ● Fullscreen intro: play once → fade → chat │ │ ○ Persistent background: loop behind chat │ └─────────────────────────────────────────────┘ ``` **The panel is independent of the wallpaper layer** (its own root element, its own `