dsh-luna-theme: Apply Luna-Chat style to DSH's rendering interface

Introduction

DSH’s interface defaults to a generic shell. People building agent applications usually have their own visual preferences, but changing colors, backgrounds, and adding desktop decorations often requires modifying the application source code or scattering theme logic across multiple custom components. Personal skinning needs are generally addressed by scattered solutions in the community, but most only cover single elements and behave inconsistently between desktop and web clients.

dsh-luna-theme is a skinning plugin with a clear positioning: it provides Luna-Chat style light and dark themes for the DSH desktop and web clients, and bundles the conversation background, balance widget, desktop pet, and splash animation into a single package, loading and unloading them together with the theme. The plugin is maintained by shinku-xuan and is categorized as “Fun Outfits” in the community directory, currently with 4 stars and 1 fork on GitHub. Current package version 0.15.0, code uses MIT License.

Below is an introduction to the components it contains, the established behaviors, and things to note before integration.

What is this

In one sentence: This is a DSH bundle plugin. After installing it to the target profile, restart the application to load the theme and the four bundled components.

It solves “personal interface decoration” problems, not business process problems. The author’s trade-offs are clear: the theme only reads the state at mount time and does not modify mode preferences; the pet chat does not write to the DSH Session, and the theme does not register model tools. In other words, it will not interfere with your existing Host configuration and Session data.

Core Features

Theme Appearance

Light mode uses cherry blossom pink, white glass panels, and blue-purple secondary buttons; dark mode uses purple glass panels and gold accents. The settings panel, menus, input box readings, Markdown content, and conversation turn navigation all follow the color scheme; mode switching has a soft gradient, and the window’s minimize, maximize, and close buttons directly follow the current mode.

Areas with built-in backgrounds are handled separately: Markdown code blocks, terminal cards, JSON and search results use the foreground color based on the background color in both modes, including uncolored literals like parentheses, braces, $variables, and punctuation. They share the same foreground with highlighted fragments and will not become the same color as the background or disappear.

Below the input box is a memory badge showing the computer’s memory usage rate. Clicking it allows viewing total system usage, used usage, and DSH process usage. On Windows, it summarizes processes by current executable filename; on other platforms or when read fails, it only shows the Host process. Other processes with the same name may be counted in Windows’ summary, which is a known behavior.

Conversation Background

The package provides ten sets of numbered assets. Each set contains a PNG static image and an MP4 animation of approximately 11.82 seconds. The video uses H.264 encoding, and the client only plays the final cut without needing to load the Cubism SDK. The main image is centered according to the full composition, and edges with inconsistent ratios are filled with the same image using soft blur, no longer expanding outward with blur.

Images and videos are stored in assets/backgrounds/, with filenames ranging from luna-1.png/luna-1.mp4 to luna-10.png/luna-10.mp4. They are provided by the Host to the client at runtime; no local directory access is needed after installation for creating assets.

There are two notable design aspects regarding background behavior.

First, changes in the settings panel only modify the draft by default. Clicking “Save” writes to the current configuration document and applies it at once, persisting after refresh and syncing to connected clients; editing controls, pressing Enter, leaving the input box, or clicking “Restore Defaults” only modify the draft and do not change the currently playing background. Closing the panel or leaving the background section discards unsaved drafts.

Second, rotation and fade-in/fade-out are timed separately. The rotation order is fixed as 1 → 2 → … → 10 → 1, independent of the single video loop duration; when switching, the previous image is retained, and a cross-fade of up to 1000ms is applied after the new asset is ready. After the fade ends, the old video and scene are released, keeping at most two scenes simultaneously. If video playback fails, the corresponding PNG is used.

Configuration fields and default values:

Configuration Field Function Default Value
animated Enable character animation, shows static image when disabled true
mask Brightness/Contrast theme mask strength, 0–100% 56
blur Background blur radius, 0–24px 2
transparency Background opacity, 0% fully visible, 100% fully transparent 0
backgroundMode rotate rotate by number, fixed fixed background rotate
rotationSeconds Display time per background, integer seconds, minimum 12 seconds 30
backgroundId Resource id selected in fixed mode luna-1
transitionMilliseconds Background cross-fade time, 0–5000ms 1000

The resource directory resources/backgrounds.json defines stable id, numeric order, Chinese and English names, poster, optional video, loop duration duration, and content revision revision. The Host provides /dsh-luna/backgrounds/<id>.* routes supporting Range and HEAD. The URL includes revision to refresh the cache when replacing the final cut. The aliases in the directory map the previously saved old id luna-v08 to luna-1, so old media does not need to be retained. When adding new backgrounds, add directory entries and resources, then run npm run build to update the background module and directory snapshot inside lib/client.js.

Luna Balance Widget

The avatar is a minimalist image with a transparent background, silver-white long hair, and red capsule-shaped eyes, paired with a separate white balance box and displayed horizontally mirrored. The bubble displays the amount and billing period in a larger font. Clicking the character refreshes the balance; dragging allows moving and snapping to the left or right edges of the screen. When the mouse is near, buttons for switching, collapsing, zooming in, and zooming out appear. Operations are also displayed when focused via keyboard; they remain visible on touch screens.

There are two paths for balance retrieval: prioritize querying the official balance interface using the DEEPSEEK_API_KEY configured in DSH; if that key is missing, switch to the currently logged-in DeepSeek account, adding the amounts of the recharge wallet and bonus wallet for display. The key must be a DeepSeek official API key; keys from other service providers cannot query this interface. Balance queries include retrying and account fallback, with a total time limit of 20 seconds. Neither the key nor the account token are sent to the page.

“Today’s Used Amount” requires logging into a DeepSeek account. It reads the platform usage bill from 00:00 (Beijing Time) of the current day to 00:00 of the next day, aggregating the amounts for all API Keys and models of the account, including consumption outside of DSH. Configuring only the API key allows viewing the balance, but the platform bill cannot be queried. Amounts are displayed in RMB first; otherwise, USD is displayed; the two currencies are not summed. The currently selected amount updates every minute and can be manually refreshed by clicking the character.

Below the bubble, a permanent billing period display shows: “Idle Period” in green, “Peak Period” in red, regardless of whether the amount query is successful. Peak hours are judged as Beijing Time workdays 09:00–12:00 and 14:00–18:00; 12:00 and 18:00 are considered idle. Weekends (including make-up workdays) and Chinese public holidays are entirely idle. The plugin comes with 2026 holiday data; the calendar needs to be updated for the new year; for years not covered, the peak window displays “Time Pending Confirmation”.

Dimensions are saved in luna-widget-size.json in the current profile. It is compatible with the old .dshw-size.json in the package root when reading. New modifications are only written to the profile and persist after replacing the installation package. The diagnostic log luna-theme-ping.log is also saved in the profile. The collapsed state is only retained on the current page.

Asahi Pet

Asahi moves at the bottom of the window, supporting drag, throw, bounce, click reaction, napping, and task status linkage. Twelve actions (idle, wave, thinking, working, waiting, happy, sad, surprise, sleep, drag, walk-a, fall) are transparent animations rendered by the actual Cubism Core using Live2D models, played as segmented sprite sheets at 30fps. The page only decodes the current and next segment, keeping at most three decoded sprite sheets; when switching resources, the previous frame is retained. In dynamic effect reduction mode, the first frame of the current action is displayed; action time pauses in the background.

Resources are located in assets/pet-live2d/, totaling 2592 frames and 217 segmented sprite sheets, including left and right directions for walking. The client plays the offline rendering results and does not need to load the Cubism SDK. After a segmented sprite sheet fails to load, it retries after 0.5s and 1s respectively; after failing three times in a row, it retries the needed sheets every 30 seconds. If it fails three times in a row, it temporarily uses the original static pose or the eight-frame sprite sheet and automatically continues the new animation after the sprite sheet is restored.

Walking uses two sets of stationary gaits, left and right, and frames are selected based on actual movement distance. Screen displacement is handled by the plugin, keeping the character facing forward and no longer switching to side profiles or mirroring the character. Ground translation only advances when actually displaying a walking action; it pauses during waving, surprise, task status, and other non-walking actions. The right-click menu provides chat, switch model, clear context, adjust size, return to corner, stay put, and sleep a while; position, size, napping, and movement preferences are saved in browser localStorage.

Pet chat uses the model configured in DSH and consumes the corresponding model quota; replies are displayed as streaming text. The chat route uses the application’s request authentication; if the authentication service is missing, requests are rejected. Personality system prompts are provided with the package in persona/asahi-chat.md. This group of chats does not write to the DSH Session, and the theme does not register model tools.

Splash Animation

After the app loads, the view point gradually pulls back from a central close-up, and characters from the outside enter the frame while maintaining front and back occlusion. Once the camera is in position, the three-layer original logos unfold in sequence. Light mode uses Back_1.png, dark mode uses Back_2.png. The default entry and dwell time is 7.6 seconds, followed by 1.4 seconds of fading to black; the lun_sp06.wav is played only after the screen is completely black and drawn, waiting for the actual voice playback to end before exiting the splash screen. The total normal playback duration is about 11.6 seconds, plus asset loading time.

Clicking the screen or pressing Esc can skip it, and it is also effective during voice playback. When the browser blocks autoplay, a black screen displays “Play Voice”; retry is provided if images or audio fail, and clicking the blank screen can also skip. When the system enables reduced dynamic effects, the completed composition is displayed directly, shortening the dwell and fade-to-black, but still waiting for the voice to end. Content is uninteractive during the splash screen; exiting or uninstalling stops the voice, retracts the mask, and restores the original focus and interaction state.

Installation and Enablement

The plugin is distributed as a DSH bundle. The installation method given in the README is: install to the target profile, restart the application to load the theme and components; no command line installation command is given. The community directory page provides an installation entry; the method is to visit the plugin directory page and follow the page instructions to install to the target profile. Since this involves running the plugin with the current dsh process permissions, it is recommended to read the source code first and confirm the installation method given on the directory page.

After installation, the four row ids in cordis.patch.yml of the profile correspond to different functions:

Row ID Function Package Entry
dsh-luna-theme Colors, materials, background animation, and memory badge dsh-luna-theme
luna-balance-widget Luna balance widget dsh-luna-theme/widget
luna-pet Asahi pet and chat dsh-luna-theme/pet
luna-opening Splash screen skin, camera pull-back, and voice dsh-luna-theme/opening

The three components can be disabled individually by setting disabled: true based on the row id:

- id: luna-opening
  disabled: true

After adjusting Host component configuration, the application needs to be restarted. Disabling the theme main row will simultaneously revoke the theme styles, background animations, and page scripts loaded by it. The splash screen is provided with the theme and does not require a separate splash screen plugin.

Typical Usage

Only view balance, no pet or splash

In the profile’s cordis.patch.yml, keep the theme main row and balance widget, and disable the remaining two:

- id: luna-balance-widget
  disabled: false
- id: luna-pet
  disabled: true
- id: luna-opening
  disabled: true

After restarting, only the color scheme and balance widget are loaded, and the pet and splash will not occupy resources. The balance part will automatically downgrade to the logged-in account when there is no DEEPSEEK_API_KEY, and the balance can also be seen in scenarios where only an account has been logged in but no key has ever been applied.

Fix a background and slow down rotation

In DSH “Settings → Background”, change backgroundMode to fixed, specify backgroundId as luna-3, and set rotationSeconds to 60. Changes only take effect after clicking “Save”; leaving the input box or clicking “Restore Defaults” only modifies the draft and does not change the playing background. Rotation interval does not accept empty values, decimals, or values less than 12 seconds.

Adjust the look and feel of background and theme

To lower the background’s presence, set blur to one of the 0–24px levels, raise transparency to 30 or above, and lower mask to below 56. These take effect after saving. These only apply to the conversation background and do not change the images and controls in the settings panel.

Configure background with external editor

backgroundMode, rotationSeconds, and backgroundId can be modified via the main plugin ConfigForm; preferences and resource type definitions are in src/shared/background-types.d.ts.

Development and Build

The source code is separated by Host and Client, and further categorized by background, balance widget, pet, and splash. Public entry points are dsh-luna-theme, /client, /widget, /pet, /opening, /backgrounds, and /background-types. After installing the runtime and development dependencies declared in package.json, execute in the plugin directory:

npm run build
npm run build:check
npm test

build collects local modules, styles, directories, and setting images from src/client/index.js, generating a lazy CommonJS client supported by DSH; build:check only checks if the product is consistent with the source code and does not rewrite files. The Host directly runs the ESM source files. Rebuilding is required after modifying source code, background directory, or setting images.

tests/ saves entry points, resource routes, and persistent regression tests; it is only used for development verification and is not included in the package.json publish manifest; user installation packages do not contain test files.

Applicable Scenarios and Notes

Suitable for developers who want to change the DSH interface to a personalized appearance while hoping to keep the desktop and web sides consistent, or for users who need to run the desktop side for a long time and want to see balance and model usage consumption. It is a purely interface decoration plugin and does not provide business process capabilities.

A few points need attention.

The plugin runs with the current dsh process permissions. The Host side reads credentials (balance query needs DEEPSEEK_API_KEY or the token of the logged-in account), provides /dsh-luna/backgrounds/<id>.* routes, and loads the client script. Before installation, check the source code and license to confirm the installation method given on the directory page matches expectations.

Pet chat consumes the quota of the model configured in DSH; this round of chat history is cleared when closing the window or clearing context and is not written to the DSH Session.

Regarding assets, the code uses the MIT License. The balance widget code is derived from MeteorNOX’s DeepSeek-Balance-Whale-Widget; see THIRD-PARTY-NOTICES.md for license and modification notices. Illustrations, characters, logos, voice, and other assets are owned by Navel; the MIT License does not cover these assets, and the plugin is for personal non-commercial interface decoration.

Sound effects and animations are sensitive to browser autoplay policies: when blocked, a black screen displays “Play Voice”; retry or skip is provided if asset loading fails.

Conclusion

dsh-luna-theme bundles skinning, background, balance widget, pet, and splash into one package, using row ids to control the loading range. The behavioral boundaries are also detailed: draft and saved configuration are separated, rotation and loop timing are independent, timers and media are released when the theme is disabled, and chat does not write to Session. For developers who want to transform the DSH appearance, it is easier to maintain than scattered custom components; the only thing to watch out for is the scope of asset copyright and the necessity review brought about by running with process permissions.

Plugin Directory Page: https://www.skillhub.cn/plugins/shinku-xuan/dsh-luna-theme

GitHub: https://github.com/shinku-xuan/dsh-luna-theme

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye