npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ganrunlin-dsh/dsh-client-ui-bg

v0.1.1

Published

User-customizable web background: local file or remote URL, applied independently to AppFrame and the welcome-screen hero

Downloads

48

Readme

@ganrunlin-dsh/dsh-client-ui-bg

A DeepSeek Harness plugin that adds a user-customizable web background. Two preference rows live in the General settings panel — one for the window background, one for the welcome-screen background. Each row accepts a color, a remote URL, or a local file upload; the resolved value paints <body> before the page shell mounts, so the user never sees a flash of the unconfigured background.

Install

dsh plugin --profile web add @ganrunlin-dsh/dsh-client-ui-bg

dsh plugin adds the package via pnpm and reconciles it into the profile's bundle stack — the package declares dsh.bundle.patch in its manifest, so reconcilePlugins() appends it to dsh.profile.bundles automatically. Restart the profile after install.

Requires @deepseek-ai/dsh-web-app ≥ 0.1.1 (any web profile). The plugin declares its DSH peers as peerDependencies, so they resolve from the host installation — no version pinning needed on the user side.

What you get

A new Background section in Settings → General, with two cards:

  • Window — paints <body> for the whole AppFrame.
  • Welcome screen — paints the welcome shell's hero backdrop.

Each card exposes a four-button kind selector (Default / Color / URL / Upload) and an inline input that swaps with the kind.

Configuration

The ui-bg settings namespace; the Host half installs the schema through installSettingsSection, so any configuration surface that owns the ui-bg key (the Settings panel, host patches, the --patch CLI flag, etc.) can drive it.

| Field | Type | Default | Semantics | |---|---|---|---| | frame.kind | 'none' \| 'color' \| 'url' \| 'file' | 'none' | Window background source kind. | | frame.value | string | '' | CSS color (#rgb / #rrggbb / #rrggbbaa), remote URL (http://… or https://…), or data URL (data:image/…). | | hero.kind | 'none' \| 'color' \| 'url' \| 'file' | 'none' | Welcome-screen background source kind. | | hero.value | string | '' | Same shape as frame.value. |

The frame slot aliases over --dsw-alias-bg-base for the whole AppFrame; the hero slot aliases over the same token, but the welcome shell paints its own backdrop inside the conversation view. When a slot is 'none', the next apply pass clears its alias and the theme default returns.

Programmatic override

# ~/.dsh/profiles/web/cordis.patch.yml
- id: ui-bg
  config:
    frame:
      kind: color
      value: '#1f2933'
    hero:
      kind: url
      value: 'https://example.com/hero.jpg'

Model Experience

None. This plugin owns presentation and persistence only; nothing here reaches a model request.

User Experience

  • The user opens the General settings panel and sees two cards under Background: Window and Welcome screen. Each card exposes a four-button kind selector (Default / Color / URL / Upload) and an inline input that swaps with the kind.
  • A color input commits #1f2933 as soon as the regex validates; a URL input commits when the value starts with http:// or https://; a file input commits when the chosen file is ≤ 4 MB and matches one of image/png, image/jpeg, image/gif, image/svg+xml. Other shapes surface an inline error in the row and refuse the write at the schema's validate callback.
  • Each write goes through ctx.settingsScope.bind<BgSettings>(...), fences on the namespace revision, and persists to ~/.dsh/profiles/web/settings.yaml. The Host-side apply() re-reads on every index-html tap and re-emits the inline boot script, so a saved change survives the next page load.
  • The inline script runs before the shell mounts and sets --dsw-user-bg-frame and --dsw-user-bg-hero on document.body. The frame slot also aliases --dsw-alias-bg-base so every existing reader (AppFrame.module.css, HeroShell.module.css, etc.) inherits the user's value without a single source-file edit.

Known Limitations and Deferred Work

  • No HMR re-apply for the boot script. The Host reads the settings section at request time and injects the script once per HTML response; the client half subscribes through ctx.settingsScope, so the visible background flips after a save without a reload, but the pre-shell paint can only refresh on the next navigation. A live-subscription hook on webServer.tapIndex would close the gap.
  • The file source stores the data URL in the durable section. The settings file grows linearly with every upload and is read fully into memory at boot. A future split could store uploads as attachments (via the dsh-attachment service) and persist only an attachment reference.
  • Remote URLs are not fetched at validation time. A malformed URL passes the regex gate but may still fail to load in the browser; CSP, CORS, and broken links surface only when the page actually paints.
  • SVG uploads are accepted but not sanitized. A user-supplied SVG can reference external resources or scripts that the same browser tab will then load. A sanitizer pass on the upload path is the right place to plug it.
  • Two settings.general.item registrations share one namespace. A future split into settings.section (one card per slot) would let the user reorder them; today both rows live next to the Appearance row at order: 20 and order: 21.

Architecture

This package ships both the Node half and the browser half in one tarball:

  • Node half (lib/index.js) — Cordis plugin entry. Registers the ui-bg settings namespace on the host context and taps the index-html response to inject the pre-shell paint script.
  • Browser half (lib/client.js) — Self-contained module factory. Renders the two settings cards through the framework's settings.general.item slot, validates writes, and re-renders on revision bumps.
  • Bundle patch (cordis.patch.yml) — Declares the plugin id and import target so dsh plugin add reconciles it into the profile's bundle stack.

The dual-face contract (./ for Node, ./client for browser) follows the DSH bundle convention; the Loader and the browser shell each pull the half they need.

License

MIT