dsh-whale-particles-bg
Animated whale background for the DSH Web UI: a particle field sampled from the whale silhouette plus a dot-grid layer, both full-screen click-through canvases mounted in the shell.overlay seat; the particles gather on load, breathe when idle and are pushed away from the pointer, the grid dots swell
Install
dsh plugin --profile web add dsh-whale-particles-bg
Sandbox test results
| Stage | Result |
|---|---|
| 1 install | ✓ |
| 2 list | ✓ |
| 3 mount | ✓ |
| 4 boot | — |
Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).
README
dsh-whale-particles-bg
[English](#english) | [中文](#中文)
Animated whale particle background for the DeepSeek Harness (dsh) Web UI — the WHALE-silhouette particle field plus the official dot-grid layer, registered into the frame-wide shell.overlay seat.
Topics: dsh-plugin · deepseek-harness · cordis-plugin
English
Preview
7.5-second capture of the whale field assembling from its scattered shell, breathing at idle, and the pointer carving a channel that slowly closes again (src/preview.gif, animated GIF, 900×487, 12fps, 7.5s, 3.2 MB):
What it is
Layer · Content
Whale (z-index 1) · Particle field sampled from the WHALE SVG path (24×18 viewBox, 6× offscreen rasterization, sampled every 2px). Particles assemble from a scattered shell, breathe when idle, and are pushed aside by a decaying scalar field left along the pointer's path: slow drags stay smooth, fast sweeps cut a channel that closes again in about a second (see [How the pointer wake works](#how-the-pointer-wake-works)).
Dot grid (z-index 0) · 90px square lattice with neighbour lines and a 140px pointer attraction that swells the dots.
Both layers are fixed, full-viewport, click-through canvases. The theme is read from body[data-ds-dark-theme] on every frame (dark: rgb(215,232,255), light: rgb(50,82,135)), so light/dark follows with no subscription. Animation runs on requestAnimationFrame throttled to ~30fps, which also suspends it while the tab is hidden.
How the pointer wake works
The pointer never moves a particle directly. Three stages:
1. Field. A coarse scalar grid over the canvas (12 px cells) is multiplied by 0.94 every frame, and the pointer stamps a 300 px cubic kernel into it ((1 - r/300)^3). The field is therefore a "pheromone" map of the pointer's path over roughly the last second, not a single point.
2. Force. Each particle samples the field bilinearly and uses its negative gradient as the push direction and its value as the strength (power = min(1, F * (1 - 0.94)), with a 0.01 dead zone that drops sub-pixel pushes). Stamps are laid along the frame's movement (ceil(delta / 40) of them, at most 8) and scaled by a low-passed pointer speed, so a fast sweep cuts deeper than a slow drag.
3. Motion. The push is an acceleration, not a target position: v += ((target - offset)k - vc)dt, offset += vdt, with k/c = 120/14 while pushed and 2.5/2.2 on release, plus a 2000 px/s speed cap and a 150 px offset cap so a released particle cannot coast off the whale.
A still pointer settles into a steady blob whose normalised value reproduces the original radial falloff exactly (peak 2 unit strength ≈ 99 px at 1920×1080, about 12 px at half the radius, zero at the edge), so hovering feels unchanged. Measured overhead: +15 us per frame on a slow drag to +50 us on a fast sweep (0.04 %-0.15 % of a 30 fps frame at 1778 particles).
Install
Prerequisites: a dsh deployment with the dsh CLI on PATH (or a source checkout, where pnpm dsh … works).
dsh plugin --profile web add git+https://github.com/kviiinh/dsh-whale-particles-bg.git # other sources: # local path : dsh plugin --profile web add /abs/path/to/this/repo # npm : dsh plugin --profile web add dsh-whale-particles-bg (if published)
This package is a bundle: it declares dsh.bundle, so the install appends it to the profile's dsh.profile.bundles and the package's own cordis.patch.yml inserts the plugin row (id: whale-particles-bg). There is nothing to hand-edit, and dsh plugin --profile web remove dsh-whale-particles-bg removes both the dependency and the layer.
Restart the harness (dsh web). Settings → Plugins → Plugin list → Global plugins then lists whale-particles-bg as running, and the whale background appears behind the UI.
lib/is committed on purpose. The browser half must be awindow.__ModuleLoader__.load({ id, factory })bundle produced by dsh's own tsdown preset (packages/client/tsdown.client.ts), which only exists inside a dsh checkout. Shipping the built artifact is what makes a git-installed copy loadable without a build step, and it keeps installs free of anyprepare-script permission prompt. There is deliberately nopreparescript.
Rebuild after a dsh upgrade
scripts/build.sh /path/to/deepseek-harness # or: DSH_CHECKOUT=/path/to/deepseek-harness scripts/build.sh
The checkout is always named explicitly — the script assumes no personal directory layout. It stages the sources into <checkout>/packages/client/dsh-whale-particles-bg/, runs pnpm install → tsc -b → tsdown --env.DSH_BUILD_FACE client, copies lib/ back here, then removes the staged copy and restores pnpm-lock.yaml and pnpm-workspace.yaml from a snapshot taken up front — including when the build fails.
The last step is scripts/sanitize-artifacts.mjs, which scrubs machine-specific content out of the built artifacts and fails the build if any survives. It exists because the client preset writes virtual module ids containing the absolute source path (for example \0dsh-global-css:<virtual>/global.css.mjs) into a //#region comment inside lib/client.js — a string every browser loading the plugin downloads, which would leak the host user name, home layout and checkout location. Should a build emit a sourcemap, the scrub also rewrites its sources so they resolve from lib/ into this package instead of naming the build staging path.
Layout
Path · Purpose
src/client/index.tsx · Browser half: the two canvas components and the shell.overlay registration
src/client/whale-path.ts · The WHALE path constant
`src/client/gl
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::5,最后更新 2026-10-31