Themes & Appearance

dsh-bloom-theme

webkubor/dsh-bloom-theme · ★ 280

webkubor

Bloom Morandi theme: four variants (mist, cinnabar, petal, ripple) built on OKLCH so light and dark stay perceptually even, switchable from the top bar, with all eight foreground/background pairs measured at WCAG AA or better.

License
MIT
Added
2026-08-21
Maintenance
active
Install kind
github
npm
@kubor/dsh-bloom-theme

No manifest check is available; listing does not imply compatibility or security review.

安装

dsh plugin --profile web add github:webkubor/dsh-bloom-theme

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. 📌 Desktop-first — a note about the DSH Web UI
  2. The gist
  3. Quick start
  4. Screenshots
  5. Install
  6. Features
  7. Design: two-track colors
  8. Develop / build (TypeScript)
  9. FAQ
  10. Contribute / open source
  11. Support
  12. DSH plugin suite
  13. License

📌 Desktop-first — a note about the DSH Web UI

Short version: Bloom's next iterations target the DSH desktop app first. The Web UI is no longer actively supported and will fade out.

(0.16.0 and earlier were built against the DSH Web UI. 0.17.0 is the desktop-ready release — it brings the DSH 0.2.0 selector adaptation plus a drift gate that catches this class of breakage automatically.) On desktop app 0.2.1-rc.5, the switcher's version display uses the desktop app version rather than an older bundled DSH package version; the drift gate also targets the locally installed desktop release.

DSH now ships a desktop app, and it is what I use every day. A theme's value lives on top of a UI — when the host changes its interface, the palettes and the glass have to follow — so that is where the work goes now.

What this means for you:

You use What happens
Desktop app New palettes, new motion, visual fixes land here first. I use it daily, so when the UI moves, I move with it.
Web UI Stays working as-is, but I no longer adapt it to new changes in the DSH web front-end. If DSH reshuffles its DOM and something looks off there, I may not catch it in time.

Two clarifications, so you do not have to guess from the heading:

  • Installed versions keep working. What stops is "growing with the new UI", not "breaking what you have".
  • If the Web UI is your only option, please open an issue and describe your setup — real demand changes my judgement. That is not a formality.

What the previous version (0.16.0) changed: running steps now take on the theme color (the sweep went from grey to the three Bloom tones); the round-status spectrum is wired back up (it vanished silently when DSH was renamed); the message-bubble glass edge that never drew in light mode is fixed; substring-selector self-overlap ("box inside a box", the square black chip) is fixed; the pill background on running steps is gone — state should not have to shout from a box.

The gist

A glass + Morandi theme for DeepSeek Harness. Eight light/dark palettes, adaptive by light/dark; panels are real frosted glass (semi-transparent + backdrop blur + glass edges); colors are low-saturation Morandi (OKLCH, WCAG AA); restrained, consistent micro-interactions; zero runtime deps; TypeScript front-end.

The Morandi character does not live in --accent. It lives in --accent-rgb.

Quick start

  • DSH desktop app: install from the in-app plugin manager and reload — a 「黛蓝 ▾」 button appears in the top bar to switch between the 10 palettes, light/dark, and wallpapers.
  • Custom profiles (CLI / server / web): dsh plugin --profile <profile> add dsh-bloom-theme, wire it into the boot graph, restart DSH — see Install below.

Screenshots

10 palettes (light): click any one and the whole accent / background / glass / motion hue switches together.

Every palette has a dark variant too (example: Amber · dark):

Install

Desktop app: install and update from the plugin manager inside the app. The desktop profile is owned exclusively by the application — running dsh plugin --profile desktop ... from a shell fails with profile "desktop" is managed exclusively by the Electron application. That is by design, not a permissions problem.

Only Node.js is required — no global dsh install; upstream's official entry is npx @deepseek-ai/dsh. If dsh is installed globally, use dsh instead.

# 1) install into your profile (use your own profile name)
npx @deepseek-ai/dsh plugin --profile <your-profile> add dsh-bloom-theme

# 2) wire it into the boot graph: add "dsh-bloom-theme" to the
#    dsh.profile.bundles array in ~/.dsh/profiles/<your-profile>/package.json

# 3) restart DSH

Refresh the page and a "Mist ▾" theme button appears top-right. Click it to switch between 10 palettes; the current version sits at the bottom of the dropdown, and a ↑ vX badge lights up when a newer version is on npm (jump to the Releases page).

Features

Feature Description
Frosted-glass panels (on by default) Semi-transparent fill + backdrop-filter blur + glass edges (top highlight / translucent stroke / soft outer glow), adaptive opacity per light/dark
8 Morandi palettes Mist / Cinnabar / Petal / Ripple / Sage / Stone / Lapis / Amber, each with light & dark, one-click switch
UI language One click in the panel to switch between 中文 / English / Русский; until you pick one it follows your browser language, exactly as before. Text only — palettes and measured contrast are untouched
Two-track colors A readable track for contrast (text/buttons) and a mood track for ambient gradients — never mixed
Micro-interactions Menu entrance, selected-row bar slide-in, hover / press feedback; shared duration & easing tokens, consistent everywhere
Theme-colored thinking animation Deep diving… flows through the current theme's three-color spectrum; auto-still under prefers-reduced-motion
Version / update hints Current version at the bottom of the dropdown; ↑ vX chip when npm is newer; update banner for very stale installs, with desktop guidance to update from Plugins in the sidebar
OKLCH + WCAG AA Perceptually uniform color space, no jumps on light/dark switch; all accent/background pairs measured ≥ 4.5:1
Zero deps · CSS-variable driven Only CSS variables + a little switch logic; near-zero runtime cost
Respects native controls Switcher mounts into the DSH header utilities area, side-by-side with native buttons
TypeScript build src/ 10 modules → tsc (ESM) for node + esbuild (single-file IIFE) for browser; one-command build / deploy / check / preflight

Design: two-track colors

Bloom's point was never "swap the colors" — it is a complete Morandi design language: low-saturation ambient gradients, cool-toned hairlines, long soft shadows, restrained radii and spacing.

The easiest thing to get wrong (and most often done wrong) is the two-track color:

  • Readable track --bloom-accent — deliberately deepened to pass WCAG; for text / buttons / selected states;
  • Mood track --accent-rgb — the real Morandi color (low-saturation, grayed); used only for large ambient gradients and cool hairlines.

All 14 gradient usages in the original use the mood track, never the readable track. When you paint a large area with the readable color, Petal goes from lotus pink to fluorescent magenta and the Morandi feel dies. This plugin ports both tracks intact, and the sibling tool contrast-guard keeps accent/background contrast honest.

Develop / build (TypeScript)

npm install
npm run typecheck    # tsc --noEmit, full type check
npm run build        # typecheck → tsc emits lib/index.js → esbuild emits lib/client.js
npm run deploy       # one-click deploy to local DSH (sync-version → build → rsync)
npm run preview      # deploy to desktop-local (the desktop host is an app, not a browser tab)
npm run dev          # build + watch (recompile+deploy on src change)
npm run package      # one-click package (npm pack → .tgz)
npm run check        # 6 static gates + contrast-guard (runs on every commit)
npm run preflight    # pre-release: version consistency / git state / listing sync

src/ is 10 modules (meta · appearance · palette · tokens · css/ · dom · drag · version · switcher · client); DSH loads the artifacts in lib/.

The build is dual-track — the two halves want opposite module formats:

Artifact Compiler Format Why
lib/index.js (node side) tsc ESM cordis' plugin loader reads it as ESM
lib/client.js (browser side) esbuild single-file IIFE DSH runs plugin client.js as a classic script — a top-level import/export is a syntax error

So the browser-side source can be split freely, but the artifact must bundle back into one self-contained file.

The version number is bumped by release-please inside the release PR, alongside package.json (via the x-release-please-version marker at the end of the line in src/meta.ts). scripts/sync-version.mjs is only a local-dev fallback and is not part of the publish path. See CONTRIBUTING.

FAQ

Theme not applying? Hard-refresh once (Cmd/Ctrl + Shift + R). If the page says Failed to load plugins, the client failed to register — re-run npx @deepseek-ai/dsh plugin --profile <your-profile> add dsh-bloom-theme or upgrade to the latest version.

Can I customize colors? For now you pick a whole palette via variants; per-color customization is on the roadmap.

Contribute / open source

  • Add a new palette: add one entry to PALETTE / VARIANTS / VARIANT_LABELS in src/client.ts — glass, motion, selected state and the contrast guardrail all follow automatically.
  • Run npm run build && npm run check and make sure contrast-guard passes before opening a PR.
  • Issues, PRs and ideas are all welcome.

Support

If Bloom makes your DSH nicer to use, drop a ⭐ or buy me a coffee (sponsor link below and one entry in the panel menu).

DSH plugin suite

Install both with Node.js, then restart DSH (replace your-profile with your profile name):

PROFILE=your-profile
npx -y @deepseek-ai/dsh plugin --profile "$PROFILE" add dsh-bloom-theme @dsh-plugins/dsh-llm-hub && PROFILE="$PROFILE" node -e 'const f=(process.env.DSH_HOME||require("os").homedir()+"/.dsh")+"/profiles/"+process.env.PROFILE+"/package.json",p=require(f),b=p.dsh.profile.bundles;for(const n of Object.keys(p.dependencies))if(/^(dsh-bloom-theme|@dsh-plugins\/)/.test(n)&&!b.includes(n))b.push(n);require("fs").writeFileSync(f,JSON.stringify(p,null,2)+"\n")'

License

MIT — keep the copyright notice on borrow/modify. Palette inspiration from typora-Bloom-theme.