dsh-ui-pet
Manifest validA canvas sprite-sheet pet plugin for the DeepSeek Harness web GUI. A dsh bundle + client plugin that renders a pointer-following mascot in the shell.overlay layer. MIT licensed.
@nkj/dsh-ui-pet
A canvas chibi cat pet for the DeepSeek Harness web GUI. It is anchored to the bottom-right viewport corner (the body does not chase the pointer — the head turns toward its gaze and the pupils track the pointer) and is styled as a background decoration in the shell.overlay layer: position:fixed (no layout impact), fully click-through (pointer-events:none), a low z-index (below other overlay entries and dialogs), and < 1 opacity so the page content shows through.
The cat is drawn procedurally on a DPR-aware canvas (no asset required) and reacts to activity, detected purely through DOM observation of stable data-* hooks (so it stays decoupled from the host's internal session/streaming state):
- Typing — while you type in the composer, the cat leans toward the input, looks at it, and shows an animated "typing dots" bubble plus a pulsing activity dot; its tail sways faster. It returns to idle after a short pause.
- Streaming / working — while the assistant streams a response, the cat tilts into a contemplative pose, looks up toward the conversation flow, and shows the same busy bubble + dot.
- Idle — the cat breathes, blinks, its eyes follow the pointer, its head subtly turns toward the gaze, and its tail sways gently.
How it plugs in
The package is a dsh bundle (dsh.bundle → cordis.patch.yml) that is also a client plugin (dsh.client). Installing it into a profile with dsh plugin --profile web add <pkg> auto-registers it (the CLI reconciles installed dependencies that declare dsh.bundle into dsh.profile.bundles), then the client module system serves /plugins/@nkj/dsh-ui-pet/client.js on the next boot. No manual cordis.yml edit.
Built-in dev loop
# once: install build deps
pnpm install
# build both artifacts (lib/index.js host half + lib/client.js browser bundle)
pnpm run build
# iterate: rebuild the browser bundle on source change (the dsh host stat-polls
# the served bundle and broadcasts a reload, so the browser refreshes on write)
pnpm exec tsdown --watch
Verify locally (before publishing)
dsh plugin --profile web add /absolute/path/to/dsh-ui-pet
pnpm dsh web # bind http://127.0.0.1:3080
In the browser at http://127.0.0.1:3080, confirm:
- In the tree —
dsh --profile web --dump-configcontains theui-petrow. - Bundle served — DevTools → Network shows
/plugins/@nkj/dsh-ui-pet/client.js(200); orcurl http://127.0.0.1:3080/plugins/@nkj/dsh-ui-pet/client.js. - Rendered, and visible — DevTools → Elements: the
<canvas>is inside theshell.overlaylayer,position:fixed,pointer-events:none, low z-index, andopacity < 1. It is anchored to the bottom-right viewport corner. - Behavior — the body stays put while the pointer moves (only the eyes follow it). Type in the composer: the pet leans toward the input and shows the busy bubble/dot. Send a message: while the assistant streams, the pet tilts into a working pose. The overlay never blocks clicks (the layer and canvas are
pointer-events:none).
While SPRITE is empty in src/client/sprite.ts, the pet draws a colorful placeholder blob, so step 4 is verifiable without any asset.
Publish
pnpm run build
npm pack # confirm lib/, cordis.patch.yml, and src are in the tarball
npm publish --access public
After publishing, a user installs it with:
dsh plugin --profile web add @nkj/dsh-ui-pet
Customizing the pet
- The cat look is parameterised in
src/client/sprite.ts: the fur/ear/nose/chest palette (FUR_TOP,FUR_BOTTOM,FUR_DARK,INNER_EAR,NOSE_PINK,CHEST_WHITE,WHISKER) and the head/body proportions (BODY_RX,BODY_RY,HEAD_RX,HEAD_RY,HEAD_OFFSET_Y,SIZE). - Animations live in
src/client/Pet.tsx: the idle bob, head-turn toward the gaze, per-state body lean, pupil track, tail sway, the "typing dots" speech bubble, and the pulsing activity dot. - Make a sprite sheet to replace the vector cat: set
SPRITE(asset path or URL) and tuneFRAME_COLS/FRAME_ROWS/FRAME_W/FRAME_H/FPSinsrc/client/sprite.ts, and setVECTOR=false. - Busy-state detection tunables live in
src/client/sprite.ts:TYPING_IDLE_MS(hold after the last composer keystroke) andWORKING_IDLE_MS(hold after the last conversation-flow mutation). - DOM hooks are the only host coupling:
[data-composer-card](composer, for typing) and[data-chat-flow](conversation stream, for working). Both are optional — if absent, the pet simply idles.
Model Experience
None. The pet manages browser-only presentation; nothing reaches a model request.
KV Cache effect
None; this package neither assembles nor sends a provider request.
Target version
Runtime-compatible with dsh 0.1.1-rc.2 (the web profile). The host dsh install supplies the runtime react, @deepseek-ai/cordis, and the slots service.
The published package is intentionally build-dependency-free: the source uses no @deepseek-ai/* imports (the DSH-specific types are left structural/untyped), so the standalone build needs only react + tsdown + typescript. The DSH integration is by convention: apply receives a ctx with a slots service, and the bundle is the standard window.__ModuleLoader__.load closure factory.
Known Limitations and Deferred Work
- The pet lives in the
shell.overlayfloating layer, so it paints above the app content (it is deliberately semi-transparent and small so it does not obscure it). Rendering it genuinely behind the content is impossible from a plugin without DSH source changes: the conversation/details/sidebar surfaces are opaque and would fully cover a behind-content canvas. Anchoring it to a corner (rather than chasing the pointer) is what keeps it clear of the text you are reading. - Busy detection is DOM-based and therefore heuristic. "Working" is inferred from conversation-flow DOM mutations, so brief non-streaming churn (e.g., a tool disclosure, or history loading on open) can also trigger the working pose for the debounce window. Distinguishing streaming specifically would require reading the host's
running/stream state through a session hook. - The
ctx/ slot types are structural and untyped to keep the standalone build self-contained. When developing inside the dsh monorepo, restore the realClientContext/PropsRuntime<'shell.overlay'>types for full checking. - The bundle format (closure factory + React externalization) is reproduced from the dsh
clientBundlepreset; iterate against a livedsh webto confirm exact output.
Comments
Loading…
From the same category
DeepSeek Harness plugin for Reactive Resume: bridges your resumes and job applications into a Harness session over MCP.
★ 41.7k
↓ 270/wk
MIT
Aug 24, 2026
dsh plugin --profile web add dsh-plugin-reactive-resumeby Tencent
Let AI agents use your real, logged-in browser without interrupting your work. CLI + extension for browser automation across any shell-capable AI agent.
★ 8.1k
↓ 7k/wk
MIT
TypeScript
Sep 30, 2026
dsh plugin --profile terminal add @wxg-prc-cpg/browser-skill-dsh-pluginby yjh051108
dsh-routing-suite — injector + router-standard kit: install the runtime injector first, then the task-aware reasoning-mode router preset (measured P1-P23).
★ 7k
MIT
JavaScript
Sep 18, 2026
dsh plugin --profile web add @dsh-external/dsh-super-injectorby Q00
Agent OS: the agent gets smarter on its own. We just hold the line: Interview-gated, staged evaluation, budgeted evolution loop. MCP server, 14 runtimes: Claude Code, Codex CLI, Gemini CLI, OpenCode,
★ 6.2k
MIT
Python
Oct 4, 2026
by dsh-market
The plugin market inside DeepSeek Harness — browse, search, one-click install · DSH 可视化插件市场
★ 5.5k
↓ 164.4k/wk
MIT
TypeScript
Oct 3, 2026
dsh plugin --profile web add dshmarketby superdesigndev
OpenRouter for agent tools. Join community here: https://discord.gg/6mQYYfFMAn
★ 4.1k
NOASSERTION
Python
Oct 4, 2026
dsh plugin --profile web add treg-dsh