DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Rail Equalizer — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins
R

dsh-rail-equalizer

Rail Equalizer

Make DSH’s “Round Navigation” rail pulse in real time with the sound currently playing on the system (Windows). The host uses WASAPI loopback capture, requiring no permissions, showing no prompts, and never accessing the microphone; the browser side only injects CSS variables without modifying offic

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add github:yuanyiHY/dsh-rail-equalizer#07a3eedf444205f6c900bb68eb207026027a7f59
READMECompatibilityVersions
轮次导航跟着系统声音律动侧栏里的「律动」开关

Description

Make DSH’s “Round Navigation” rail pulse in real time with the sound currently playing on the system (Windows). The host uses WASAPI loopback capture, requiring no permissions, showing no prompts, and never accessing the microphone; the browser side only injects CSS variables without modifying official components, and fully restores the default styles when disabled.

Compatibility and provenance

Rail Equalizer is published as dsh-rail-equalizer and currently resolves to version 0.1.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
github
Registry updated
9/16/2026

Versions

0.1.0stable
9/16/2026

Related plugins

Loading related plugins…

Latest
0.1.0
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
Unavailable
Files
Unavailable
Surface
web
License
MIT
Source
github
GitHub
★ 0
Weekly downloads
0
Last push
9/16/2026
View source ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

Related plugins

More verified plugins in ui-customization.

Web App@deepseek-ai/dsh-web-appThe dsh browser-surface bundle: the web patch layer over dsh-base plus the runtime glue plugin (frontend dist serving, web-surface prompt, bash runtime variables, URL line)Experimental Agent Team Web Profile@deepseek-ai/dsh-experimental-agent-team-web-profileExperimental Web profile layer for Agent Teams Remote and UI pluginsRemote Web Ui@linxin666/dsh-remote-web-uiScan-to-pair remote access for the dsh web GUI that shares one official interface: a QR beside the settings button pairs phones and PCs into the same Web GUI (a portrait-touch adaptation layer for phones, full desktop on PCs) through one-time tokens and rClient Ui Task Board@linxin666/dsh-client-ui-task-boardHost-authoritative task board for the DSH Web GUI with real session execution, Host cron scheduling, and optional cross-platform idle-sleep protection; mounted without DSH source changes.

README

dsh-rail-equalizer

让 DSH 的**「轮次导航」导轨**(聊天右侧那根刻度条)跟着系统正在播放的声音实时律动。

放音乐、放视频、打游戏 —— 只要声音是从这台电脑的默认播放设备出来的,导轨就会跟着动。 不需要任何授权、不弹任何窗口、不碰麦克风、不录屏,戴耳机照样工作。

轮次导航跟着系统声音律动

侧栏里的「律动」开关

仅 Windows。 音频采集层依赖 WASAPI。英文说明见 README.en.md。


它是怎么拿到声音的

这是本插件唯一"重"的地方,值得说清楚。

浏览器的 getDisplayMedia(屏幕共享)做不到"一次授权" —— 这是 Chrome/Edge 刻意的安全设计:每次调用都必须重新选一次共享目标,权限不做持久化,没有任何 API 能绕过。而麦克风方案在戴耳机时完全无效。

所以本插件走的是宿主端 WASAPI 回环:DSH 的宿主进程(Node)通过 koffi 直接调用 Windows Core Audio 的 COM 接口,抓默认播放设备正在渲染的 PCM。

IMMDeviceEnumerator.GetDefaultAudioEndpoint(eRender)
  → IMMDevice.Activate(IAudioClient)
  → IAudioClient.Initialize(AUDCLNT_STREAMFLAGS_LOOPBACK)
  → IAudioClient.GetService(IAudioCaptureClient)
  → 轮询 GetBuffer / ReleaseBuffer

和 OBS 抓桌面音频是同一个机制。它不是"录音",是在读系统混音器已经把声音交给声卡的那份数据,所以:

  • 没有任何"权限"概念需要向谁申请
  • 耳机 / 音箱 / HDMI / 虚拟声卡,抓的都是默认播放设备(你在系统里切输出,它跟着切)
  • 只读,不写入、不改变音量、不影响任何正在播放的程序
  • 音频数据只在内存里过一遍算电平,不出这台电脑、不落盘

koffi 通过 optionalDependencies(@koromix/koffi-win32-x64)分发预编译二进制,装包即用,不需要 Visual Studio / node-gyp / 任何编译工具链。

它是怎么做到"不动原组件"的

官方导轨由 @deepseek-ai/dsh-client-ui-chat 渲染。本插件没有 patch、没有 fork、没有替换它的任何代码或组件。

浏览器半只做四件事:

做什么具体
打一个标记往导轨的 <nav> 上加 data-dsh-eq 属性
注入一张样式表一个 <style> 标签,全部靠 CSS 覆盖(两套构建的横条选择器都覆盖)
写几个变量document.documentElement 上的 --dsh-eq-*
画一个控制行侧栏那一行是纯 DOM(insertBefore 插进文档流);展开的设置面板走官方 shell.overlay 插槽

为什么这不可能破坏功能:

  1. 律动只作用于可见的那根横条,而且只叠加 scale / filter / box-shadow 三个属性。 官方导轨在不同 DSH 构建里画横条的方式不一样,两种都覆盖:
    • 新构建:横条是真实的 <span class="…_tick">,它的尺寸/透明度/配色由 React 写成内联样式。 内联样式优先级很高,所以绝不能去改这四个属性 —— 改用独立的 scale 属性叠加: scale 与 transform 是两个互不覆盖的属性(最终矩阵 = translate × rotate × scale × transform), 元素原有的内联尺寸与四态差异一像素都不会动。
    • 旧构建:横条是 button 的 ::before 伪元素,那里用 transform: … scaleX() scaleY() 叠加。 两套选择器各自只在对应构建里命中,互不干扰。
  2. 无论哪种构建,都不碰 width / height / opacity / background-color —— 官方四态(当前 / 悬停 / 未加载 / 生成中)的尺寸与配色差异一个都没被改。
  3. 变形从 1 起算(静止即恒等变换),filter 从 brightness(1) 起算,无辉光时 box-shadow 不画 —— 电平静默时视觉效果就是原样。伪元素与 scale 都不参与布局,也不会出现在 getBoundingClientRect() 里, 所以导轨的滚动、坐标定位、点击跳转在几何上完全不受影响。
  4. 只叠加 filter: brightness() 与 box-shadow,不动 background / color,主题 token 原样生效。
  5. 正在生成的那一轮带 aria-busy="true",样式表显式把它排除在行波动画之外 —— 它自己那条"呼吸"表现一点没被覆盖。
  6. 每个刻度的行波相位用 nth-child 静态生成 CSS(设在行容器上靠继承下发),完全不往 DOM 里写东西,不会和 React 的渲染打架。
  7. 关闭 = 移除属性 + 移除样式表 + 清空变量,三件事一起做。关掉之后导轨和没见过这个插件完全一样。

安装

仅 Windows。 音频采集层依赖 WASAPI,package.json 里也声明了 os: ["win32"],所以在 macOS / Linux 上会被包管理器直接拒装,而不是装完再崩。

dsh plugin --profile desktop add github:yuanyiHY/dsh-rail-equalizer

装完重启 DSH Desktop(宿主进程要重新加载 bundle 才会注册路由)。

从源码 / 本地目录安装(改代码即时生效)

git clone https://github.com/yuanyiHY/dsh-rail-equalizer
dsh plugin --profile desktop add link:<克隆到的绝对路径>

⚠️ 安装路径里不能有空格 —— dsh plugin 会把参数转给 pnpm,带空格的路径会被切碎成多个包名。本地开发建议放在 ~/.dsh/local-plugins/ 这类没有空格的目录下。

不需要编译工具链。 koffi 虽然带一个 install 脚本,但原生二进制是打包在 optional dependency(@koromix/koffi-win32-x64)里的,脚本没执行也能正常加载。pnpm 若提示需要授权构建脚本,跳过不影响使用。

卸载

dsh plugin --profile desktop remove dsh-rail-equalizer

重启后宿主侧的采集与路由完全消失。浏览器侧因为插件不再加载,什么都不会注入。 也可以只点侧栏那一行的开关关掉 —— 效果等同,且立刻生效。

使用

侧栏里、官方「工作区」区块正上方会出现一行:

┌──────────────────────┐
│ ♪  律动        [ ⬤ ] │   ← 点整行(开关以外)展开 / 收起设置面板
└──────────────────────┘      点右侧开关 → 直接开 / 关

这一行是插进侧栏文档流的(insertBefore 到 [class*="_regionArea"] 之前), 用和生态里其它插件(如技能中心)一样的做法,并带自愈:React 重渲染把它挤掉就重新插回去。

为什么不注册进官方插槽? 侧栏唯一位置合适的 sidebar.workspaces 是 kind: "single" —— 往里注册会顶掉官方的工作区区块。而侧栏其余插槽(sidebar.settings / sidebar.brand.*)也都是 single。 所以只能插 DOM,这也是其它侧栏插件共同的做法。

为什么不用浮层(position: fixed)? 试过,不行 —— 浮层会盖住同样插在这一区域的 其它插件(技能中心那一行就是这么被盖没的)。插进文档流后各占各的位置,谁都不挡谁。

也没有单独的齿轮按钮了 —— 免得和 DSH 自己的设置齿轮撞脸。设置面板只在展开时出现, 定位到这一行的右侧(--dsh-eq-pill-x/y 由 JS 实测写入)。

设置面板里:

项目说明
总开关关掉后导轨完全恢复默认样式(样式表被移除,不是"置零")
运动方式四选一,即时生效,见下表
灵敏度0.4–3.0。系统音量小、音乐本身轻的时候往上调
强度0.2–2.0。整体变形幅度
低频冲击0–2.0。鼓点让刻度纵向"砸"下去多少
行波只在「行波」模式下有意义:关掉则波浪不跑,刻度原地起伏
波速行波周期,0.46×–2.4×(滑杆值 2600–500ms)

四种运动方式

用现有的 N 根刻度当素材,四种完全不同的运动模型:

方式观感驱动量
频谱(默认)每根刻度长度 = 它负责的那段频率,低音→高音依次排开,像音乐播放器的频谱条--dsh-eq-v(该刻度分到的频段)
脉动所有刻度同相位,整排一起伸缩呼吸,最"齐"--dsh-eq-lvl + 全局动画相位
摆动刻度本身不变形,整条导轨左右往复摆动--dsh-eq-sw × 电平
行波每根刻度错开相位,一条波沿轨道向上跑--dsh-eq-lvl + 每刻度相位

频谱模式是唯一的"真频谱":宿主端跑 2048 点 FFT + Hann 窗,把 40Hz→16kHz 按对数切成 16 段(和听感一致),客户端再按实际刻度数把 16 段均匀铺到 N 根刻度上 —— 所以 5 根刻度也能看到从低到高的完整分布,50 根刻度就是一根根连续的频谱。

客户端会热重载、宿主不会,所以可能出现「客户端新版 / 宿主旧版」。此时没有频段数据,频谱模式会自动降级成整排一起动,而不是完全不动。自检里的 bandsAvailable 会告诉你当前是哪种。

面板底部有实时电平条和后端状态(设备格式 / 连接状态 / 出错原因)。设置存在浏览器 localStorage(键 dsh-rail-eq:settings:v1)。

CPU 与省电

  • 采集是按需的:有浏览器连上 SSE 流才开始抓,最后一个断开后 8 秒自动停。页面没开时这个插件完全不占 CPU。
  • 实测解码开销约 2 ms/s CPU(48kHz 立体声 float32),可以忽略。
  • 电平以 ~30Hz 经同源 SSE 推送;浏览器侧再用 requestAnimationFrame 平滑到屏幕刷新率。
  • 尊重系统的**「减少动态效果」**(prefers-reduced-motion):此时只保留柔和的亮度起伏,不做变形与行波。

出问题怎么办

导轨完全不动

  1. 点侧栏那一行展开设置面板,看底部状态:
    • 采集失败:... → 看下面「常见报错」
    • 已连接,等待音频… → 链路是通的,只是系统此刻没在放声音
    • 连接中… → 宿主路由没起来,八成是没重启 DSH
    • 当前平台不支持(仅 Windows) → 预期行为,本实现是 Windows 专用的
  2. 确认声音确实是从默认播放设备出来的。有些播放器可以指定独立输出设备,如果它绕过了默认设备,就抓不到。
  3. 确认导轨还在页面上(轮次导航是官方组件,官方改名/移除的话本插件会静默不生效,不影响其它功能)。
  4. 还是没效果 → 看浏览器半的自检。宿主侧看不到 DOM,所以浏览器半会把自己的状态回传给宿主, 读 GET /rail-eq/status 里的 clientReport 字段,能看到: railFound(找没找到导轨)、matched(CSS 选择器命中没有)、mode / tickCount(当前模式、数到几根刻度)、 bandsAvailable(宿主有没有在发频段数据)、vars(电平变量写了多少)、 tick.scale / tickRect(横条被拉伸成多大)、uiRendered(标题栏按钮有没有真的被渲染)。 排查「装了但没效果」这一类问题,这个字段通常一眼就能定位。

Initialize(LOOPBACK) 失败 0x88890008 —— 该设备不支持回环(少见,某些独占模式/虚拟声卡)。切一个默认输出设备再试。

不支持的混音格式 tag=... —— 设备的混音格式既不是 IEEE float32 也不是 PCM16。把默认播放设备的格式改成 16bit/24bit、44100/48000Hz 通常能解决。

手动重启采集(换过播放设备之后):

curl -X POST http://127.0.0.1:<DSH端口>/rail-eq/restart

正常情况下不需要 —— 采集出错会自动重试。

调试用的接口

路由用途
GET /rail-eq/status完整状态:是否在采集、音频格式、包数、客户端数、当前电平
GET /rail-eq/level单发当前电平,不会启动采集
GET /rail-eq/streamSSE 电平流(浏览器半用的就是它)
POST /rail-eq/restart重启采集
POST /rail-eq/report浏览器半自检回传(排「没效果」用,结果出现在 /status 的 clientReport)

开发

lib/
  index.js     宿主半:SSE 路由 + 采集生命周期(Cordis 插件)
  wasapi.js    WASAPI 回环采集(koffi 直调 Core Audio COM)
  analyzer.js  PCM → 4 个时域电平 + 16 段对数频谱(2048 点 radix-2 FFT + Hann 窗,快攻慢放包络)
  client.js    浏览器半:导轨绑定 + CSS 变量 + 控制 UI
test/
  host-integration.mjs  宿主端集成测试(不需要 DSH 重启)
  band-probe.mjs        单点频段探针(验证某个频率落在哪一段)
  make-tone.mjs         生成测试音

宿主半是纯 ESM,浏览器半是 window.__ModuleLoader__.load({ id, factory }) 形态的静态 bundle,都不需要构建步骤。改完 lib/*.js 重启 DSH 生效。

跑测试(有声音在放时最有意义):

node test/make-tone.mjs 30
# 另开一个窗口播放 test/tone.wav,然后:
node test/host-integration.mjs

测试会覆盖:路由分发、404、按需采集(单发探活不该启动采集)、SSE 头与推流、status 补发、电平数值健康度、四频段独立性、频谱结构(最强段显著高于中位段)、断开后自动停机、dispose 清理。

koffi 踩过的两个坑

  1. 输出参数不是返回值数组。 koffi 里 _Out_ 参数要传一个容器([null])进去,原生代码把结果写回容器,函数返回值就是 C 的返回值(这里是 HRESULT)。
  2. COM vtable 要手动解引用。 koffi.decode(obj, 'void *') 拿到 vtable 指针,再 koffi.decode(vtable, index * ptrSize, 'void *') 拿到方法指针,最后 koffi.call(fn, proto, obj, ...)。proto 的第一个参数是 this。

已知限制

  • 仅 Windows。 音频采集层依赖 WASAPI。macOS 可以用 ScreenCaptureKit 或虚拟声卡,没有实现。
  • 抓的是默认播放设备。 播放器如果指定了独立输出设备,抓不到。
  • 导轨的定位靠语义锚点(nav + button[class*="_mark"],优先用 aria-label),不依赖中英文案也不依赖哈希类名。官方若大改导轨 DOM 结构,findRail() 一个函数就能修。
  • 没有接入 DSH 的 locale 命名空间,界面文案是中英混合。