A photo-real desk pet for the DSH window: four personas with five expression sprites each, whose dance, hair-flip and walk actions play as 24 fps VP9 alpha video clips; proactive lines with an optional edge-tts neural voice, ink / confetti / cloud / fog / bomb effects, a right-click menu and a /dsh-pet command, plus a small chat box that answers through a one-shot host model call without writing to your session. UI text ships in en, zh, es, pt and hi.
Install
# from npm (prebuilt)
dsh plugin --profile web add dsh-pet-plugin
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:zuoyunlai/dsh-pet-plugin
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
A little companion that lives in the bottom-right corner of the DSH web UI: it stays around or drops in at random, talks (with voice), walks, dances, gets shy or annoyed, and carries a tiny input box you can chat with. Four photo-realistic personas, each with its own temper.
Scope: the pet only lives inside the DSH window (it mounts into the framework's overlay slot). It cannot float above other applications — that would need a separate Electron shell rather than a plugin.
At a glance
Languages: UI chrome, persona taglines and the chat system prompt follow the browser interface language — shipped for
en / zh / es / pt / hi(locale/*.json, namespacepet; slots register withlocale: 'pet'per the DSH slot contract). Each persona also ships an English line pack, so a non-Chinese UI hears English lines.Mount points:
shell.overlay(the pet itself, a click-through layer) andconversation.input.right(the entry button next to the composer).Private chat: what you type in the small box never enters your session. The host half exposes
POST /dsh-pet/chatand answers with a one-shotctx.llm.stream()call (no session, no session log). Defaults:deepseek-account/deepseek-flash; provider, model, maxTokens and temperature are plugin config.Icon:
icon.svg(the rose silhouette) and the composer button share the same path.Settings panel: grouped (look / voice / display / actions / effects), custom dropdowns (native
<select>popups are system-white and unreadable in dark themes) and custom switches; it is pinned to the viewport and does not follow the pet.Four personas (photo-realistic, same lighting, 5 expressions each: default / happy / shy / angry / sleepy): 薇 (violet), 绯 (crimson), 靛 (indigo), 雪 (silver). Expression changes cross-fade (240 ms) instead of hard-cutting.
Action sequences: a persona may declare
actions: { dance: [...], hair: [...], walk: [...] }; each set is 3 frames played as a 340 ms flip-book. All four have dance / hair-flip / walk, each stylised to the character.Adding artwork: drop transparent PNGs into
assets/and reference them fromPERSONAS(image, orimages: { mood: 'file.png' }). Served by/dsh-pet/assets/(image extensions only, basename only).tools/make-pet-image.pyremoves a green-screen background (preferred) and falls back to a gradient key.
Behavior
| Capability | How |
|---|---|
| Always-on / random | Toggle in the panel; random mode rolls a per-hour probability inside the active window |
| Active hours | Start/end time, supports crossing midnight (22:00 → 03:00) |
| Proactive lines | Per-mood line packs, bubble + speech |
| Voice | Optional: if the host has any python with edge-tts, /dsh-pet/tts synthesises (cached) and /dsh-pet/tts/status probes it; otherwise it falls back to the system speechSynthesis. The plugin itself has zero runtime dependencies |
| Small input box | Chat with the pet only; one-shot model call, nothing is written to any DSH session |
| Moods | idle / walk / dance / shy / angry / sleep / talk / happy |
| Gaze | Pupils follow the mouse (CSS variables only, no re-render) |
| Effects | Ink / confetti / cloud / fog (wipable) / bomb + cracked screen |
| Event hooks | Confetti after a turn longer than 4 s; a cloud appears after a failed tool call |
| Temper | Per-persona weight table decides what it does more of |
| Hide | "Hide for 1 h" in the panel |
Install (local, no registry)
Published as dsh-pet-plugin on npm; it also installs straight from a folder.
# from the registry (after publish)
dsh plugin --profile desktop add dsh-pet-plugin
# from a local checkout: quit DSH first, then
powershell -NoProfile -ExecutionPolicy Bypass -File .\install.ps1 # or double-click install.cmd
Quit DSH first (the profile's package.json is HMR-watched). The script adds
"@local/dsh-pet": "file:<this dir>" to the profile, registers the bundle, runs
pnpm install, then reads back all four facts. update.cmd only refreshes files and is
safe while DSH is running. For the sweeter neural voice:
pip install edge-tts # any python the host can find
export DSH_PET_PYTHON=/path/to/python # only if auto-discovery misses it
Verify
node --check client.js
node tests/smoke.mjs # fake window + React stub, renders every persona/mood
# host routes need the harness packages, so run them from the installed copy:
cd <profile>/node_modules/@local/dsh-pet && node --test tests/host.test.mjs
node <dsh-plugin-guide>/bin/dsh-plugin-dev.js check --cwd . --strict
node <dsh-plugin-guide>/bin/dsh-plugin-dev.js verify --cwd .
Customize
- The client bundle is generated: edit
src/*.jsand runnode build.mjs, which concatenates the parts intoclient.js(the only file DSH loads). Never editclient.jsby hand —npm testrebuilds and then runs the smoke test. - Personas, lines and tempers:
pets/<id>/pack.json—images(five expressions),actions(dance / hair / walk, three frames each),voice,temper, andlines/linesEnline packs. - UI strings: edit the
petnamespace inlocale/*.json, thennode build.mjs— the dictionaries are injected at build time, so the locale files are the single source of truth. New language: runnode tools/gen-locales.cjsfor a skeleton, then translate. - Moods and animations: add keyframes in
src/70-style.jsand map the class bymoodinsrc/96-overlay.js. - Action clips: a pack may carry
clips: { dance: "pet-x-dance.webm" }— a VP9 WebM with an alpha channel. When that action plays the pet renders a looping<video>instead of flipping through still frames, which is the only way to get true 24 fps motion. - Artwork: drop transparent WebPs into
assets/and reference them frompets/<id>/pack.json, thennode build.mjs(it regeneratessrc/30-personas.js). The/dsh-pet/assets/route only serves image extensions.
Security model
- The host routes are gated three ways, none of them tied to a fixed port or domain:
Hostmust be a loopback address, the host's own origin, or listed in theallowedHostsplugin config (for reverse-proxy / LAN deployments); a presentOriginmust be same-origin with thatHostor the desktop shell (dsh-app://app,dsh-app://shell); andSec-Fetch-Site, when present, must besame-originornone. Non-browser clients that send none of these are allowed — that is the deliberate limit of a local HTTP endpoint, see below. - Speech synthesis is a
POSTendpoint that returns the audio bytes; there is no GET URL to feed to an<audio src>, so a page (or another local process) cannot make the host synthesise anything by pointing an element at it. - Synthesised speech is cached in the OS temp dir with a size cap that is re-checked after every synthesis, and writes go through a random temp name + rename so a pre-planted symlink cannot redirect them.
- Anything the page sends (settings, chat history, persona id) is treated as data: validated, length-capped, and never interpolated as instructions or markup.
- Neural voice sends the spoken text to Microsoft's edge-tts endpoint. Turn it off
(or never install
edge-tts) to keep everything local; the panel says so.
Known limits
Host version: built and tested against dsh
0.2.1-alpha.2. It needs thewebServerservice and theshell.overlay/conversation.input.rightslots, which are 0.2-generation APIs — on a 0.1.x host it installs but never mounts (one console line says so).engines.dshinpackage.jsonis a declaration only: the installer does not enforce it, and the plugin declares no@deepseek-ai/dsh-*peer ranges on purpose, so a version mismatch never blocks installation.Neural voice needs a host python with
edge_tts; otherwise the system SAPI voice is used.Browsers block autoplay before the first user gesture — click the page once.
Settings live in
localStorage. The debug handle (globalThis.__dshPet) stays off unless you setdsh-pet.debug=1inlocalStorageor append?petdebug=1.The pet cannot float above other applications (overlay slot only).
Links
More in this category
PC2005-cloud/dsh-pet#dsh-pet★ 3496
Desktop pet for the DSH Web UI with 25 transparent animations, screen wandering, click reactions and drag, plus a reproducible asset-generation pipeline.
Nagi-ovo/dsh-ads★ 682
Parody ads in 2005-Chinese-web style: sidebar banners, in-chat feeds, corner popups, and a close button whose hit area is smaller than it looks. All fictional.
vlln/whale-girl★ 375
Desktop pet (QQ-pet style): floats in the corner, draggable, feedable, playable.
yyh-001/dsh-meme★ 295
Chat meme stickers: text-only send, mood auto-send, QQ/WeChat-style picker, auto-learn, custom packs.
a86582751/dsh-nexttavern★ 191
NextTavern is a long-form roleplay plugin for DeepSeek Harness 0.1.7-rc.2 Web, with character-card import and creation, worldlines, worldbooks, layered long-term memory, keyword/semantic/hybrid retrieval, character agents, and card or novel export. SillyTavern character-card import is supported; v0.2.9 fixes distribution and installation.
Sutera-Diffusus/dsh-whale-musume★ 156
A whale-girl companion for DeepSeek Harness with 45 achievements, daily quests and weekly check-ins, three mini-games, 92 artworks, 620 dialogue lines, a growth journal, weather and festival reactions, per-tool work poses, cross-device save export/import (JSON file or migration code), accessibility mode and an optional MiMo TTS bridge. Data stays in the host localStorage with no telemetry. Verified on DSH desktop 0.2.0-rc.2; compatible with 0.2.1-rc.1/rc.2 and legacy 0.1.x web.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.