# dsh-signal-field v0.4.1 [![中文](https://img.shields.io/badge/简体中文-red?style=for-the-badge)](README.md) [![EN](https://img.shields.io/badge/English-blue?style=for-the-badge)](README_en.md) ![version](https://img.shields.io/badge/version-v0.4.1-blue?style=for-the-badge) ![license](https://img.shields.io/badge/license-MIT-green?style=for-the-badge) ![platform](https://img.shields.io/badge/platform-DSH%20Web%20%2F%20Desktop-informational?style=for-the-badge) An animated-UI plugin for DeepSeek Harness (DSH) on Web and desktop: it brings a dithered signal-field backdrop, a blueprint headline type effect, frosted-glass composer surfaces and an ASCII whale animation to the new-session page and chat sessions, and extends the same backdrop and glass to the HUD panel — each toggleable under Settings → UI Motion. > [!TIP] > The whale animation in this plugin is based on **[dsh-ascii-whales](https://github.com/Chael-Chael/dsh-ascii-whales)** — thanks to its author **Chael-Chael** for open-sourcing it. Full upstream attribution, licences and the list of adaptations are in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md). > [!NOTE] > The scope is exactly two kinds of page: the **new session** page and the **chat session** page. The plugin manager, the scheduled-task page and any other panel page keep the stock DSH look: since v0.1.1 the plugin creates no layer, writes no scope attribute and injects nothing there, and it destroys an existing layer and canvas when you navigate away. > > Since v0.2.0 it also covers the chat page **composer strip** and the `dsh-awesome-hud` **HUD panel glass** (the right sidebar backdrop was removed in v0.2.4). --- ## Demo **Light Mode** ![Light theme animation: the dithered signal-field backdrop, the "DEEPSEEK HARNESS" blueprint headline and the frosted composer](docs/light_mode_preview.gif) **Dark Mode** ![Dark theme animation: the same motion rendered with the dark palette](docs/dark_mode_preview.gif) --- ## What you get | Area | Signal field | ASCII whales | Blueprint headline | Frosted glass | | --- | --- | --- | --- | --- | | New session (`data-content-phase="hero"`) | ✓ | ✓ optional | ✓ "DEEPSEEK HARNESS" | ✓ composer | | Chat session | ✓ (composer strip included) | — | — | ✓ composer | | HUD panel (`dsh-awesome-hud`, both pages) | ✓ shows through, blurred | — | — | ✓ panel | - The field spans the content area but deliberately does **not** repaint the left navigation column: DSH keeps its own fill, so colour stacking with plugins such as `dsh-better-sidebar` stays predictable. - Light and dark palettes follow the DSH theme automatically: light `#e7e9f0 / #b6bfd8 / cursor erase`, dark `#070a12 / #3a4a7a / cursor reveal`. - Backdrop interaction: drifting noise wave + pointer-trail erase/reveal + click ripple. - **ASCII whales** (migrated from `dsh-ascii-whales` in v0.4.0): a layer of living characters on the new-session page — whales cruise with beating tails, small fish school, chase and flee, and wakes diffuse, all drawn from monospace glyphs. It appears **only on the new-session page** and **stacks** with the signal field (field underneath, whales on top; the whale canvas is transparent, so it reads as whales swimming in front of a dithered sky). The two switches are independent. - Headline interaction: entry reveal, glyphs turn into dashed vector outlines near the pointer, with an optional selection frame, draggable letter blocks and drifting specks. - The headline shares the hero row with the whale mark, "探索未至之境" and the preview badge, and the whole row is centred; letter blocks can be dragged anywhere on the page without being clipped, and spring back on release. - Both the composer and the HUD panel hang their blur on the host's `::before`, never on the host element itself: `backdrop-filter` turns that element into the containing block for its `position:fixed` descendants, so putting it on the host makes the popups inside that subtree resolve against the host and get clipped by its `overflow:hidden`. In v0.2.0 this trapped `dsh-awesome-hud`'s own git graph and other dialogs inside the 300px panel; v0.2.1 fixes it and pins the rule with automated assertions. - Messages scrolling under the composer no longer land on the status row: since v0.2.5 the **composer seat grows its own `::before` backing** — a `backdrop-filter` blur plus a bottom-edge tint at `z-index:-1`, so it always paints *below* the card and the status-row text and can never blur any UI. The v0.2.2 colour band and the v0.2.3 `::after` blur both painted above the seat's children; v0.2.4 switched to a `mask` but put it on the scroll container, and the seat is a child of it — the whole seat faded out (the status-row text vanished), and the backdrop root created by the mask stopped the composer card from sampling the signal field, degrading the glass to a transparent card with visible noise. Both are fixed in v0.2.5. v0.2.7 shrinks that backing to **only the info line below the composer** (height measured at runtime as "card bottom → seat bottom" and exposed as `--mui-seat-band-h`): with the v0.2.5 full-seat layer, `backdrop-filter` averaged the fine dither into a smooth pale grey, so the whole composer strip looked like it had no animated backdrop at all and the card blurred an already-smoothed field. The rest of the seat is transparent again, so the backdrop shows all the way into the composer area. - The HUD panel floats over the right-hand side of the content area, where there was no signal field, so its glass could only blur flat white and looked opaque. Since v0.2.3 a matching field layer is placed behind the panel, and v0.2.5 fixes two things about it: the layer is now inserted into the panel's own layer (DSH's `shell.overlay`) immediately before the panel (it used to hang on `body` with `z-index:-1`, where the shell's opaque background covered it completely), and its box now runs to the bottom-right corner of the viewport instead of "panel rect + 24px" — the panel's height follows its content, so a short panel used to leave a plain white block underneath. v0.2.6 fixes two remaining artefacts: the layer used to be laid out as "panel rect + 24px", so it started above the conversation area and the right column showed a **hard-edged rectangular patch**; that 24px overhang also landed on top of the conversation area, stacking two signal fields into a **dirty vertical band** (light cell 233 → 243, dark cell 233 → 218). The box is now aligned to the *content band* itself (left = content-area right edge, top = content-area top edge, right/bottom = viewport edges) and carries its own opaque same-source base (`--mui-surface-base`), so any overlap is covered instead of composited twice. - Since v0.2.4 the **right sidebar is out of scope**: its animated backdrop is removed entirely (layer, observers, CSS and the setting), so the sidebar keeps the stock DSH look; the switch count drops from 11 to 10. The vertical strip the HUD panel itself occupies is still covered by its backdrop layer (otherwise the panel has nothing to blur and a white block appears beneath it); that layer disappears with the panel. - **HUD backing field: interaction and timing** (v0.3.1): it shares the same "Backdrop pointer interaction" switch as the content area — sweeping across the strip behind the panel gives the same cursor erase (light theme) / light-up (dark theme) trail, and clicking gives the same ripple (clipped by the narrow container, which is expected). It does **not** play the entry reveal at all, so it renders at full strength the moment you open a chat session; the content area keeps its original 1.8 s reveal and 0.5 s fade. --- ## Settings page Settings → UI Motion (a `settings.section` entry with id `signal-field`, order 58). Since v0.4.0 the page is **three cards** with no divider between them (the card border does that job); the **Effects** card is then split into five groups by a divider plus a small heading. | Card | Content | | --- | --- | | **Master** | Enable all effects (switch, plus a one-line hint) | | **Pages** | New session page / Chat session page (each with a one-line hint) | | **Effects** | see the five groups below | The five groups inside the **Effects** card, top to bottom: | Group | Rows | Controls | | --- | --- | --- | | **Backdrop** | Backdrop default motion / Backdrop pointer interaction / Backdrop intensity (**30%**) / Backdrop animation speed (**1×**) | switch / switch / slider / slider | | **Headline** | Headline default motion / Headline pointer interaction / Headline animation speed (**1×**) | switch / switch / slider | | **Whales** | Whale animation / Whale species (humpback / orca) / 11 number fields (two-column number inputs) | switch / segmented / number | | **Composer** | Composer frosted glass | switch | | **Frame rate** | Animation redraw cap (**30 fps**, shared by the field and the whales) | slider | - **1 master switch + 8 switches + 4 sliders + 1 segmented control + 11 number inputs**: the master card is global, the pages card chooses where the effects run, the effects card tunes them. - **Row order changed in v0.4.0**: it used to be headline → backdrop → composer → frame rate → whales; it now follows the five groups above (backdrop → headline → whales → composer → frame rate). - Turning a page off disables everything on that page (signal field, whales, blueprint headline, composer glass) and returns it to the stock DSH look; with "New session page" off neither the headline nor the whales appear. - Whales are subordinate to the page switches: the master switch, "New session page" and "Whale animation" must **all** be on before anything is rendered. - **The HUD panel has no switch of its own**: it follows the "Chat session page" switch, so turning the chat page off also reverts the panel; it is *not* controlled by "Composer frosted glass" (that switch only governs the composer card). - The blur radius is fixed at 14px (the old "Glass blur" slider was removed in v0.2.9) and shared by the composer and the HUD panel. - **Animation redraw cap** (new in v0.2.11; 15–60 fps, step 5, **30** by default) limits how many times per second the **signal field and the whales** redraw in order to save power (since v0.4.0 the whales obey it too, which is why the row was renamed from "Redraw frame-rate cap"). It is **independent of image quality**: grain size, glass strength, colours and canvas size are unchanged — only the draw rate moves. While the window is unfocused (another app in front) it drops to 8 fps and returns to the configured value the moment the window regains focus; while the pointer moves or clicks on the field it is temporarily uncapped for about 1.2 s so trails never show steps. Default 30 fps halves redraws on a 60 Hz display and quarters them on a 120 Hz one. The whales advance on **wall-clock time**, so a lower cap only draws them less often — it never makes them swim slower. - **Headline animation speed** (new in v0.3.0; 0.25×–2×, step 0.25, **1×** by default) sets how fast the sweep runner, the reveal lens and the hover-to-outline transition run; **1× is the original feel**. It applies live while dragging: the headline never flickers, never replays, and its glyph textures are never re-baked. Pointer following and drag spring-back deliberately ignore it, otherwise the feel would degrade as you slow it down. - **Backdrop animation speed** (new in v0.3.0; 0.25×–2×, step 0.25, **1×** by default) is a single multiplier for the whole backdrop: wave drift, ripple wobble and ripple spread all scale together, and **ripples live correspondingly shorter** (1.6s ÷ factor) — that follows from using one unified multiplier. The HUD panel's backing field follows the same factor. It is fully independent of the redraw cap: high speed with a low cap looks steppy, and that trade-off is yours to make. - The headline only exists on the new session page, so the three rows in the **Headline** group are effectively hero-only. - Scope: the effects run only on the new session and chat pages; the plugin manager, the automation page and any other panel page keep the stock DSH look. That rule is expressed by the plugin's behaviour and by this document — since v0.2.10 the settings page **no longer** shows a static note about it. - Stored in browser `localStorage` under `dsh-signal-field:v1` and restored after a restart; "Restore defaults" clears it. The old per-page × per-effect structure is mapped semantically onto the new model (an old default intensity of 55% follows the new 30% default; hand-tuned values are kept). - Turning the master switch off destroys the canvas, stops animation and removes every injected scope attribute, restoring the stock DSH look. ### Whale animation (v0.4.0, migrated from `dsh-ascii-whales`) Only the animation itself and the rows below were migrated. Ocean colour, eye background, colourful shimmer, the glass switch, font source and local font scanning are **not** part of this plugin and stay fixed at their migration-time values (DeepSeek blue `#4d6bfe`, eye following the main colour, colourful shimmer off). The character style is **fixed to ASCII** — there is no graphic-rune / Hanzi / Kanji switch, and only a single monospace subset is embedded. | Row | Default | Range / step | Notes | | --- | --- | --- | --- | | Whale animation | on | — | the layer's own switch; see the three gates above | | Whale species | humpback | humpback / orca | orca is slightly smaller with white markings | | Whale count | **1** | 1–20 / 1 | with more than one, sizes step down by 1 / 0.7 / 0.84 / 0.77 / 0.65 / 0.9 | | Whale swim speed | **0.5** | 0.1–10 / 0.05 | clock multiplier | | Whale body swing | **0.75** | 0–3 / 0.05 | spine wave amplitude | | Whale turn agility | **0.8** | 0.1–3 / 0.05 | steering response | | Whale tail frequency | **0.85** | 0.1–5 / 0.05 | tail-beat rate | | Whale size | **1.5** | 0.1–10 / 0.1 | base size per whale | | Whale opacity | **0.5** | 0–1 / 0.05 | whole-layer opacity | | Whale cell size (x) | **0.5** | 0.1–10 / 0.05 | smaller means finer cells, more glyphs and more cost | | Whale grid opacity | **0.1** | 0–1 / 0.01 | the grid behind the glyphs; 0 hides it | | Whale fish count | **188** | 0–1000 / 1 | school size; 0 removes the fish | | Whale wake intensity | **1** | 0–10 / 0.1 | the fading trail left behind | - The defaults equal the values actually in use in `dsh-ascii-whales` at migration time, **not** its factory defaults (factory: 3 whales, 1.2× size, 170 fish, and so on). - Changing whale species / count / size / cell size / fish count **rebuilds the whole ocean** (instances and sizes are bound at construction time); the other parameters update in place and never replay while you drag. - Whale pointer interaction **follows the "Backdrop pointer interaction" switch**: with it on, the pointer scatters and attracts the fish and a click splashes; with it off no pointer listener is registered at all. - Whales **ignore** the system "reduce motion" preference and always run at the configured frame rate (a deliberate choice, unlike the headline and the field). --- ## Accessibility and degradation - With `prefers-reduced-motion: reduce`, the first install seeds "idle motion" and "pointer interaction" as off; the settings page explains this and lets you turn them back on. **Whales are the exception**: they never read that preference and always run at the configured frame rate — turn "Whale animation" off if you do not want them. - Without WebGL2, or after context loss, the backdrop degrades to a soft radial gradient (`[data-mui-field][data-fallback]`): no dithering, no interaction, nothing else breaks. - Without Canvas2D the whales **degrade silently**: the layer is still mounted but no engine is created — no error, no impact on the field or the headline (the layer carries `data-whale-fallback` for diagnosis). - If no headline mount point exists, the settings page says so and every other effect keeps working. --- ## Install / upgrade / remove ```text # install (target is the absolute path of the plugin package directory) plugin_manager install_bundle target=/dsh-signal-field # upgrade after editing sources node scripts/build.mjs # regenerate client.js # the profile links this directory: a page refresh loads the new bundle; # re-run install_bundle only when package.json / exports change. # If a refresh is not enough: toggle the plugin off/on, or restart DeepSeek Harness. # remove plugin_manager remove_bundle target=dsh-signal-field ``` --- ## Known limits and version coupling The plugin only reads the host and never mutates DSH state, but it does depend on a few DOM contracts. If the effects disappear after a DSH upgrade, check this table: | Purpose | Anchor | Behaviour when missing | | --- | --- | --- | | Page detection | presence of `[data-conversation-content]` | the whole page is out of scope: no layer, no attributes, no headline | | New session vs chat | `[data-conversation-content][data-content-phase]` | without a `hero` phase it is treated as chat and no headline is mounted | | Backdrop layer host | the conversation surface `[data-conversation-content]` itself | no backdrop; everything else works | | Whale layer | same host; the `[data-mui-whale]` layer is appended as the last child of the surface | no whales; everything else works | | Whale embedded font | the `Whales Mono` `@font-face` subset | falls back to a system monospace face: outlines drift but animation keeps running | | Whale rendering | Canvas2D (`getContext("2d")`) | silent degradation, no whales drawn | | Headline mount point | the largest-font leaf text block inside `[data-content-phase="hero"]` | no headline; the settings page reports it | | Headline insertion point | climb to the hero row whose parent is a column flex container, then insert before the text group | no headline when the row cannot be located | | Composer card | `[data-composer-card]` | no frosted glass | | Composer strip | `[data-composer-seat]` and its use of `--dsw-alias-bg-base` | the opaque strip returns and the backdrop breaks there | | Composer strip | `blur + bottom tint` on `[data-composer-seat]::before` (`z-index:-1`, chat phase only) | messages no longer scroll over the status row, the card still blurs the real field, and the status-row text stays untouched | | HUD panel | `.hud-panel` from `dsh-awesome-hud` (the blur lives on `.hud-panel::before` only) | no frosted glass (harmless when that plugin is absent) | | Dark theme | `body[data-ds-dark-theme]` | light palette only | | Palette tokens | `--dsw-alias-label-primary` / `--dsw-alias-brand-primary` | built-in neutral fallback colours | `[data-conversation-content]` is the plugin's only page-detection source and therefore its single point of failure (since v0.1.1 it no longer reads `ctx.layout`). --- ## Upgrade regression checklist 1. New session: the whale mark, "DEEPSEEK HARNESS", "探索未至之境" and the preview badge sit on one centred row. 2. New session: the area **below** the composer is covered by the backdrop. 3. Chat session: the composer strip is no longer white, the backdrop runs to the bottom of the page, and the composer card reads as the same frosted glass as on the new-session page (v0.2.5 fixed the "transparent card" caused by the mask breaking backdrop-filter). 4. Chat session, scrolling the transcript: message text **no longer overlaps the status row**, and the status-row text below the composer (the workspace and model lines) is **fully visible, opaque and crisp** (the key v0.2.5 regression). 5. Expanding a question card / plan list: nothing covers or blurs the area beneath the overlay (the key v0.2.4 regression). 6. Right sidebar: back to the stock DSH look, with **no** signal field. 7. HUD panel: it reads as frosted glass and the signal field shows through blurred; the strip of the right-hand column **below** the panel is backdrop rather than a plain white block (the key v0.2.5 regression); there is **no** hard-edged patch and **no** denser band around the panel (the key v0.2.6 regression); turning "HUD panel frosted glass" off restores the original look and removes that backdrop layer. 8. The HUD's own popups (git graph, branch/commit/confirm dialogs, file and branch menus, commit hover tip) are still centred in or anchored to the viewport — **not trapped inside the panel and not clipped**. 9. Drag the headline to the page corners and over the composer: it stays visible and springs back on release. 10. Regression: backdrops/headline/composer glass on both pages, light/dark switching, every switch and slider applying immediately and surviving a refresh; the plugin manager and scheduled-task page still keep the stock DSH look. 11. With the master switch off: no `data-mui*` attribute remains on `document.documentElement`, and `