dsh-soundscape 🔊
A session soundscape for the DeepSeek Harness Web GUI: turn-complete celebration (synthesized fanfare + confetti), blocked-on-user alerts, error buzz, send clack, and optional typing ambience. Zero audio assets, zero core changes, plus a
ctx.soundscapeservice for other plugins.
A DeepSeek Harness (DSH) web plugin that gives the agent's turns an audio identity: synthesized WebAudio feedback when a turn starts, succeeds, fails, or blocks on you — and a confetti burst when work completes. Every sound is generated live by oscillators and envelopes — no audio files, no network requests, no core modifications. Install, restart, and it works; tune it per-sound in the settings page.
✨ Features
| Event | Sound | Default |
|---|---|---|
| Turn started | send rebound clack send |
✅ |
| Turn completed successfully | celebration fanfare + confetti celebrate (or plain ding) |
✅ |
| Turn errored / interrupted | low buzz buzz |
✅ |
| Waiting on you (approval / question / plan review) | two-tone alert alert (1.5s throttle) |
✅ |
| Session opened | soft two-note greeting greet |
⛔ |
| Streaming output (optional) | typing ambience click (throttled + jittered) |
⛔ |
- Zero audio assets: pure WebAudio oscillator synthesis.
- Zero core changes: only official client-plugin seams (
conversation.input.dock/conversation.session.header.actions/settings.section). - Durable settings: the
soundscapesettings namespace, saved immediately. - Cross-plugin service:
ctx.soundscape.play(name)/ctx.soundscape.celebrate()for other client plugins. - HMR friendly: every registration is a
ctx.effect; hot reload cleans up automatically.
📦 Install
Prereqs: DeepSeek Harness (dsh web works), Node ≥ 22.19, pnpm.
# From GitHub
dsh plugin --profile web add "github:Blaczz/dsh-soundscape#main"
# Local directory (development)
cd dsh-soundscape && npm install --legacy-peer-deps && npm run build
dsh plugin --profile web add ./dsh-soundscape
# Local link
dsh plugin --profile web add link:./dsh-soundscape
Restart dsh web after install (a new plugin row needs one restart; later source changes ride HMR).
Git installs need
allowBuildsauthorization: if the firstadd github:...fails, put the package key underallowBuildsin~/.dsh/profiles/web/pnpm-workspace.yamlas dsh prints, then re-run; or publish a prebuilt npm package to skip build authorization entirely.
🎛️ Usage
- Install, restart, open any session, send a message:
- turn start → rebound clack;
- successful completion → fanfare + confetti (switch to a plain ding in settings);
- error/interrupt → buzz; waiting on your approval/answer → two-tone alert.
- The session header has a 🔊/🔇 quick mute toggle (durable across restarts).
- Settings → 🔊 音效: master switch, master volume, per-sound toggles with previews, and stream-cadence knobs.
🔌 For developers: the ctx.soundscape service
Other client plugins add soundscape to their inject and call:
export const inject = ['slots', 'soundscape']
export function apply(ctx: Context): void {
ctx.soundscape.play('celebrate') // one sound
ctx.soundscape.celebrate() // full celebration (sound + confetti)
if (!ctx.soundscape.isEnabled()) ctx.soundscape.setEnabled(true)
}
Sound names: click send ding celebrate buzz alert greet. Each is gated by its user setting and the master volume.
🛠️ Development
npm install --legacy-peer-deps # build deps
$env:DSH_NODE_MODULES = "$env:USERPROFILE\.dsh\profiles\node_modules"
npm run setup:dsh-workspace # symlink the runtime @deepseek-ai/* packages
npm run verify # ★ one-shot local gate (clean + typecheck + test + build)
npm run typecheck # typecheck src + tests
npm test # vitest (37 tests: state machine / synth / engine / settings / manifest)
npm run build # tsc + tsdown → lib/
dsh web --patch ./cordis.patch.yml # zero-install quick verification
npm run verify is the pre-push gate: the extracted pure state machine (turn-feedback.ts) plus mock AudioContext / fetch tests catch event-mapping, gating, and throttle bugs locally, no browser needed.
Layout
dsh-soundscape/
├── package.json # dual contract: dsh.bundle.patch + dsh.client
├── cordis.patch.yml # bundle patch layer (inserts this package)
├── tsdown.config.ts # client bundle (__ModuleLoader__.load + purity gate)
├── scripts/ # build / clean / setup-dsh-workspace
├── src/
│ ├── index.ts # host half: settings namespace + loopback HTTP API
│ ├── soundscape-settings.ts # shared settings model (schema + defaults)
│ ├── settings-api.ts # GET/PATCH settings API (loopback-only)
│ └── client/ # browser half
│ ├── index.ts # apply: ctx.soundscape service + slot injection
│ ├── SessionListener.tsx # conversation-snapshot diff → event sounds
│ ├── SoundEngine.ts # WebAudio engine (lazy AudioContext)
│ ├── synth.ts # pure synthesis primitives (oscillators + envelopes)
│ ├── confetti.ts # zero-dependency canvas confetti particles
│ ├── HeaderMute.tsx # session-header mute toggle
│ ├── SettingsSection.tsx # settings page (with previews)
│ └── settings-client.ts # settings API client
└── tests/ # manifest contract + settings patch validation
🧩 Ecosystem positioning
- Fills a gap: before this, the DSH ecosystem had no turn-complete sound/celebration effect and no blocked-on-user alert sound (desktop notifications are silent;
dsh-fun-typewritercovers only typing ambience). - Technical route: dual-sided client plugin (
dsh.client+ bundle patch), mirroringdsh-fun-typewriter's zero-asset WebAudio + plugin-owned settings API, extended with thectx.soundscapecross-plugin service (thectx.providepattern fromdsh-client-shortcuts). - Zero core changes: everything registers through
ctx.effect/ctx.slots.inject; HMR unload cleans up.
⚖️ License
MIT © 2026 Blaczz. An independent community plugin, not affiliated with DeepSeek Harness.
No comments yet. Be the first to write one.