Theflowyears/dsh-arknights-theme ↗★ 1
dsh-arknights-theme
Arknights theme pack for the DSH Web GUI: wallpaper skin with saturation-driven edge blur, an acrylic sidebar, a Rhodes Island icon treatment, and a one-click wallpaper picker. 适合想要个性化明日方舟主题界面、自适应壁纸和亚克力侧栏的用户。
Install
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Theflowyears/dsh-arknights-themeREADME
Read the full README ↗明日方舟主题美化包 · Arknights Theme Pack
给 DeepSeek Harness Web 界面套一层明日方舟的皮:整屏壁纸、按壁纸饱和度自适应的边缘虚化、亚克力侧栏、 罗德岛图标体系,以及一键换壁纸的挑选器。
An Arknights theme pack for the DeepSeek Harness Web GUI: fullscreen wallpapers with saturation-driven edge blur, an acrylic sidebar, a Rhodes Island icon treatment, and a one-click wallpaper picker.
安装 / Install
dsh plugin add Theflowyears/dsh-arknights-theme
重启 dsh web 后刷新页面。插件往 package.json 里声明了 dsh.bundle,所以可以按仓库直接安装。
Requires a DSH build whose @deepseek-ai/cordis is 4.x. Restart dsh web after installing.
功能 / What it does
- 壁纸皮肤:12 张壁纸,16:9 与 3:4 两种切幅按窗口比例自动切换;边缘处的虚化强度与羽化宽度由每张图 自身的饱和度算出,不是一套固定参数。
- 对比度可控:对话框面、面板、侧栏的不透明度按「壁纸最坏情况 + 当前配色」逐张解算,沉浸度滑杆在 「看得清」与「看得见壁纸」之间连续插值,面板始终不透明以保证可读。
- 自适应文字色:文字色取壁纸主色相,用 OKLCH 求解亮度,保证在最差面板上仍达 WCAG AA(正文 ≥4.5:1)。
- 亚克力侧栏与顶栏一体处理:不额外加板子,靠同一层材质与发丝边。
- 一键换壁纸:选择器显示高清预览图(640×360)、沉浸度与实测对比度;另有「切换」按钮一键下一张 (Shift 反向)。选择会被记住,重启后仍在。
- 罗德岛图标体系:文件夹、折叠、面板等图标换成 PRTS 素材。
- 签名的权限批准条:工具请求授权时弹出的确认卡上,「允许」带阿米娅的签名、「拒绝」带凯尔希的签名——
跟签批一样,每个签名落在各自按钮的文字后面。签名用图片的 alpha 通道上色(
mask-image),所以不会是 「浅色盖浅色」那种看不见的效果。
截图 / Screenshots
见 screenshots.json(选用的是壁纸挑选器里的预览图)。界面截图欢迎提 PR 补充。
素材与版权 / Assets and rights
代码 MIT;美术素材不是。 壁纸版权归鹰角网络(Hypergryph)所有,每张插画仍归其画师本人所有; 图标取自 PRTS Wiki。素材仅供个人本地使用,请勿商用或再分发。画师名单见 ARTWORK-ATTRIBUTION.md(壁纸选择界面里也有一份可折叠的名单),图标来源在 ICON-ATTRIBUTION.md。
画师 / Illustrators: 阿没MEInoss · soho · ぷらねっと · NUEE · 史里爬 · 最上-川 · Coomlee · momostima
以下是本项目的实现说明(架构、透明层与对比度解算、构建流程):
dsh-amiya-wallpaper
An Arknights / Amiya wallpaper skin for the DSH Web GUI.
It does four things:
- Fullscreen wallpapers from your own images. Twelve wallpapers generated by the import module, each rendered to a 16:9 and a 3:4 cut and switchable from a picker at the sidebar foot.
- Saturation-driven edge treatment. Every image is analysed, and the more saturated it is, the harder its two side bands are blurred and the wider the gradient that blends them into the centre. A wide landscape keeps its centre sharp edge to edge; anything narrower grows blurred wings at the sides.
- An iOS-style acrylic left column. The sidebar column gets a real
backdrop-filterfrost over the wallpaper, with the tint supplied by the--dsw-specific-sidebar-filltoken. - A Rhodes Island icon treatment. Amiya's brand mark and wordmark are registered through the real sidebar slots, the sidebar's own glyphs are replaced with authored Arknights-style SVG, and the palette shifts to the game's amber-on-slate glass.
Install
node ../install.mjs # from this directory
node ../install.mjs --dry-run # print the plan first
node ../uninstall.mjs # undo
The installer copies this package into the profile's module path and appends
dsh-amiya-wallpaper to that profile's dsh.profile.bundles. Restart DSH
afterwards. To install elsewhere:
node ../install.mjs --target "D:/other/dsh/profiles/web"
Using it
- 壁纸 button at the sidebar foot opens the picker. It shows all twelve wallpapers with their analysis label, and remembers your choice.
- The Amiya mark replaces the sidebar brand mark; the wordmark replaces the build string beside it.
- Settings → Appearance also lists an
arknights-amiyatheme. The skin's glass palette is applied over whatever theme is active, so selecting it is optional — it is there if you want the palette to persist independently.
Files
| Path | Role |
|---|---|
lib/index.js | Host half. Serves assets/ and icons/ over one read-only /amiya-wallpaper prefix route. |
lib/client.js | Generated browser half: wallpaper painting, acrylic CSS, token layer, slot occupants. |
cordis.patch.yml | Inserts the loader row (ui-skin-amiya-wallpaper) when the bundle is composed. |
assets/wallpapers.json | The manifest: per-image analysis, treatment numbers, labels, palettes. |
assets/*.webp | The generated wallpaper cuts. |
assets/skin.css | The fully-substituted stylesheet, usable standalone. |
icons/hazard-rule.svg | The one authored glyph — a decorative caution stripe, not game art. |
ICON-ATTRIBUTION.md | Per-glyph PRTS provenance for every icon inlined in the bundle. |
Every other glyph in the bundle is a real game asset from the PRTS wiki,
inlined as a data URI by the build step. prts/ in the toolchain directory holds
the downloaded originals and is deliberately not part of this package, so no
Hypergryph binaries are redistributed with it.
How the edge treatment is decided
The import module measures each source image on a 128px downsample: mean HSV saturation, the saturation's spread, mean value (luminance), and a saturation-weighted circular mean hue. From those it derives:
| Quantity | Range | Driver |
|---|---|---|
blurSigma | 12 – 62 | busyness = 0.7·saturation + 0.6·spread, scaled by canvas width |
featherRatio | 10% – 21% per side | the same busyness |
scrimAlpha | 0.12 – 0.46 | busyness and luminance — a bright loud image gets the strongest scrim |
wingSaturation | 1.04 – 1.22 | the blurred wings keep their colour rather than washing to grey |
For the twelve images in this set that produces saturation → blurSigma from
0.065 → 17 up to 0.418 → 33: the near-monochrome image gets a light touch and
the busiest one gets the heaviest.
Rendering per cut:
- Fill layer — cover-crop to the canvas, blur by
blurSigma, saturation and brightness lifted, so the canvas is always completely filled. - Subject layer — a source at least as wide as the canvas keeps
coversizing, so its centre is untouched; anything narrower is height-fitted and therefore gains wings on both sides. - Feather — the subject's own left and right edges are multiplied by a
smoothstep alpha ramp (
dest-in), so the seam into the fill layer is a gradient, never a cut. A small floor keeps a hint of the subject's edge. - Scrim — a squared-falloff black gradient over the outer bands, so sidebar and title-row labels keep their contrast.
verify-assets.mjs in the parent directory measures the result: it computes the
mean absolute Laplacian (a focus measure) over narrow edge bands and over the
centre band of each generated asset and compares both against the same bands of
the source image.
How text stays readable
Two rules, and they are not stylistic:
The label colour is never overridden. Text colour always comes from the active palette. An earlier revision forced a near-white label in both palette modes, which made text vanish wherever the light palette's surfaces were still light — the composer tip card, the directory-flow panel, the input field. Forcing one label polarity while the other palette's surfaces stay untouched is the whole failure mode.
The glass is solved per wallpaper and per palette. CSS composites alpha in
sRGB space, so a veil composited over the picture's measured mean colour is the
backdrop the text will sit on. The build step binary-searches the smallest
opacity that reaches 7:1 WCAG contrast against that palette's label colour, so a
bright picture earns a heavier veil than a dark one and no wallpaper can push the
text below the target. The solved numbers travel per wallpaper in tokens (for
overrideTokens) and glass (for the --dsw-specific-* surfaces in
skin.css).
Measured worst case, over 12 wallpapers × 2 palettes × 3 surface classes:
6.99:1. See ../README.md for the solver and ../verify-assets.mjs for the
measurement.
Selector strategy
DSH emits CSS-module class names as _, and the hash changes on
every rebuild. So skin.css never hard-codes a hash. It matches on the local
name with attribute selectors:
[class*="_sidebarCol"] { backdrop-filter: blur(32px) saturate(190%); }
[class$="_newSession"] > svg { display: none; } /* $= because a settings switch is also a _toggle */
Local names are the stable half of the generated name, so these survive an
upgrade that rehashes the build. Where a name could plausibly appear on another
control the selector is anchored with $= instead of *=.
Where no class name is knowable: use the role
The permission windows, the preset menu and every other popup come from the shared primitive library, whose CSS-module hashes cannot be read from here — and guessing them would break on the next rebuild. Their roles are knowable though, and they are semantic rather than generated:
| Hook | What it addresses |
|---|---|
[role="dialog"], [role="alertdialog"] | any modal, including the full-access gate |
[role="menu"], [role="listbox"] | a popup menu or select list |
[role="menuitem"], [role="menuitemradio"], [role="option"] | its rows |
aria-checked="true", aria-selected="true" | the row in force |
So the Arknights frame (amber hairline, corner bracket, cut radius, amber bar on the chosen row) is applied through roles, and the colour comes from the tokens: the warning family is remapped to the interface amber, which turns the approval card's border and warning strip amber without needing to name them, and the dialog and menu surfaces are already the solved glass.
Every surface token, not just the obvious ones
The palette declares its surfaces across several families, and a skin that
handles only some of them leaves the rest at the other palette's colour. These
are all set per palette in skin.css, because each one is a place text can land:
--dsw-alias-bg-base, -layer-1, -layer-2, -layer-3, -overlay,
-mask-1, -module-platform, --dsw-specific-sidebar-fill, -tip,
-input-major, -bubble, -bubble-highlight, -menu, -selector,
-login-input, -sidebar-nav-item-active, -hover, -active-accent,
--dsw-alias-interactive-bg-hover, -hover-danger.
Extending it
More wallpapers — drop images into F:\DSHtemporary\WallPapar (or any
directory), re-run the pipeline in the parent directory, and re-run
build-client.mjs; the picker and the theme's per-wallpaper accent follow the
manifest automatically.
More icons — add an entry to ../prts-assets.json (name, PRTS File: title,
role, and the media.prts.wiki URL from the imageinfo API), run
node ../fetch-prts-icons.mjs, then reference it from ../skin.css with a
url("__ICON_NAME__") slot and add that slot to CSS_ICON_SLOTS in
../build-client.mjs. Never hand-draw a replacement for something the game
already has.
Visual vocabulary
The interface language is Hypergryph's, taken from the game itself rather than
approximated: cut-corner machined panels over rounded shapes, thin technical
linework, originium crystals as the recurring small motif, and one warm amber
(#f2b544) carried against cold steel structure — plus a dark glass veil so the
wallpaper stays legible behind the interface.
Specifically, the skin uses these PRTS assets:
| Where | Asset |
|---|---|
sidebar.brand.mark | Logo 罗德岛.png — the Rhodes Island emblem |
| Sidebar wordmark | text (RHODES ISLAND / AMIYA / DSH) |
| New-session glyph | the supplied Avatar_special_35.png, cut to a lit circle at 28px. The file is a 150×150 scene with a black vignette on every edge and no transparency, so it is passed through the medallion transform: the crop locks onto the brightest mass, a soft circular mask drops the frame, and gamma compresses the highlights (a plain brightness lift turned it into a white blob — the disc now measures 99 mean luma with no clipped pixels) |
| Workspace / working-directory glyph | 道具 源石碎片.png, lifted to a pale steel silhouette; amber 道具 至纯源石.png on the active row |
| Footer wallpaper button | 头像 阿米娅.png — Amiya, cropped round behind an amber ring |
| Blank-session hero | the game's own wordmark, Logo 明日方舟.svg, in front of 探索未至之境 where the host draws its fish. Rasterised at build time to a 172×96 PNG (3.3 KiB) — inlining the 52 KiB SVG for something shown at 48px tall would be 16× the bytes for no visible gain — and sized by height so the 203:113 aspect survives. The wordmark's own fill is #ffffff, which is invisible on the light palette's plate, so it is recoloured per palette: knocked down to black ink on the light glass, left white on the dark. brightness(0) keeps the alpha, so only the letterforms change |
| Composer control | the current picture's own thumbnail; opens the picker |
| Composer dock ribbon | Logo 罗德岛-精英干员.png — the Rhodes Island elite emblem |
| Dispatch bar signature | Kal'tsit's autograph from signatures/kaltsit.png, riding in the control row's trailing group — between the wallpaper controls and the model switcher. It is recoloured through mask-image (the art supplies only its alpha) rather than a filter chain: invert(1) sepia(1) on black ink yields pale yellow, which measured 1.02:1 on the light palette, i.e. invisible. It is now rgb(255 206 98) on the dark glass (6.2:1) and rgb(74 44 0) on the light (4.8:1), dilated 0.5px to thicken strokes that are barely a pixel wide. Amiya's PRTS autograph is the fallback if the file goes missing |
| Picker header signature | 收藏贴 阿米娅签名.png — Amiya's own handwriting (11.8:1 on the picker's dark plate). A separate slot from the dispatch bar's: they were one slot for a while, and swapping it to Kal'tsit silently took Amiya's off the picker |
| Instrument strip glyphs | the two session-stat pills lead with national emblems instead of the host's gauge and database icons: Logo 谢拉格.png on the activity pill — 轮 / 步 / tok/s — and Logo 乌萨斯.png on the consumption pill — tok / cache hit. Both are 510×510 white line art, so they are painted through mask-image like the signatures (white ink would vanish on the light palette): rgb(255 206 98) on the dark glass, rgb(74 44 0) on the light. Set at 18px because heraldry at the host's 14px is a smudge. The wider national set (维多利亚, 哥伦比亚, 莱塔尼亚, 卡西米尔, 伊比利亚) is registered in prts-assets.json — swapping either crest is a one-word change |
| Approval panel | the host's permission prompt ([data-approval-key]), signed. 允许 carries Amiya's autograph, 拒绝 carries Kal'tsit's, each riding inside its own button after the label — the primitive Button is display: inline-flex with a 4px gap, so a pseudo-element lands after the text and no markup is invented. The refusal is outlined, so its ink sits on the card's own glass and takes the measured amber; the approval is filled from a host theme the skin cannot read, so its ink inherits the button's own color |
| Picker cells | the picture's own thumbnail, its number and its analysis label |
| Picker footer | the illustrator list, collapsed into a `` |
| Corner watermark | 头像 阿米娅 skin2.png, desaturated and blown out to a pale silhouette |
| Section and active marks | 道具 至纯源石.png |
Wallpaper illustrators. The set was supplied as a group without a file-by-file
mapping, so the names are credited as a group rather than guessed per picture:
阿没MEInoss · soho · ぷらねっと · NUEE · 史里爬 · 最上-川 · Coomlee · momostima.
The picker carries the same list in a collapsed ``, and
ARTWORK-ATTRIBUTION.md in the published repository holds the long form.
Authored rather than sourced (interface affordances, not game art — a game asset pressed into a fold button reads as an unidentifiable smudge at 18px):
panel-collapse/panel-expand— the sidebar fold glyphs, a panel outline with its divider and a double chevron, drawn at 2px so they stay legiblehazard-rule— the decorative caution stripe
On the operators
Six operator portraits are fetched and kept in the toolchain's prts/
(阿米娅, 迷迭香, 凯尔希, 陈, 能天使, 银灰). They are not rendered as
a per-wallpaper badge.
An earlier revision assigned every wallpaper an operator and a class crest by hue and sh