DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Nkjv2 /

Nkjv2/dsh-ui-pet

Verified

A 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.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@e2e9e201

@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:

  1. In the tree — dsh --profile web --dump-config contains the ui-pet row.
  2. Bundle served — DevTools → Network shows /plugins/@nkj/dsh-ui-pet/client.js (200); or curl http://127.0.0.1:3080/plugins/@nkj/dsh-ui-pet/client.js.
  3. Rendered, and visible — DevTools → Elements: the <canvas> is inside the shell.overlay layer, position:fixed, pointer-events:none, low z-index, and opacity < 1. It is anchored to the bottom-right viewport corner.
  4. 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 tune FRAME_COLS/FRAME_ROWS/FRAME_W/FRAME_H/FPS in src/client/sprite.ts, and set VECTOR=false.
  • Busy-state detection tunables live in src/client/sprite.ts: TYPING_IDLE_MS (hold after the last composer keystroke) and WORKING_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.overlay floating 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 real ClientContext / PropsRuntime<'shell.overlay'> types for full checking.
  • The bundle format (closure factory + React externalization) is reproduced from the dsh clientBundle preset; iterate against a live dsh web to confirm exact output.
—/ 5

No ratings yet

Verified DSH bundle

Commit e2e9e201f6fc

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout