dsh-claude-style 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,82 @@
2
2
 
3
3
  All notable changes to `dsh-claude-style` are documented here, newest first.
4
4
 
5
+ ## [0.10.2] - 2026-09-30
6
+
7
+ [中文](#cn-0.10.2) | [English](#en-0.10.2)
8
+
9
+ <h3 id="cn-0.10.2">新增功能</h3>
10
+
11
+ - **设置页新增「动画效果」,三档可选**:「随系统」跟随 Windows 自己的「显示动画」设置(原来的行为);「减弱」把动画停在代表帧上、界面的过渡压到瞬时;「总是」无论系统怎么设置都播放动画。系统设置中途变化时立即按新值生效。后台任务的转圈在三种设置下都照常转动,停住的圈读起来像坏了而不是安静。
12
+
13
+ ### 体验优化
14
+
15
+ - **小鲸鱼 Deepy 的帧图改为浏览器端矢量化播放**:每张动画表图第一次被用到时,在页面里把 PNG 像素重建成 SVG(按颜色合并同行游程)再播放——浏览器按显示尺寸栅格化矢量,内存里只留显示大小的小图(原先整张大位图常驻,18 张全解码的理论上限约 144 MB),且任意屏幕缩放比例下都锐利。转换结果以表图自己的内容戳为键缓存,一张表只有自己的像素变了才重转;转换失败的表按原 PNG 播放,与之前行为一致。实测每张表的一次性转换约 50–95 毫秒,生成的矢量与原图逐像素一致。
16
+ - **流式输出期间界面的每帧开销约减半**:一轮功能刷新的实测中位耗时从 6.6 毫秒降到 3.0 毫秒(p90 从 9.4 降到 3.2,同页同法对比)。三处改动:思考档位开关的摆放原来每轮都「写外边距再读位置」强制两次重排,现在只在档位文字变化时量一次、位置值不变不写(该功能单轮耗时 2.24 → 0.007 毫秒);上下文计量环的宽度原来每轮读取(流式期间等于每轮一次强制布局),现在只在百分比读数或重绘范围变化时量;其余功能的刷新维持「只读必要节点、只写变化值」。
17
+ - **小鲸鱼 Deepy 的播放交给浏览器的动画引擎**:换帧从「每 50 毫秒一次定时器改写 background-position(每帧一次主线程重绘)」改为「胶片条 transform 平移 + WAAPI steps 关键帧」——循环动画播放期间主线程完全没有 JS 运行,换帧只走合成器。状态机、减弱动态效果下的静止帧、点击戳刺与抬起反应的行为不变;冒烟测试核对帧在前进、且不唤醒任何界面刷新。
18
+ - **DeepSeek 档的亮色背景蓝更淡**:亮色画布由 `#F7FAFF` 换成 `#FAFBFF`,侧栏 `#F7F9FF`,各层底色、分段控件与开关底板、表头、滚动条按同样的幅度调淡,整页的蓝现在只是白底上的一层色调。暗色配色不变。
19
+ - **会话的数字收进上下文弹层,输入行不再挂那行小字**:输入卡片下方原来那行「2 轮 158 步 · 242 tok/s · 32M tok · 缓存命中 99%」及其悬停展开的卡片一并去掉;这些数字(模型用时、工具调用用时、首 token 平均、输出速度,以及缓存命中、未缓存输入、缓存读取、输出)现在追加在上下文计量环的弹层里,排在宿主自己的上下文明细下方,弹层开着的时候跟着会话实时更新。该弹层改为悬停弹起(跟随「悬停打开弹层」偏好,指针离开即收起),点击打开也照旧可用;它本来是「啪」地出现,现在与皮肤自建的卡片一样淡入上浮。数字还没到时,那块位置先按同样的高度占住(两个小标题下面是与真实行等高的占位条),不会出现弹层先矮后高;占位最多保留 2 秒,之后让位给宿主自己画的版面。
20
+
21
+ ### 问题修复
22
+
23
+ - **已归档列表的会话标题不再默认是黑色**:静止时与进行中的会话一样用次级灰,只有指针停在行上或键盘焦点进入行时才是主文字色。
24
+ - **桌面端封号彩蛋页不再重复出现窗口按钮,Claude 标贴着顶栏**:Windows 桌面壳的最上面一行是系统层,它自己画了最小化、最大化、关闭三个按钮;彩蛋页以前又画了一套,顶栏上于是出现两排按钮。现在这页不画自己那套,星芒标与字标、「退出登录」直接排进系统顶栏那一行,那一行也跟着页面换成象牙白或暖黑;按住这一行的空白处仍然可以拖动窗口。
25
+ - **封号彩蛋页在 DeepSeek 档下也显示 Claude 标**:以前选 DeepSeek 时页面上只剩「Claude」文字、旁边的星芒被去掉;这页复刻的是 Claude 自己的界面,现在两档都画完整的 Claude 字标。
26
+ - **账号弹层不再先贴着底部出现再往上跳**:宿主的账号卡片挂载时只带它自己那三行,皮肤的行晚一帧进入,卡片随之变高,宿主再晚一帧按新的高度重新摆位。此前这次重新摆位发生在卡片已经淡入到约三分之一的时候,于是看到的是它先停在偏下的位置、再跳上去。现在卡片在皮肤的行走位完成之前不上色,入场动画从它最终的高度与位置开始播放。
27
+
28
+ ### 移除
29
+
30
+ - **删除 Anthropic 品牌档**:设置页「修改品牌标识」只剩 DeepSeek 与 Claude 两档;已经存过 `anthropic` 的设置读作 Claude(这一档的标识与配色本来就与 Claude 相同)。
31
+
32
+ ### 其他变更
33
+
34
+ - **README 的小鲸鱼介绍附上动图**:「特点」里小鲸鱼 Deepy 一条下面加了八张 GIF,分别是空闲、思考、写回答与调用工具、指挥子代理、等你操作、失败、完成与睡着。仓库里的 Deepy 展示页因体积过大(约 7.6 MB)移除,全部 20 个动画的 GIF 仍在 `showcase/gifs/`。
35
+
36
+ <h3 id="en-0.10.2">New Features</h3>
37
+
38
+ - **A new Animation setting with three choices**: Follow the system keeps Windows' own "show animations" setting in charge (the previous behaviour); Reduced holds every animation on its still frame and takes the interface's transitions down to nothing; Always plays them whatever the system says. A change to the system setting lands immediately. The background-work ring turns in all three, since a still ring reads as broken rather than as calm.
39
+
40
+ ### Improvements
41
+
42
+ - **Deepy's animation sheets now play as vectors generated in the browser**: the first time an animation is wanted, its sheet's PNG pixels are rebuilt as SVG (same-color runs of a row merged into one path per color) and that vector is what plays — the browser rasterizes it at the size the whale is drawn, so memory holds only that small image (the sheets used to stay decoded whole, with a theoretical ceiling around 144 MB for all eighteen), and the whale is sharp at every display scale. Generated vectors are cached under each sheet's own content stamp, so a sheet is re-converted only when its own pixels change; a sheet that decodes but does not convert plays as the PNG it came from, exactly as before. Measured locally: a one-time 50–95 ms per sheet, and the generated vector is pixel-identical to the source.
43
+ - **The per-frame cost of streaming is roughly halved**: a measured feature-refresh pass went from a 6.6 ms median to 3.0 ms (p90 from 9.4 to 3.2, same page, same method). The effort control's placement used to force two reflows per pass (write a margin, read the box back); it now measures only when the level's label changes and writes only moved values (that feature alone went from 2.24 ms to 0.007 ms a pass). The context meter's width used to be read every pass — a forced layout each pass while streaming — and is now re-measured only when the percentage reading or the restyle scope changes.
44
+ - **Deepy now plays on the browser's animation engine**: frame changes move from a 50 ms timer rewriting background-position (a main-thread repaint per frame) to a filmstrip translated by WAAPI steps keyframes — while a loop plays, no JS runs on the main thread at all and frames composite instead of repaint. The state machine, the still frames under reduced motion, and the poke/lift reactions behave exactly as before; the smoke suite checks that frames advance without waking a single skin pass.
45
+ - **A paler blue behind the DeepSeek brand's light palette**: the light canvas moves from `#F7FAFF` to `#FAFBFF`, the sidebar to `#F7F9FF`, and the raised layers, segmented-control and switch plates, table headers and scrollbars step back with them, so the blue now reads as a tint on white. The dark palette is unchanged.
46
+ - **The session's numbers moved into the context popover, and the composer row no longer carries them**: the "2 turns 158 steps · 242 tok/s · 32M tok · Cache hit 99%" line under the input card and the card it opened on hover are both gone; those numbers (model time, tool-call time, average time to first token, output speed, and cache hits, uncached input, cache reads, output) are appended to the context meter's popover, under the host's own context rows, and follow the session while that popover stays open. The popover now opens on hover — following the "open popovers on hover" preference, and folding away when the pointer leaves — while a click still opens it, and it fades and rises in the way the skin's own cards do instead of popping. Until the numbers arrive, that block holds their height (bars as tall as real rows, under the two real headings), so the popover never opens short and grows; the place is held for at most 2 seconds, after which the host's own layout stands.
47
+
48
+ ### Bug Fixes
49
+
50
+ - **Archived conversations no longer rest in black**: an archived title sits in the same grey as the host's own session rows and takes the primary ink only while the pointer is on its row or the keyboard focus is in it.
51
+ - **The account-hold page on the Desktop no longer draws a second set of window buttons, and its Claude lockup sits on the titlebar row**: the top row of a Windows Desktop window belongs to the system, which paints minimize, maximize and close there; the page used to draw its own three as well, so the titlebar showed two rows of buttons. It draws none of its own now — the starburst and wordmark and the Sign out button take their place in that row, the row takes the page's ivory or warm black, and the window is still dragged by the empty part of it.
52
+ - **The account-hold page shows the Claude lockup under the DeepSeek brand too**: choosing DeepSeek used to leave the bare "Claude" text with the starburst dropped; the page reproduces Claude's own screen, so both brands now draw the full Claude lockup.
53
+ - **The account popover no longer appears against the bottom edge and jumps up**: the host mounts its card with its own three rows and places it from that geometry, the skin's rows arrive a frame later so the card grows, and the host re-places it a frame after that. That re-placement used to land when the card had already faded to about a third, so it read as appearing low and then jumping. The card now stays unpainted until the skin's rows are in it and its placement has settled, and the entrance animation plays from its final height and place.
54
+
55
+ ### Removals
56
+
57
+ - **The Anthropic brand choice is deleted**: the settings page's Brand mark row offers DeepSeek and Claude only, and a stored `anthropic` reads as Claude, whose marks and palette it already shared.
58
+
59
+ ### Chores
60
+
61
+ - **The README's Deepy entry now shows it moving**: eight GIFs sit under the Deepy item in Features — idle, thinking, answering and calling tools, conducting subagents, waiting on you, failed, finished and asleep. The repository's Deepy showcase page is removed for its size (about 7.6 MB); GIFs of all 20 animations remain in `showcase/gifs/`.
62
+
63
+ **Full Changelog**: [v0.10.1...v0.10.2](https://github.com/Nwflower/dsh-claude-style/compare/v0.10.1...v0.10.2)
64
+
65
+ ## [0.10.1] - 2026-09-28
66
+
67
+ [中文](#cn-0.10.1) | [English](#en-0.10.1)
68
+
69
+ <h3 id="cn-0.10.1">其他变更</h3>
70
+
71
+ - **README 预览换成 Claude 与 DeepSeek 两套配色的截图**:原来只有一组亮暗首页截图,现在两套配色各有工作台首页与一段 Markdown 对话(标题、列表、任务清单、表格、代码高亮、引用)的亮暗截图,共八张;截图里的工作区、会话、用量与昵称都是示例数据。
72
+ - **README 新增鸣谢**:注明像素小鲸鱼 Deepy 的动画帧图出自 calmly-eating-bugs 绘制的 Deepy 小鲸鱼主题包、经作者许可随插件分发,并附上作者贡献到仓库 `showcase/` 目录的展示页与 GIF 原件入口。展示页只在 GitHub 仓库里,npm 包的内容与体积不受影响。
73
+
74
+ <h3 id="en-0.10.1">Chores</h3>
75
+
76
+ - **README previews now show both the Claude and the DeepSeek palettes**: the single light/dark pair of the home page gives way to eight shots, each palette showing the Studio home page and a Markdown conversation (headings, lists, task lists, a table, highlighted code, a quote) in light and dark; the workspaces, sessions, usage and nickname in them are sample data.
77
+ - **README acknowledgements**: Deepy's animation frames are credited to the Deepy whale theme pack drawn by calmly-eating-bugs and shipped by the author's permission, with pointers to the showcase page and GIF originals the author contributed under the repository's `showcase/` folder. The showcase lives only in the GitHub repository; the npm package's contents and size are unchanged.
78
+
79
+ **Full Changelog**: [v0.10.0...v0.10.1](https://github.com/Nwflower/dsh-claude-style/compare/v0.10.0...v0.10.1)
80
+
5
81
  ## [0.10.0] - 2026-09-28
6
82
 
7
83
  [中文](#cn-0.10.0) | [English](#en-0.10.0)
package/README.en.md CHANGED
@@ -18,14 +18,39 @@
18
18
 
19
19
  ## Preview
20
20
 
21
+ The settings page's Brand mark row switches between the Claude and DeepSeek palettes, and light/dark follows your system's color mode. In each group the top row is the Studio home page and the bottom row a Markdown conversation, light on the left and dark on the right.
22
+
23
+ ### Claude
24
+
21
25
  <table>
22
26
  <tr>
23
- <td align="center" width="50%"><img src="./docs/light.png" alt="Light canvas — warm ivory" /></td>
24
- <td align="center" width="50%"><img src="./docs/dark.png" alt="Dark canvas — warm black" /></td>
27
+ <td align="center" width="50%"><img src="./docs/claude-home-light.png" alt="Claude brand, Studio home — light" /></td>
28
+ <td align="center" width="50%"><img src="./docs/claude-home-dark.png" alt="Claude brand, Studio home — dark" /></td>
29
+ </tr>
30
+ <tr>
31
+ <td align="center" width="50%"><img src="./docs/claude-conversation-light.png" alt="Claude brand, Markdown conversation — light" /></td>
32
+ <td align="center" width="50%"><img src="./docs/claude-conversation-dark.png" alt="Claude brand, Markdown conversation — dark" /></td>
25
33
  </tr>
26
34
  </table>
27
35
 
28
- > Light mode pairs an ivory canvas `#FCFCFB` with a pale sidebar `#FBFBF9`; dark mode uses warm black `#141413`. The theme follows your system's light/dark setting, and ember orange `#D97757` is the single action accent across both canvases.
36
+ > Light mode pairs an ivory canvas `#FCFCFB` with a pale sidebar `#FBFBF9`; dark mode uses warm black `#141413`. Ember orange `#D97757` is the single action accent across both canvases, and Claude Code's pixel crab stands on the Studio home page's composer.
37
+
38
+ ### DeepSeek
39
+
40
+ <table>
41
+ <tr>
42
+ <td align="center" width="50%"><img src="./docs/deepseek-home-light.png" alt="DeepSeek brand, Studio home — light" /></td>
43
+ <td align="center" width="50%"><img src="./docs/deepseek-home-dark.png" alt="DeepSeek brand, Studio home — dark" /></td>
44
+ </tr>
45
+ <tr>
46
+ <td align="center" width="50%"><img src="./docs/deepseek-conversation-light.png" alt="DeepSeek brand, Markdown conversation — light" /></td>
47
+ <td align="center" width="50%"><img src="./docs/deepseek-conversation-dark.png" alt="DeepSeek brand, Markdown conversation — dark" /></td>
48
+ </tr>
49
+ </table>
50
+
51
+ > Light mode is a white with a touch of sky blue, `#F7FAFF`, with the sidebar at `#F3F7FE`; dark mode is a blue-black `#13161D`. The accent is DeepSeek's brand blue `#4D6BFE`, and Deepy the pixel whale stands on the composer on the home page and in conversations alike.
52
+
53
+ > The workspaces, sessions, usage figures and nickname in the screenshots are sample data.
29
54
 
30
55
  ## Fonts
31
56
 
@@ -62,17 +87,32 @@ Keep only one theme enabled at a time. After installation, **restart `dsh web`**
62
87
 
63
88
  ## Features
64
89
 
65
- 1. **Theme** — applies globally the moment it is installed, with nothing to configure. Light mode uses ivory `#FCFCFB`, dark mode warm black `#141413`, and both share the same ember orange `#D97757` action accent; light/dark follows the system color mode. The settings page's Brand mark row offers DeepSeek / Claude / Anthropic: DeepSeek turns the whole palette blue — the accent becomes DeepSeek's brand blue `#4D6BFE` (buttons, switches, checks, links and the status line follow), the yellowish ivory light canvas gives way to a white with a touch of sky blue, `#F7FAFF` (sidebar `#F3F7FE`), the warm-black dark canvas to a blue-black `#13161D`, the hairlines and grey inks turn cool and user bubbles take a touch of blue; the sidebar and the home page keep the host's own DeepSeek whale and wordmark, painted DeepSeek blue, and the account row's picture without an avatar and a running turn's status line take DeepSeek's whale mark as well. The choice used to be labelled "Off", and a value stored under that name reads as DeepSeek.
66
- 2. **Composer** — the input box is rebuilt from the ground up: a permission segmented control (Read / Edit / Auto / Yolo) with its tier list under it, a model trigger carrying the vendor lockup, and the toolbar and status stats laid out on a single line, with the send and stop buttons unified into 7px rounded rectangles. The stats sentence and the model trigger share the same font size and color. The permission tiers come from the host's own catalog: a deployment draws exactly the tiers it configures, and a tier a third-party plugin registers (the auto mode plugin's `auto-mode`, say) appears in the list and takes the Auto slot; the list stays text-only, so a tier's declared glyph is not drawn. Switching tiers slides the highlight from the old tier to the new one, and every segmented control on the settings page does the same.
90
+ 1. **Theme** — applies globally the moment it is installed, with nothing to configure. Light mode uses ivory `#FCFCFB`, dark mode warm black `#141413`, and both share the same ember orange `#D97757` action accent; light/dark follows the system color mode. The settings page's Brand mark row offers DeepSeek / Claude: DeepSeek turns the whole palette blue — the accent becomes DeepSeek's brand blue `#4D6BFE` (buttons, switches, checks, links and the status line follow), the yellowish ivory light canvas gives way to a white carrying only a hint of sky blue, `#FAFBFF` (sidebar `#F7F9FF`, with the raised layers, segmented-control plates, table headers and scrollbars stepped back in the same measure), the warm-black dark canvas to a blue-black `#13161D`, the hairlines and grey inks turn cool and user bubbles take a touch of blue; the sidebar and the home page keep the host's own DeepSeek whale and wordmark, painted DeepSeek blue, and the account row's picture without an avatar and a running turn's status line take DeepSeek's whale mark as well. The choice used to be labelled "Off", and a value stored under that name reads as DeepSeek; the third choice this row once carried, Anthropic, is gone, and a value stored as `anthropic` reads as Claude, whose marks and palette it shared. The settings page also carries an **Animation** row — Follow the system (Windows' own "show animations" setting decides), Reduced (every animation holds its still frame, whatever the system says) and Always (they play, whatever the system says); the background-work ring turns in every setting, since a still ring reads as broken rather than as calm.
91
+ 2. **Composer** — the input box is rebuilt from the ground up: a permission segmented control (Read / Edit / Auto / Yolo) with its tier list under it, a model trigger carrying the vendor lockup, and the toolbar laid out on a single line with the send and stop buttons unified into 7px rounded rectangles. The session's numbers are no longer a sentence on that line: the two host pills behind it are hidden, and their detail (model time, tool-call time, average time to first token, output speed, and the token-usage rows) is appended to the context meter's popover — read from the host's own session projections, so it matches what the host itself would show and follows the session while the popover stays open. That popover opens on hover and folds away when the pointer leaves, arriving with the same short fade and rise as the skin's own cards; while the numbers are still on their way, a placeholder holds their height so it never opens short and grows. The model trigger and the meter share the same font size and color. The permission tiers come from the host's own catalog: a deployment draws exactly the tiers it configures, and a tier a third-party plugin registers (the auto mode plugin's `auto-mode`, say) appears in the list and takes the Auto slot; the list stays text-only, so a tier's declared glyph is not drawn. Switching tiers slides the highlight from the old tier to the new one, and every segmented control on the settings page does the same.
67
92
  3. **Model picker** — a new two-level popover. The first level lists the official service plus the quick providers selected in settings; "More models" opens a second level grouped by provider. Every row carries its vendor lockup and a description, and the footer holds the reasoning-effort slider (stepless — it snaps to the nearest level on release) together with the "More models" entry. The second level aligns its bottom edge with the first, providers already shown on the first level are not repeated, and models without thinking support get no slider. Hovering opens the popover after a 100 ms dwell and closes it after 150 ms; the gap between the two cards does not count as leaving.
68
- 4. **Workspace** — the sidebar's "Workspace" heading becomes an **Active / Archived** segmented control. Active keeps the host's session tree, while Archived is the skin's own flat list (title, time, and per-row unarchive and delete icon buttons). A refused delete raises the host's Toast with the reason: a conversation still held open by the app asks for a restart first, and every other refusal names the reason. Rows match the host's session rows measurement for measurement (row x=12 / width 251 / height 28 / title x=36). Switching between the two views slides the highlight from one segment to the other.
69
- 5. **Sidebar** — the New session and Plugins rows take Claude's real shape: no background at rest, a background on hover, the "+" of New session set inside a circular chip, and both icons rotating 90° clockwise on hover (four-fold symmetric glyphs, so they land back on themselves). The account drawer and the ban-screen easter egg remain as they were. On the desktop the brand row sits 10px higher than the host draws it, level with the web build. While the pointer is over the sidebar, the brand mark at its top left fades into a search box (the collapsed rail has none); pressing it, or the host's search shortcut (Ctrl+K on the desktop, Ctrl+Alt+K on the web), fades in a search palette near the top of the window, and the Workspace heading's own search icon is gone: it searches past sessions (by title, workspace name and what was said in them: every message between you and the model counts, a few Chinese characters from the middle of a sentence match, case does not matter, and the matching line shows under the row with the match in bold; the first time the palette opens after the host starts, every session is read once, which takes a dozen seconds or so), projects, plugins, the skills the current session offers and keyboard shortcuts, with All / Sessions / Projects / Plugins / Skills / Shortcuts across the top, and with the box empty it lists the five most recent sessions and the New session, Plugins, Settings and Keyboard shortcuts actions. ↑↓ moves, Enter opens, Tab and Shift+Tab switch the category, Esc closes; a session opens, a project starts a new session in that workspace, a plugin opens its details on the plugins page, a skill puts `/name ` at the head of the current session's input, and a shortcut opens the host's shortcut list filtered to that entry.
70
- 6. **Account area** — the nickname and the picture each follow one fixed order. Nickname: the custom nickname → the signed-in account's name → the HDSL launcher's account name → the last probed system user → the freshly probed system user → `User`. Picture: the signed-in account's avatar → the HDSL launcher's avatar → the Claude mark. The account profile is fetched from the server only at startup, on hot reload, and on sign-in and sign-out — never polled. The HDSL contract is read once by the host half and forwarded over two read-only routes (`GET /dsh-claude-style/hdsl` for the metadata, `GET /dsh-claude-style/hdsl-skin.png` for the avatar image; neither carries the avatar file's absolute path, and both sit behind the host's request fence). A contract version that is missing or unknown voids the whole group, and a deleted avatar file falls back to the mark. What the launcher publishes is a skin sheet rather than a finished avatar, so that picture is cropped into the head first — the face's 8×8 texel block inset by 1/18 of the box with the hat layer over the whole box, drawn square so no rounding shaves its pixels. The account popover remains the host's own: the host's account row is the entry point, and the popover lists the account header, the other plugins' footer entries, and the host's own Settings / Feedback / Sign out, each keeping its original copy, order, and click behavior. On hosts without an account area (Web), the plugin builds a popover with the same look. The card takes the main canvas's fill (ivory in light mode, sky white under the DeepSeek brand) and spans the sidebar's width. Without an avatar the picture is the brand mark: the Claude mark under the Claude and Anthropic brands, DeepSeek's whale under the DeepSeek brand.
93
+ 4. **Workspace** — the sidebar's "Workspace" heading becomes an **Active / Archived** segmented control. Active keeps the host's session tree, while Archived is the skin's own flat list (title, time, and per-row unarchive and delete icon buttons). A refused delete raises the host's Toast with the reason: a conversation still held open by the app asks for a restart first, and every other refusal names the reason. Rows match the host's session rows measurement for measurement (row x=12 / width 251 / height 28 / title x=36), and they rest in the same grey: an archived title darkens only while the pointer is on its row or the keyboard focus is in it. Switching between the two views slides the highlight from one segment to the other.
94
+ 5. **Sidebar** — the New session and Plugins rows take Claude's real shape: no background at rest, a background on hover, the "+" of New session set inside a circular chip, and both icons rotating 90° clockwise on hover (four-fold symmetric glyphs, so they land back on themselves). The account drawer remains as it was. On the desktop the ban-screen easter egg rides the window's own titlebar row: its lockup and Sign out sit in that row beneath the system's window buttons (which the page draws no second copy of), the row takes the page's own canvas colour, and the window is still dragged by it. On the desktop the brand row sits 10px higher than the host draws it, level with the web build. While the pointer is over the sidebar, the brand mark at its top left fades into a search box (the collapsed rail has none); pressing it, or the host's search shortcut (Ctrl+K on the desktop, Ctrl+Alt+K on the web), fades in a search palette near the top of the window, and the Workspace heading's own search icon is gone: it searches past sessions (by title, workspace name and what was said in them: every message between you and the model counts, a few Chinese characters from the middle of a sentence match, case does not matter, and the matching line shows under the row with the match in bold; the first time the palette opens after the host starts, every session is read once, which takes a dozen seconds or so), projects, plugins, the skills the current session offers and keyboard shortcuts, with All / Sessions / Projects / Plugins / Skills / Shortcuts across the top, and with the box empty it lists the five most recent sessions and the New session, Plugins, Settings and Keyboard shortcuts actions. ↑↓ moves, Enter opens, Tab and Shift+Tab switch the category, Esc closes; a session opens, a project starts a new session in that workspace, a plugin opens its details on the plugins page, a skill puts `/name ` at the head of the current session's input, and a shortcut opens the host's shortcut list filtered to that entry.
95
+ 6. **Account area** — the nickname and the picture each follow one fixed order. Nickname: the custom nickname → the signed-in account's name → the HDSL launcher's account name → the last probed system user → the freshly probed system user → `User`. Picture: the signed-in account's avatar → the HDSL launcher's avatar → the Claude mark. The account profile is fetched from the server only at startup, on hot reload, and on sign-in and sign-out — never polled. The HDSL contract is read once by the host half and forwarded over two read-only routes (`GET /dsh-claude-style/hdsl` for the metadata, `GET /dsh-claude-style/hdsl-skin.png` for the avatar image; neither carries the avatar file's absolute path, and both sit behind the host's request fence). A contract version that is missing or unknown voids the whole group, and a deleted avatar file falls back to the mark. What the launcher publishes is a skin sheet rather than a finished avatar, so that picture is cropped into the head first — the face's 8×8 texel block inset by 1/18 of the box with the hat layer over the whole box, drawn square so no rounding shaves its pixels. The account popover remains the host's own: the host's account row is the entry point, and the popover lists the account header, the other plugins' footer entries, and the host's own Settings / Feedback / Sign out, each keeping its original copy, order, and click behavior. On hosts without an account area (Web), the plugin builds a popover with the same look. The card takes the main canvas's fill (ivory in light mode, sky white under the DeepSeek brand) and spans the sidebar's width. Without an avatar the picture is the brand mark: the Claude mark under the Claude brand, DeepSeek's whale under the DeepSeek brand.
71
96
  7. **Conversation views** — in the desktop Windows titlebar mode, the Conversation / Trajectory control sits centered and always visible on the titlebar row (the same row as the New session button). On wide windows with a short title it stays on the title's row; otherwise it keeps its own row below the title. Switching views slides the highlight from the old tab to the new one. For running, stopped and failed turns the status line follows the end of the turn's work (the footer and queued messages sit below it) and looks like Claude Code's: while running, a turning spark, then elapsed time · output tokens · what the model is doing (waiting for the model, thinking, thought for N s, writing, preparing a tool call, running tools); once stopped or failed, a still spark and "Stopped / Failed · duration · output tokens". Under the DeepSeek brand the spark is DeepSeek's whale mark, which sways as it swims while the turn runs. A turn that finishes normally keeps the host's own look and place.
72
97
  8. **Home layouts** — the new-conversation page comes in two layouts, Studio by default and switchable in the settings page at any time: **Classic** is the centered headline over the composer card, the headline drawn from a pool of greetings for the time of day (a few each for morning, midday, afternoon, evening and night, plus a few for any hour) and redrawn each time the new-conversation page comes back; **Studio** pins the greeting to the top left as one fixed line ("What's up next, <user>?"), docks the composer in the conversation's single-line form at the window's bottom edge with a row of hairline context chips above it, and sets the greeting and a 480px usage panel against the composer's left edge: an Overview tab with six stat cells (sessions, messages, total tokens, active days, peak hour, favorite model) and a twenty-six-week per-day heat grid of square cells in equal columns, a Models tab stacking each day's per-model tokens into one bar over a ranked model list (swatch, name, input and output, share; past six rows it folds behind a "show more" row, and the open list folds back with "show less"), and All / 30d / 7d range pills at the top right, which the peak hour and the multiplier line follow too; once the picked range's total passes one book, a multiplier line appears under the grid, naming one of sixty-five books (Tao Te Ching to In Search of Lost Time) drawn afresh each time the new-conversation page comes back. The numbers are rolled up by the plugin's host half: with `dsh-cost-meter` installed it reads that plugin's ledger cache directly (read-only — their file is never written), and without it the host half folds the local session logs itself, caching per log by size and modification time. Both sources answer each model's four buckets and each day's per-model tokens, with one model served by several providers counted as one row; the ledger keeps no hours, so the peak hour is always folded per day from the local session logs; when the roll-up cannot answer, the panel falls back to the projection block each host session row carries. The panel draws its skeleton first and does not shift when the numbers land. Before a workspace is picked (a fresh start, no session yet), the usage panel and the Read / Edit / Auto / Yolo permission segments still show; the segments rest on the preset a new session starts in, and pressing them opens the workspace picker, the same as pressing the input box, whose dashed "pick a workspace" ring now outlines the single-line input box alone. When the window is too short for the whole panel, the panel scrolls between the greeting and the composer with its bottom edge fading out, and the page no longer runs past the window. The workspace picker is drawn as Claude Code's folder menu: a narrow card of plain text rows set closer together, with no folder glyph in front of each folder and no plus sign on "Add workspace…"; the current workspace keeps the accent check.
73
98
  9. **The pixel crab** — in the Studio layout, Claude Code's pixel crab stands on the new-conversation composer card's top edge, near its right end (the Classic layout has none). When it is clicked or the pointer leaves it (and on its own every half minute or so while the page is open), it plays Claude Code's fishing routine, frame for frame from Claude Code's own animation: a blink, the rod raised and cast down past the card's edge, a hop into a side-on stance for a spell of fishing, and the rod reeled in as it turns back — about three and a half seconds. With reduced motion requested (Windows' "Show animations in Windows" turned off, for one), it moves only when clicked.
74
99
  10. **Deepy the pixel whale** — under the DeepSeek brand the crab gives way to Deepy, a pixel whale drawn on a 52×52 grid whose every frame comes from the Deepy theme pack's animations, 50 ms a frame. On the home page (both layouts) it stands on the composer card's top edge near its right end; in a conversation it stands on top of the whole input area (the composer card together with the todo, queue and goal cards above it), and while you are asked to approve something, answer a question or review a plan it stands on the panel that takes the card's place. Only the main conversation carries it; the sidebar's subagent chats do not. What it does follows the agent's work: between jobs it breathes, flicks its tail and blinks, and every half minute or so looks around or spouts water; while the model reasons or has not started answering, a thought cloud floats over it; while the model writes an answer or calls tools it types at a keyboard, puts on headphones when two sessions work at once and a hard hat from three; while subagents run it wears headphones for one and conducts a squad of little whale clones with its tail for two or more; a context compaction has it inhale the fragments; while you are asked for something it rings an exclamation bell; a failed tool call or a failed turn gives it a fright, smoke and dizzy stars; a turn or a compaction that finishes gets a flip and confetti (a finish that comes right after a failure is celebrated once the fright has played out). On the home page it reads the whole workspace: how many sessions are working picks the animation, a session waiting on you rings the bell, and one finishing in the background is celebrated. After a minute with no work and no pointer movement or key press it puts on a nightcap and falls asleep, and wakes with a start at the next one. Clicking its face or its tail pokes it into a jelly wobble, four quick clicks tickle it, and pressing it and pulling lifts it into a dangle until you let go. With reduced motion requested, each state holds one frame, and it moves only when clicked. The frames weigh about 0.4 MB, so they stay out of the page script: the plugin's host half serves them over a public route, `GET /dsh-claude-style/deepy/<animation>.png`, and the browser fetches an animation's frames the first time it plays. Against a host half that predates the route (the plugin updated without restarting the host), the frames do not load, the whale stays away and the console says so once.
75
100
 
101
+ <table>
102
+ <tr>
103
+ <td align="center" width="25%"><img src="./showcase/gifs/idle.gif" width="120" alt="Idle" /><br />Idle</td>
104
+ <td align="center" width="25%"><img src="./showcase/gifs/thinking.gif" width="120" alt="Thinking" /><br />Thinking</td>
105
+ <td align="center" width="25%"><img src="./showcase/gifs/typing.gif" width="120" alt="Answering and calling tools" /><br />Answering and calling tools</td>
106
+ <td align="center" width="25%"><img src="./showcase/gifs/conducting.gif" width="120" alt="Conducting subagents" /><br />Conducting subagents</td>
107
+ </tr>
108
+ <tr>
109
+ <td align="center" width="25%"><img src="./showcase/gifs/notification.gif" width="120" alt="Waiting on you" /><br />Waiting on you</td>
110
+ <td align="center" width="25%"><img src="./showcase/gifs/error.gif" width="120" alt="Failed" /><br />Failed</td>
111
+ <td align="center" width="25%"><img src="./showcase/gifs/happy.gif" width="120" alt="Finished" /><br />Finished</td>
112
+ <td align="center" width="25%"><img src="./showcase/gifs/sleeping.gif" width="120" alt="Asleep" /><br />Asleep</td>
113
+ </tr>
114
+ </table>
115
+
76
116
  ## Disabling and uninstalling
77
117
 
78
118
  To pause the theme without uninstalling it, add the following to the profile's `cordis.patch.yml` (`~/.dsh/profiles/web/cordis.patch.yml`):
@@ -99,6 +139,10 @@ Then restart `dsh web`. If you previously added this theme's entry to `cordis.pa
99
139
  | [Changelog](CHANGELOG.md) | Version history |
100
140
  | [Contributing](CONTRIBUTING.md) | Building from `src/`, commit conventions, and the screenshot and regression tooling (in English) |
101
141
 
142
+ ## Acknowledgements
143
+
144
+ The animation frames of Deepy the pixel whale come from the Deepy whale theme pack drawn by calmly-eating-bugs ([@wp3171216237](https://github.com/wp3171216237)), and ship with the plugin by the author's permission. Many thanks to the author! GIFs of all 20 animations, contributed by the author, are in [showcase/gifs/](showcase/gifs/).
145
+
102
146
  ## Related projects
103
147
 
104
148
  > Running several themes at once? Try [dsh-skin-manager](https://github.com/xiaoyangcheng84-svg/dsh-skin-manager) — it switches between all installed themes from a single settings page.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  # DSH Claude Style
4
4
 
5
- **为 DeepSeek Harness Web 复刻 Claude Code Desktop 风格与交互体验的主题插件。**
5
+ **为 DeepSeek Harness 复刻 Claude Code Desktop 风格与交互体验的主题插件。**
6
6
 
7
7
  > **在 DSH 里,就是 Claude Code Desktop 的样子。**
8
8
 
@@ -18,18 +18,60 @@
18
18
 
19
19
  ## 预览
20
20
 
21
+ 本插件提供了两种主题。通过插件设置,可以在 Claude 与 DeepSeek 两套配色之间切换,亮暗跟随系统颜色模式。
22
+
23
+ ### Claude
24
+
25
+ <table>
26
+ <tr>
27
+ <td align="center" width="50%"><img src="./docs/claude-home-light.png" alt="Claude 档工作台首页 —— 亮色" /></td>
28
+ <td align="center" width="50%"><img src="./docs/claude-home-dark.png" alt="Claude 档工作台首页 —— 暗色" /></td>
29
+ </tr>
30
+ <tr>
31
+ <td align="center" width="50%"><img src="./docs/claude-conversation-light.png" alt="Claude 档 Markdown 对话 —— 亮色" /></td>
32
+ <td align="center" width="50%"><img src="./docs/claude-conversation-dark.png" alt="Claude 档 Markdown 对话 —— 暗色" /></td>
33
+ </tr>
34
+ </table>
35
+
36
+ > Claude品牌主题,原汁原味。工作台首页(上),对话界面(下),浅色(左),深色(右)
37
+
38
+ ### DeepSeek
39
+
21
40
  <table>
22
41
  <tr>
23
- <td align="center" width="50%"><img src="./docs/light.png" alt="亮色画布 —— 暖调象牙" /></td>
24
- <td align="center" width="50%"><img src="./docs/dark.png" alt="暗色画布 —— 暖调黑" /></td>
42
+ <td align="center" width="50%"><img src="./docs/deepseek-home-light.png" alt="DeepSeek 档工作台首页 —— 亮色" /></td>
43
+ <td align="center" width="50%"><img src="./docs/deepseek-home-dark.png" alt="DeepSeek 档工作台首页 —— 暗色" /></td>
44
+ </tr>
45
+ <tr>
46
+ <td align="center" width="50%"><img src="./docs/deepseek-conversation-light.png" alt="DeepSeek 档 Markdown 对话 —— 亮色" /></td>
47
+ <td align="center" width="50%"><img src="./docs/deepseek-conversation-dark.png" alt="DeepSeek 档 Markdown 对话 —— 暗色" /></td>
25
48
  </tr>
26
49
  </table>
27
50
 
28
- > 亮色:象牙白画布 `#FCFCFB` 与浅色侧栏 `#FBFBF9`;暗色:暖黑 `#141413`。主题遵循系统亮暗模式切换,陶烬橙 `#D97757` 是两套画布唯一的操作强调色。
51
+ > DeepSeek品牌主题,拥有特色宠物小鲸鱼Deepy。工作台首页(上),对话界面(下),浅色(左),深色(右)
52
+ >
53
+ > <table>
54
+ > <tr>
55
+ > <td align="center" width="25%"><img src="./showcase/gifs/idle.gif" width="120" alt="空闲" /><br />空闲</td>
56
+ > <td align="center" width="25%"><img src="./showcase/gifs/thinking.gif" width="120" alt="思考" /><br />思考</td>
57
+ > <td align="center" width="25%"><img src="./showcase/gifs/typing.gif" width="120" alt="写回答、调用工具" /><br />写回答、调用工具</td>
58
+ > <td align="center" width="25%"><img src="./showcase/gifs/conducting.gif" width="120" alt="指挥子代理" /><br />指挥子代理</td>
59
+ > </tr>
60
+ > <tr>
61
+ > <td align="center" width="25%"><img src="./showcase/gifs/notification.gif" width="120" alt="等你操作" /><br />等你操作</td>
62
+ > <td align="center" width="25%"><img src="./showcase/gifs/error.gif" width="120" alt="失败" /><br />失败</td>
63
+ > <td align="center" width="25%"><img src="./showcase/gifs/happy.gif" width="120" alt="完成" /><br />完成</td>
64
+ > <td align="center" width="25%"><img src="./showcase/gifs/sleeping.gif" width="120" alt="睡着" /><br />睡着</td>
65
+ > </tr>
66
+ > </table>
29
67
 
30
68
  ## 字体
31
69
 
32
- > **重要:Anthropic 字体不随 npm 包分发,仅在仓库 [`fonts/`](fonts/) 供下载**——既可以直接安装到系统,也可以免安装:把两个 `.ttf` 放进插件包的 `fonts/` 目录,宿主会以同样的 webfont 方式提供它们(两种方式的字体文件完全一致,效果相同)。生效均需刷新 / 重启 web。
70
+ > 本插件使用的字体如下。
71
+ >
72
+ > Anthropic Sans/Serif 字体版权归 Anthropic 所有,仅供个人使用,不适用 MIT 许可。
73
+ >
74
+ > **重要:Anthropic 字体不随 npm 包分发,仅在仓库 [`fonts/`](fonts/) 供下载**。
33
75
 
34
76
  | 字体 | 用途 | 文件 |
35
77
  |---|---|---|
@@ -43,52 +85,23 @@ Anthropic 字体启用(二选一):
43
85
 
44
86
  ② 免安装——把 `.ttf` 复制到插件包的 `fonts/` 目录。完成后刷新页面生效。
45
87
 
46
- > Anthropic Sans/Serif 字体版权归 Anthropic 所有,仅供个人使用,不适用 MIT 许可。
47
-
48
88
  ## 安装
49
89
 
50
- > 需要 dsh ≥ 0.1.7
90
+ 1. 官方插件页,添加以下插件即可快速安装
51
91
 
52
- 1. 通过终端安装
53
-
54
- ```bash
55
- dsh plugin --profile web add dsh-claude-style # npm 包(推荐)
56
- dsh plugin --profile web add Nwflower/dsh-claude-style # GitHub 源
57
92
  ```
58
-
59
- 2. 通过[插件市场](https://github.com/dsh-market/dsh-market)安装
60
-
61
- 同一时刻建议只启用一个主题。安装后**重启 `dsh web`** 并刷新页面即生效。
62
-
63
- ## 特点
64
-
65
- 1. **主题** —— 安装即全局生效,无需配置。亮色象牙白 `#FCFCFB`、暗色暖黑 `#141413`,两套画布共用同一个操作强调色陶烬橙 `#D97757`;亮暗跟随系统颜色模式切换。设置页「修改品牌标识」有 DeepSeek / Claude / Anthropic 三档:选 DeepSeek 时整套配色换成蓝色系——强调色换成 DeepSeek 的品牌蓝 `#4D6BFE`(按钮、开关、勾选、链接与状态行都跟着变),亮色画布从偏黄的象牙白换成带一点天蓝的亮白 `#F7FAFF`(侧栏 `#F3F7FE`),暗色画布从暖黑换成蓝黑 `#13161D`,边框与灰色文字一并换成冷色,用户消息气泡带一点蓝;侧栏与首页保留宿主自己的 DeepSeek 鲸鱼与字标,画成 DeepSeek 蓝,账号行没有头像时、进行中轮次的状态行也改用 DeepSeek 的鲸鱼标。这一档以前叫「关闭」,存下的旧值照样读作 DeepSeek。
66
- 2. **输入框** —— 输入框整块重做:权限分段控件(只读 / 编辑 / 自动 / Yolo)与它下方的档位列表、带品牌锁定标的模型触发器、工具栏与状态统计同一行排版,发送键与停止键统一成 7px 圆角。统计句与模型触发器共用一套字号与颜色。权限档位取自宿主的权限目录:宿主配置了哪几档就画哪几档,第三方插件注册的档位(例如 auto mode 插件的 `auto-mode`)会自动出现在列表里并占用「自动」那一格;列表保持纯文字,档位自己声明的图标不画。切换档位时,高亮块从原档位平滑滑到新档位;设置页里的各组分段控件也是如此。
67
- 3. **模型选择器** —— 全新的两级弹层:一级列官方服务与设置页勾选的快捷供应商,「更多模型」二级按供应商分组;每行带厂商锁定标与说明文案,底部是推理等级推条(无极滑动,松手对齐最近档位)与「更多模型」入口。二级底边与一级对齐,一级已显示的供应商不再重复;模型不支持思考时不画推条。悬停停留 100ms 打开、离开 150ms 关闭,两卡之间的空隙不算离开。
68
- 4. **工作区** —— 侧栏「工作区」标题改成 **进行中 / 已归档** 分段控件:进行中沿用宿主的会话树,已归档是皮肤自己的平铺列表(标题、时间、每行「取消归档」与「删除」两个图标按钮)。删除被拒时弹出宿主的 Toast 说明原因:会话仍被应用占用时提示重启后再删除,其余拒绝提示失败原因。行排版与宿主的会话行逐项一致(行 x=12 / 宽 251 / 高 28 / 标题起点 x=36)。切换两种视图时,高亮块在两段之间平滑滑动。
69
- 5. **侧栏** —— 新会话与插件两行取 Claude 真机形状:默认无底色、hover 才有底色,新会话的「+」套一枚圆形底,两行图标 hover 顺时针转 90°(四重对称图形,转回原位);底部账户抽屉、封号彩蛋一并保留。桌面端的品牌行比宿主原样上移 10px,不再比 Web 端低出一截。鼠标移到侧栏上时,左上角的品牌标志淡出、换成一个搜索框(侧栏收起成窄条时没有),点它或按宿主的搜索快捷键(桌面端 Ctrl+K,Web 端 Ctrl+Alt+K)在窗口上方淡入搜索面板,「工作区」标题行原来的搜索图标不再显示:搜历史会话(按标题、所属工作区名和对话内容:你和模型说过的每句话都算,句子中间的几个中文字也能搜到,不分大小写,行下显示命中的那一句并把命中的字加粗;宿主启动后第一次打开面板时要把全部会话读一遍,约十几秒)、项目、插件、当前会话可用的 Skill 与快捷键,顶部「全部 / 会话 / 项目 / 插件 / Skill / 快捷键」切换分类,搜索框为空时列出最近的五个会话与「新会话 / 插件 / 设置 / 键盘快捷键」几个操作。↑↓ 选择、Enter 打开、Tab 与 Shift+Tab 切换分类、Esc 关闭;选中会话即打开,选中项目在该工作区开新会话,选中插件打开它在插件页的详情,选中 Skill 把 `/名称 ` 放到当前会话输入框开头,选中快捷键打开宿主的快捷键列表并筛到这一条。
70
- 6. **账号区** —— 昵称与头像各走一条固定顺序。昵称:自定义昵称 → 官方账号昵称 → HDSL 启动器昵称 → 上次探测到的系统用户名 → 本次探测到的系统用户名 → `User`;头像:官方账号头像 → HDSL 启动器头像 → Claude 徽标。官方账号资料只在启动、热重载、登录与登出时向服务器读取,不轮询;HDSL 契约由宿主半边读一次后经两条只读路由转发(`GET /dsh-claude-style/hdsl` 回账号元数据、`GET /dsh-claude-style/hdsl-skin.png` 回头像图片,都不含头像文件的绝对路径,并过宿主的请求栅栏),契约版本读不到或不认识时整组忽略,头像文件被删除时回落到徽标。启动器给的是皮肤贴图而不是成品头像,因此账号位置的头像由贴图裁出:脸部 8×8 贴图块按盒子 1/18 内缩、帽子层铺满整盒,方形绘制不被圆角裁切。账号弹层沿用宿主自带的那一个:宿主的账号行就是入口,弹层里依次是账号头部、其它插件的页脚条目与宿主自己的「设置 / 意见反馈 / 退出登录」,各行的文案、顺序与点击行为保持宿主原样;宿主没有账号区的环境(Web)由插件自建同样外观的弹层。弹层卡片与主画布同色(亮色下为象牙白,DeepSeek 品牌下为天蓝亮白)、宽度与侧栏一致。没有头像时显示品牌标:Claude 与 Anthropic 两档是 Claude 徽标,DeepSeek 档是 DeepSeek 的鲸鱼标。
71
- 7. **对话视图** —— 对话 / 轨迹控件在桌面 Windows 标题栏模式下居中常显在标题栏那一行(与新会话按钮同一行);宽窗口且标题较短时它停在标题那一行,否则留在标题下方自己那一行。切换视图时,高亮块从原标签平滑滑到新标签。进行中、已停止与失败的轮次,状态行跟在这一轮工作的末尾(页脚与排队中的消息在它下面),画成 Claude Code 的样子:进行中是转动的火花标记加「用时 · 输出 tokens · 当前动作」(等待模型、思考中、思考了 N 秒、输出中、准备调用工具、运行工具中),停止或失败后火花静止、文字为「已停止 / 处理失败 · 用时 · 输出 tokens」;DeepSeek 品牌下火花换成 DeepSeek 的鲸鱼标,进行中时它摇摆着游动。正常结束的一轮保留宿主原来的样子与位置。
72
- 8. **首页版面** —— 新会话页有两套版面,默认是工作台,在设置页随时切换:**经典**是居中大标题加输入卡片,标题按时段从一组问候里抽一句(早上、午间、下午、晚上、深夜各有几句,另有几句不分时段),每次回到新会话页换一句;**工作台**把标题移到左上并固定为一句「What's up next, 用户名?」,输入框改用对话内的单行样式贴住窗口底部、上方一行细边框上下文胶囊,标题与一块 480px 窄栏用量面板贴着输入框左缘排布:概览页签是六个数字格(会话数、消息数、Token 总量、活跃天数、高峰时段、最常用模型)与 26 周按天热力图(等分列方格),模型页签是每天一根按模型颜色堆叠的柱子加一份模型排行(色块、模型名、输入与输出、占比,超过六行折成「再显示 N 个」,展开后可「收起」),右上角的「全部 / 30 天 / 7 天」切换统计范围(高峰时段与趣味行一并跟随);所选范围内的用量超过一本书时,热力图下方出现倍数趣味行,书目共六十五本(《道德经》到《追忆似水年华》),每次回到新会话页随机换一本。数据由插件的宿主半边汇总:装了 `dsh-cost-meter` 时直接读它的账本缓存(只读,不写对方文件),没有时读本机会话日志自己算,并按日志的文件大小与修改时间增量缓存;两种来源都按模型给出四类 token、按天给出各模型的 token,同一模型经不同提供方的用量合成一行;账本不记小时,高峰时段始终由本机会话日志按天算出;汇总不可用时面板改用宿主会话列表每行自带的投影值。数字没到之前面板先画骨架,位置在填充前后不变。还没选工作区时(刚打开、尚无会话),用量面板与 Read / Edit / Auto / Yolo 权限分段照常显示,分段停在新会话的默认权限上,点它和点输入框一样打开工作区选择;表示「先选工作区」的虚线框只框住单行输入框本身。窗口高度放不下整块面板时,面板在问候语与输入框之间自己滚动、底边渐隐,页面不会被撑出窗口。工作区选择菜单照 Claude Code 的文件夹菜单绘制:窄卡片、纯文字行排得更紧,每行前面的文件夹图标与「添加工作区…」前的加号都不画,当前工作区仍以强调色勾号标出。
73
- 9. **像素螃蟹** —— 工作台版面的新会话页上,输入卡片上沿、靠右的位置站着 Claude Code 的像素螃蟹(经典版面没有)。点它一下、或指针从它身上移开时(页面开着时也会每隔二三十秒自己来一次),它会照 Claude Code 的样子钓一次鱼:眨眨眼,举起鱼竿甩过卡片边沿,跳一下侧过身钓一会儿,再收竿转回正面,逐帧照搬 Claude Code 的动画,前后约三秒半。系统要求减少动态效果时(例如 Windows 关掉了「在 Windows 中显示动画」),它只在被点击时才动。
74
- 10. **像素小鲸鱼 Deepy** —— 品牌选 DeepSeek 时,螃蟹换成小鲸鱼 Deepy(画在 52×52 的像素格上,每一帧照搬 Deepy 主题包的动图,每帧 50 毫秒)。它在首页(两种版面都有)站在输入卡片上沿、靠右的位置;进入对话后站在整块输入区的上沿(输入卡片连同上面的待办、排队、目标卡片),要你批准、回答问题或审阅计划时,站到替换输入卡片的那块面板上。只有主对话区有它,侧栏里的子代理对话没有。它的动作跟着智能体的工作走:没事时慢慢呼吸、甩尾、眨眼,每隔二三十秒东张西望或开心喷水一次;模型在想或还没开始回答时头顶冒思考云;模型写回答、调用工具时趴在键盘后敲代码,同时有两个会话在干活时戴上耳机摇摆,三个以上戴安全帽砌砖;有子代理在跑时,一个戴耳机、两个以上用尾巴打拍子带小鲸鱼分身;压缩上下文时把碎片吸进肚子;等你批准或回答时摇感叹号铃铛;工具调用失败或这一轮失败时受惊冒烟、眼冒金星;一轮或一次压缩顺利结束时空翻撒彩纸(紧跟在失败之后的完成,等冒烟演完再庆祝)。首页上它看的是整个工作区:有几个会话在干活就按几个会话挑动作,有会话在等你时摇铃,别的会话在后台做完时庆祝。闲下来后一分钟没动鼠标、没按键时它会戴上睡帽睡着,再动一下就惊醒。点它的脸或尾巴会被戳得果冻一样晃,连点四下被挠痒痒,按住往外拖会被拎起来晃荡,松手放回。系统要求减少动态效果时,每个状态只停在一张代表帧上,点它才会动。动图帧图共约 0.4 MB,不打进页面脚本:插件的宿主半边经公开路由 `GET /dsh-claude-style/deepy/<动作>.png` 提供,浏览器在某个动作第一次出现时才下载它的帧图;宿主半边还是旧版(更新插件后没有重启宿主)时读不到帧图,小鲸鱼不出现,控制台留一条提示。
75
-
76
- ## 停用与卸载
77
-
78
- 不停用安装、先暂停主题 —— 在 profile 的 `cordis.patch.yml`(`~/.dsh/profiles/web/cordis.patch.yml`)中加入:
79
-
80
- ```yaml
81
- - id: ui-skin-claude-style
82
- disabled: true
93
+ dsh-claude-style
83
94
  ```
84
95
 
85
- 保存后约 1 秒内热生效,刷新页面即回到原生外观。
96
+ 2. 通过终端安装
86
97
 
87
98
  ```bash
88
- dsh plugin --profile web remove dsh-claude-style # 卸载
99
+ dsh plugin --profile web add dsh-claude-style # npm 包(推荐)
89
100
  ```
90
101
 
91
- 然后重启 `dsh web`;若曾在 `cordis.patch.yml` 手工添加过本主题的条目,一并删除。
102
+ 3. 通过[插件市场](https://github.com/dsh-market/dsh-market)安装
103
+
104
+ 同一时刻建议只启用一个主题。安装后推荐重启 `DeepSeek Harness`以获得完整能力。
92
105
 
93
106
  ## 文档
94
107
 
@@ -99,9 +112,11 @@ dsh plugin --profile web remove dsh-claude-style # 卸载
99
112
  | [更新日志](CHANGELOG.md) | 版本历史 |
100
113
  | [贡献指南](CONTRIBUTING.md) | 如何从 `src/` 构建、提交规范与截图/回归工具(英文) |
101
114
 
102
- ## 友链
115
+ ## 鸣谢
116
+
117
+ 像素小鲸鱼 Deepy 的动画帧图来自 calmly-eating-bugs([@wp3171216237](https://github.com/wp3171216237))绘制的 Deepy 小鲸鱼主题包。
103
118
 
104
- > 同时启用多个主题?推荐 [dsh-skin-manager](https://github.com/xiaoyangcheng84-svg/dsh-skin-manager),在其设置页一键切换所有已安装主题。
119
+ ## 友链
105
120
 
106
121
  > 想把 Claude Code / Codex 等外部代理的会话历史导入 DSH 接着聊?推荐作者的另一个插件 [dsh-chat-import](https://github.com/Nwflower/dsh-chat-import)。
107
122
 
package/docs/STYLE.md CHANGED
@@ -26,9 +26,10 @@ blue. The single accent is DeepSeek's brand blue `#4D6BFE` — the colour of its
26
26
  whale logo and of Deepy — with a darker step for text links on the light canvas
27
27
  and a lighter one on the dark; the sidebar's whale and wordmark and the hero's
28
28
  fish take it as their ink. The neutrals are the host's own cool family (its
29
- `neutral-bluish` ramp) under a sky-tinted white in light and a blue-black in
30
- dark. User bubbles take a blue tint as the host's own do, and inline code keeps
31
- the body ink as the host draws it. The skin's Claude marks (the account row's
29
+ `neutral-bluish` ramp) under a white carrying only a hint of sky in light and a
30
+ blue-black in dark. User bubbles take a blue tint as the host's own do, and
31
+ inline code keeps the body ink as the host draws it. The skin's Claude marks
32
+ (the account row's
32
33
  picture without an avatar, the turn status line's spark) become DeepSeek's
33
34
  whale (`src/assets/brand/deepseek-mark.svg`, the host's `FISH_LOGO_PATH`); the
34
35
  violet top rung of the reasoning slider stays.
@@ -40,16 +41,16 @@ violet top rung of the reasoning slider stays.
40
41
  | link | `#C6613F` / `#A94F2F` | `#3B56D9` / `#2C43B8` | `#E08A6D` / `#F0A488` | `#8FA4FF` / `#B0C0FF` | text link at rest / under the pointer |
41
42
  | markdown link | `#184F95` | `#3B56D9` | `#8AB4F8` | `#8FA4FF` | `--dsh-claude-link` |
42
43
  | brand art | `#141413` | `#4D6BFE` | `#FAF9F5` | `#4D6BFE` | sidebar whale and wordmark, `--dsh-claude-logo-ink` |
43
- | canvas | `#FCFCFB` | `#F7FAFF` | `#141413` | `#13161D` | bg base / layer 1, `--dsh-claude-canvas` |
44
- | sidebar | `#FBFBF9` | `#F3F7FE` | `#141413` | `#13161D` | sidebar, `--dsh-claude-sidebar-canvas` |
45
- | layers | `#FBFBF9` / `#F9F9F6` | `#F3F7FE` / `#EFF4FD` | `#242320` / `#2E2C29` | `#212631` / `#2A303C` | layer 2 / layer 3 |
44
+ | canvas | `#FCFCFB` | `#FAFBFF` | `#141413` | `#13161D` | bg base / layer 1, `--dsh-claude-canvas` |
45
+ | sidebar | `#FBFBF9` | `#F7F9FF` | `#141413` | `#13161D` | sidebar, `--dsh-claude-sidebar-canvas` |
46
+ | layers | `#FBFBF9` / `#F9F9F6` | `#F7F9FF` / `#F4F7FE` | `#242320` / `#2E2C29` | `#212631` / `#2A303C` | layer 2 / layer 3 |
46
47
  | raised card | canvas | canvas | `#1E1E1D` | `#1B1F28` | popovers, menus, search palette, `--dsh-claude-raised` |
47
- | hairlines | `#E8E6DC` / `#DEDCD2` / `#D0CDC1` | `#E1E8F4` / `#D6DFEE` / `#C7D2E6` | `#242320` / `#2E2C29` / `#3A3833` | `#212631` / `#2A303C` / `#363D4B` | border l1 / l2 / l3 |
48
- | solid hover | `#F0EFE9` | `#E9EFF9` | `#2E2C29` | `#2A303C` | the host's solid hover chip |
49
- | chip | `#F6F6F4` | `#EEF3FB` | selector | selector | segmented control and switch at rest, `--dsh-claude-chip` |
50
- | table head | `#F0F0EF` | `#EAF0F9` | `#242320` | `#212631` | `--dsh-claude-table-head` |
48
+ | hairlines | `#E8E6DC` / `#DEDCD2` / `#D0CDC1` | `#E7ECF7` / `#DDE4F1` / `#CFD8EA` | `#242320` / `#2E2C29` / `#3A3833` | `#212631` / `#2A303C` / `#363D4B` | border l1 / l2 / l3 |
49
+ | solid hover | `#F0EFE9` | `#EEF3FC` | `#2E2C29` | `#2A303C` | the host's solid hover chip |
50
+ | chip | `#F6F6F4` | `#F2F6FD` | selector | selector | segmented control and switch at rest, `--dsh-claude-chip` |
51
+ | table head | `#F0F0EF` | `#EFF3FB` | `#242320` | `#212631` | `--dsh-claude-table-head` |
51
52
  | inks | `#141413` / `#6E6A60` / `#8F8A7E` / `#A6A094` | `#0F1115` / `#61666B` / `#81858C` / `#ADB2B8` | `#FAF9F5` / `#B0AEA5` / `#8F8D84` / `#6B6A65` | `#EEF1F8` / `#AEB5C4` / `#8A92A3` / `#666E7E` | label primary / secondary / tertiary / caption |
52
- | user bubble | hover wash | `#E6EDFD` | host's | `#232A3A` | `--dsw-specific-bubble` |
53
+ | user bubble | hover wash | `#EAF0FE` | host's | `#232A3A` | `--dsw-specific-bubble` |
53
54
  | hover wash | `rgba(0, 0, 0, 0.08)` | `rgba(38, 49, 72, 0.08)` | `rgba(255, 255, 255, 0.08)` | `rgba(255, 255, 255, 0.08)` | `--dsh-claude-hover-bg` |
54
55
 
55
56
  **Host token bindings.** The skin supplies its palette through the host's own
@@ -144,21 +145,24 @@ start clipping descenders. The fill, hairline, radius and size are unchanged.
144
145
  ## Popovers · 多选一弹层
145
146
 
146
147
  Every single-choice popover in the skin — the permission menu, the model picker,
147
- the account drawer, the session-stats card, and the host's own menu primitive
148
- under the hero row's workspace and preset pickers — is meant to start from one
149
- recipe. New popovers take it rather than inventing a card.
148
+ the account drawer, and the host's own menu primitive under the hero row's
149
+ workspace and preset pickers — is meant to start from one recipe. New popovers
150
+ take it rather than inventing a card.
150
151
 
151
152
  Two rules hold across all of them, both owned by `shared/popover.js`. A
152
153
  pointer opens a card only after a **100 ms dwell** — long enough that crossing a
153
154
  28px trigger on the way somewhere else unfolds nothing — and the card closes
154
- 100 ms after the pointer leaves. Two cards keep their own numbers with the reason
155
- written where they are used: the model picker's levels close after 150 ms (the
156
- pointer has to cross level 1 to reach level 2) and the session-stats card waits
157
- 300 ms to open (its sentence sits mid-row, where a passing pointer would trip
158
- it). And **only one card is on screen at a time**: each popover registers its
159
- close path with `registerPopover(name, close)` and calls
160
- `closeOtherPopovers(name)` on the way open, so opening the model picker folds the
161
- permission menu, the account drawer, the stats card and the host's hero menu.
155
+ 100 ms after the pointer leaves. One card keeps its own number with the reason
156
+ written where it is used: the model picker's levels close after 150 ms (the
157
+ pointer has to cross level 1 to reach level 2). And **only one card is on screen
158
+ at a time**: each popover registers its close path with `registerPopover(name,
159
+ close)` and calls `closeOtherPopovers(name)` on the way open, so opening the
160
+ model picker folds the permission menu, the account drawer and the host's hero
161
+ menu.
162
+
163
+ The context meter's popover is the host's own panel (it portals it, places it,
164
+ and dismisses it), so the skin drives its trigger on hover and paints nothing of
165
+ the shell itself. What it carries is described under "Context popover" below.
162
166
 
163
167
  **Card**
164
168
 
@@ -217,9 +221,56 @@ two-line entries. The workspace card is Claude Code's folder menu: a 180px-min
217
221
  card with 4px padding, 26px plain-text rows (no folder glyph in front of each
218
222
  folder, no `+` on the pinned add row) and the accent check on the current one.
219
223
 
220
- **All five are aligned**: the account drawer and the stats card were the outliers
224
+ **The account card** is that primitive too, and it carries the skin's rows
225
+ inside it. The host mounts it with nothing but its own three entries and places
226
+ it from that geometry; `features/account/surface.js` injects the skin's container
227
+ a frame later, the card grows, and the host re-places it on the frame after the
228
+ list changed. Nothing may be painted in between: the card would fade in at the
229
+ height and the place it is about to leave — low, then jumping up mid-fade. So
230
+ while the account row is armed the card stays unpainted (the same armed window
231
+ that carries its one-shot entrance), and the feature stamps
232
+ `data-dsh-claude-account-ready` once the skin's rows are inside it and its
233
+ placement has been read twice with the same value. The entrance animation hangs
234
+ on that stamp, so it plays on the card the reader will actually see.
235
+
236
+ ## Context popover · 上下文弹层
237
+
238
+ The context meter's popover is the host's own panel: the skin opens it by
239
+ pressing the host's trigger (hover, with the shared 100 ms dwell and close
240
+ grace, gated on the "open popovers on hover" preference; a click still works),
241
+ and paints nothing of its shell, its placement or its dismissal. It mounts
242
+ instead of toggling `data-open`, so the feature stamps the panel and it takes
243
+ the cards' own short rise as a one-shot animation — same 4px, same `scale(.98)`,
244
+ same 0.15s — and a surface the skin opens arrives the same way wherever it is
245
+ the host's.
246
+
247
+ What the skin appends to it is the session's numbers
248
+ (`features/permissions/session-stats.js`), read from the host's `sessionStats`
249
+ and `tokenUsage` projections — the same durable whole-log values the host's own
250
+ pills render — never by opening the host's stat dialogs. The labels and the
251
+ duration / token templates come from the host's `chat` locale namespace, so the
252
+ two surfaces read the same words; the host's small formatting rules
253
+ (`formatDuration`, `formatTokensPerSecond`, `formatExactTokens`,
254
+ `formatCacheHitPercent`) are mirrored so the figures match character for
255
+ character.
256
+
257
+ The block: a 1px `var(--dsw-alias-border-l1)` rule and 10px above it, then per
258
+ section an 11px / 16px heading at 600 in `label-tertiary` and a two-column grid
259
+ (6px by 10px). A row is a stack: 12px / 16px label in `label-tertiary` over a
260
+ 14px / 20px value at 500 in `label-primary`, the value in tabular figures so
261
+ numbers do not dance as they change. Rows follow the host's own rules — one
262
+ appears only when its input exists — and the block is rewritten on every
263
+ projection frame while the panel is open.
264
+
265
+ While the projections have answered nothing, the block holds the numbers' place
266
+ under the two real headings: bars at a row's own 37px (16 + 1 + 20) in the host's
267
+ solid hover fill, pulsing over 1.6s (still under the reduced animation choice).
268
+ The place is given up after 2s, so a host that serves no such projection ends at
269
+ the panel it drew itself rather than keeping placeholder bars.
270
+
271
+ **All five are aligned**: the account drawer was the outlier
221
272
  (8px row radius, 2px and 4px card gap, 8px padding, 220 / 260px min-width,
222
- z-index 1000 and 100000) and now follow the table above. The hero row's pickers are the host's own menu primitive, which differs in
273
+ z-index 1000 and 100000) and now follows the table above. The hero row's pickers are the host's own menu primitive, which differs in
223
274
  two ways that CSS cannot change: it mounts instead of toggling a `data-open`
224
275
  attribute, so it takes the same fade/scale as a one-shot `0.15s` animation; and
225
276
  the host places it *below* its trigger, which is where the composer sits — so
@@ -273,9 +324,10 @@ content size (13px, 24px line), one line with an ellipsis. Parts are joined by
273
324
  ` · `: `elapsed · N tokens · action` while the turn runs, `Stopped` or `Failed`
274
325
  (the host's words) `· duration · N tokens` after; the token part is left out
275
326
  until a finished step has reported usage. While the turn runs the spark turns a
276
- full circle every 2.4s, breathing down to 78% at the half turn, in every motion
277
- setting, like the sidebar's background-work ring; a stopped or failed turn's
278
- spark stands still. A turn that finishes normally keeps the host's own control.
327
+ full circle every 2.4s, breathing down to 78% at the half turn, in every
328
+ animation setting, like the sidebar's background-work ring; a stopped or failed
329
+ turn's spark stands still. A turn that finishes normally keeps the host's own
330
+ control.
279
331
 
280
332
  ## Home layouts · 首页版面
281
333
 
@@ -404,9 +456,10 @@ when the pointer leaves it, and on its own every 25–45 seconds while the page
404
456
  in view, it plays Claude Code's fishing routine, 43 frames of 80ms (3.44s): a
405
457
  blink, the rod raised overhead and cast down past the card's edge, a hop into a
406
458
  side-on stance, a spell of fishing, and the rod reeled in as it turns back to
407
- face front. With reduced motion requested, only a click plays it: the pointer
408
- passing by and the idle timer leave it still. Only the crab takes the pointer;
409
- the room the rod swings through does not.
459
+ face front. With the animation choice resolved to "reduced" (the settings page's
460
+ Animation row, or the system's own setting under "follow the system"), only a
461
+ click plays it: the pointer passing by and the idle timer leave it still. Only
462
+ the crab takes the pointer; the room the rod swings through does not.
410
463
 
411
464
  ## Deepy · 小鲸鱼
412
465
 
@@ -423,8 +476,9 @@ screens without `image-rendering: pixelated`, which would drop rows on a
423
476
  downscale. The body is Deepy's blue `#4E6FFF` with a navy `#142660` outline and
424
477
  a white belly in both themes; on the dark canvas the outline and the soft shadow
425
478
  recede and the blue body carries the shape. Only the resting body (columns
426
- 12–44, rows 30–48) takes the pointer. With reduced motion requested each state
427
- holds its still frame; a click or a pull still plays its reaction.
479
+ 12–44, rows 30–48) takes the pointer. With the animation choice resolved to
480
+ "reduced" each state holds its still frame; a click or a pull still plays its
481
+ reaction.
428
482
 
429
483
  | State | Animation | Still frame |
430
484
  |---|---|---|