dsh-agent-whale-girl
An unofficial whale-girl (鲸鱼娘) companion for the DeepSeek Harness Web GUI.
She replaces the sidebar brand mark and floats over the page as a draggable,
collapsible mascot: her head follows your cursor, she reacts to pats and clicks,
she follows what the agent is doing, and her speech bubble reports the current
session's real token usage.
whale-girl
The character is community fan art, not an official DeepSeek asset — see
Source & attribution. Chinese docs: README.zh.md.
What she does
| Area | Behaviour |
|---|
Sidebar brand mark (sidebar.brand.mark) | Replaces the stock fish logo with a close-up of her face (avatar-face.png). Registered with priority: -1 so it wins the single-value slot. |
Floating companion (shell.overlay) | A 220×298 paper doll over the frame, with a token card above her and speech bubbles. Drag her anywhere inside the frame (position kept in localStorage['whale-girl:position']); double-click returns her to the bottom-right corner and forgets the position; when the window shrinks she is folded back into view. |
| Gaze | Her head turns towards the pointer (up to ±7°) and her tail counter-swings (±4.8°); both settle back to centre 0.22 s after the pointer leaves. The pivot is measured from the eyes/lashes in the art, not from the bounding box. |
| Pat | Press and hold ≥ 350 ms: a one-shot squash-and-return animation plus a dedicated line. She does not fold away. |
| Click and combo | A quick click (< 350 ms) folds or unfolds her, with an answering line; 3–4 fast clicks get a counted complaint; the 5th click fires a one-shot easter egg. |
| Mood | data-mood follows context occupancy: <50% calm, ≥50% tense, ≥85% crit. Each crossing drops a 💦 in her corner for 2.6 s. |
| Speech | Lines are triggered by state and filled with real numbers from DSH's own session projections (tokenUsage, contextPressure): a greeting on mount, an answer on click, live progress while the turn is producing output, a context warning at 80 %, and a "done" line 2.5 s after output stops. She never calls the network or the model. |
| Token card | Context occupancy (bar plus tokens / window) and output / input / cache-read counts for the current session — the same projections the composer's own indicator uses. Hidden when there is no session; it yields when the window is narrower than 900 px. |
| Three-layer puppet | Her body, head and tail are separate layers that are pixel-identical to the still illustration at rest, so they are invisible until she moves. |
Animations run only while she is being interacted with: exactly three one-shot
@keyframes (wg-pat / wg-egg / wg-emote), no infinite, no alternate,
no will-change; getAnimations() is empty when idle.
Install
The package declares a dsh.bundle patch, so installing it mounts both halves —
no profile editing, no manual copy:
dsh plugin --profile desktop add github:Turanbuturan/dsh-agent-whale-girl
--profile desktop is the DSH desktop app; use --profile web for a plain web
profile. A release tarball or a local checkout works the same way:
dsh plugin --profile desktop add ./dsh-agent-whale-girl
Reload the page afterwards. Host-side changes need a full app restart (Node's ESM
cache pins the module path), but this plugin's host half is empty — a page
refresh is enough.
Manual drop-in
Copy the folder into <profile>/plugins/ and add the row to the profile's
cordis.patch.yml:
- insert:
- id: whale-girl
name: "./plugins/dsh-agent-whale-girl/index.js"
The path resolves against the profile directory. Removing the insert row (and
refreshing) removes her; the folder may stay in place.
Uninstall
dsh plugin --profile desktop remove dsh-agent-whale-girl
If you used the manual drop-in instead, delete the insert row and refresh.
Build and verify
lib/client.js and lib/client.css are committed, so installing needs no build
step. To rebuild after changing the art or the skeleton:
node build.mjs # regenerates lib/client.js + lib/client.css from the PNGs and layers.json
node verify-bundle.cjs lib/client.js
verify-bundle.cjs is a structural and behavioural self-check (registrations,
injected CSS, layer geometry, gaze maths, click/pat/combo timing, mood values).
Use absolute paths — the script resolves the bundle relative to the working
directory.
Files
| File | Purpose |
|---|
package.json | Declares dsh.bundle.patch (installable bundle) and dsh.client.platform = "web" (browser half). |
index.js | Host half: an intentionally empty apply() so the loader can mount the package. |
cordis.patch.yml | The mount declaration read at install time. |
lib/client.js / lib/client.css | Build output: the client bundle that registers both slots, and the stylesheet it injects. |
build.mjs | Builds the two files above from the PNGs and layers.json (inlines the art, writes the skeleton geometry into CSS). |
layers.json | Puppet skeleton: crop boxes, rotation origins in the 414×560 art space, amplitudes, measured pivots. |
verify-bundle.cjs | Self-check. |
avatar-body.png / avatar-head.png / avatar-tail.png | The three puppet layers. |
avatar-face.png | 96×96 face crop used by the 24 px mark and the folded bubble. |
avatar.png | The full-body illustration before cutting. |
assets/ | Source art. |
Source & attribution
The code is MIT. The character art is community fan art and keeps the terms of
the repositories it came from:
See NOTICE for the file-by-file mapping. "DeepSeek" and the DeepSeek
whale logo belong to their respective owners; this plugin is an unofficial
community project.
License
MIT — see LICENSE.