wallpaper-engine-dsh 2.0.0 → 2.1.1

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/README.md CHANGED
@@ -8,11 +8,11 @@ A DSH bundle that turns your local **Wallpaper Engine** library into the live ba
8
8
 
9
9
  **The library, rendered live.** The grid lists every wallpaper the browser can genuinely render — video and web wallpapers. Scene and application wallpapers are Wallpaper Engine's private `.pkg` scene packages; since no browser can execute them, they are filtered out rather than offered as degraded stills. Everything listed plays for real, badged Video or Web, and a search box narrows large libraries by title or workshop id instantly.
10
10
 
11
- **Legibility on any wallpaper.** Text stays readable by construction, not by luck. The veil always opposes the text colour — black in the dark theme, white in the light theme — so neither a pitch-black nor a pure-white wallpaper can swallow the UI. On top of that, a Smart veil samples the wallpaper's brightness every few seconds and automatically strengthens the veil when a scene drifts too bright (or too dark) for the current theme (web wallpapers' pixels are unreadable inside the sandbox, so their preview still stands in as the sample); it also strengthens the border contrast and the glass frosting on the same evidence. Dropdowns, menus, and dialogs sit on DSH's opaque surfaces and are never affected.
11
+ **Legibility on any wallpaper.** Text stays readable by construction, not by luck. The veil always opposes the text colour — black in the dark theme, white in the light theme — so neither a pitch-black nor a pure-white wallpaper can swallow the UI. On top of that, a Smart veil samples the wallpaper's brightness every few seconds and automatically strengthens the veil when a scene drifts too bright (or too dark) for the current theme (web wallpapers' pixels are unreadable inside the sandbox, so their preview still stands in as the sample). While a wallpaper is active, dropdown menus, the slash-command popup, the queue-dock panel, the settings dialog, and the image lightbox all render as frosted glass: the shell's own menu primitive carries an isolation property that silently kills its internal blur layer, so the plugin applies the blur on the surface element itself and deepens the menu fill, keeping overlay text readable over any wallpaper. Everything reverts to the host look when the wallpaper is off.
12
12
 
13
- **Manual framing.** Pick a base layout — Cover, Contain, Stretch, Original, or Free — then frame the shot yourself. **Adjust** opens the live wallpaper fullscreen: scroll to zoom, drag to pan. In the first four layouts the crop is clamped so the image always fills the screen with no exposed edges; **Free** places the wallpaper at natural size on a black canvas where it can be dragged anywhere, zoomed from 0.1× to 4×, and rotated to any angle (±90° buttons or Alt+drag), with just enough kept on screen that it can never be dragged out of sight. **Mirror** flips the wallpaper horizontally and works in every layout — a flip never exposes an edge. Esc or Done finishes, the framing persists, and **Reset crop** restores the default in one click. Web wallpapers take the same select and the same zoom/pan/rotate framing — the transform applies to the iframe directly.
13
+ **Manual framing.** Pick a base layout — Cover, Contain, Stretch, Original, or Free — then frame the shot yourself. **Adjust** opens the live wallpaper fullscreen: scroll to zoom, drag to pan. In the seamless layouts the picture already fills the screen at 100% — zoom in with the wheel first and panning unlocks (the hint bar says so). In the first four layouts the crop is clamped so the image always fills the screen with no exposed edges; **Free** places the wallpaper at natural size on a black canvas where it can be dragged anywhere, zoomed from 0.1× to 4×, and rotated to any angle (±90° buttons or Alt+drag), with just enough kept on screen that it can never be dragged out of sight. **Mirror** flips the wallpaper horizontally and works in every layout — a flip never exposes an edge. Esc or Done finishes, the framing persists, and **Reset crop** restores the default in one click. Web wallpapers take the same select and the same zoom/pan/rotate framing — the transform applies to the iframe directly.
14
14
 
15
- **Four live sliders.** Wallpaper blur, Scrim, Borders, and Glass — every change lands instantly and persists. Blur renders in place: composition, layout, and crop stay identical at every blur level, and within one blur radius of the screen edge the picture fades softly into the veil beneath the UI chrome. A whisper of dither noise keeps smooth gradients band-free; at zero blur the media bypasses the filter pipeline entirely for bit-exact pixels.
15
+ **Four live sliders.** Wallpaper blur, Scrim, Borders, and Glass — every change lands instantly and persists. Blur renders in place: composition, layout, and crop stay identical at every blur level, and within one blur radius of the screen edge the picture fades softly into the veil beneath the UI chrome. A whisper of dither noise keeps smooth gradients band-free; at zero blur the media bypasses the filter pipeline entirely for bit-exact pixels. The Glass slider's colour melt is anchored to the shell's own menu material: at the 40px ceiling it reproduces the host recipe blur(40px) saturate(150%) exactly, so full glass reads as one system with the shell's native frost.
16
16
 
17
17
  **Rotation lists.** Build any number of carousel lists, each with its own wallpapers, interval (1–120 min), and order (sequence or random). Auto-rotate arms once the active list holds at least two usable wallpapers; the status row always reports whether rotation is actually running. Your first playable Wallpaper Engine playlist is imported automatically on first run; any other playlist can be imported into any list.
18
18
 
@@ -48,6 +48,14 @@ Restart `dsh web`, then open **Settings → General → Wallpaper Engine**.
48
48
 
49
49
  Your selection and every knob persist in the browser's `localStorage`.
50
50
 
51
+ ## Desktop
52
+
53
+ The desktop shell and the browser share the same frontend and the same injection pipeline; the `platform: "web"` declaration works as-is, with no separate desktop package.
54
+
55
+ - **Windows**: the main window is opaque and the wallpaper renders at the DOM layer. The window-controls strip at the top is an opaque host-owned overlay; the plugin blends the wallpaper into it with a short fade in the overlay's own colour, and the fade switches off in fullscreen.
56
+ - **macOS**: the shell sidebar is the system's native vibrant material, so what shows behind the wallpaper there is the system material rather than the wallpaper itself — host behaviour.
57
+ - **With system transparency effects off** (`prefers-reduced-transparency`), all glass and blur falls back to solid surfaces; the wallpaper stays, and legibility is carried by the veil and the solids.
58
+
51
59
  ## How it works
52
60
 
53
61
  The bundle has two halves:
package/README.zh.md CHANGED
@@ -8,11 +8,11 @@
8
8
 
9
9
  **只列出能真实播放的壁纸。** 网格中列出浏览器可以真实渲染的全部类型——视频与网页壁纸。场景/应用壁纸是 Wallpaper Engine 私有的 `.pkg` 场景包,浏览器无法执行,因此直接过滤,不以降级的静态图代替。列出的每张壁纸都真实播放,并按 视频/网页 标注类型;搜索框可按标题或创意工坊 ID 筛选较大的壁纸库。
10
10
 
11
- **任何壁纸上文字都可读。** 遮罩颜色始终与文字颜色相反:深色主题用黑色遮罩,浅色主题用白色遮罩,因此过亮或过暗的壁纸都不会盖住文字。在此基础上,「智能可视」每隔几秒采样一次壁纸亮度,亮度过高或过低时自动加强遮罩(网页壁纸的像素在沙箱中读不到,改用其预览图作为采样依据)。下拉菜单、弹窗等浮层显示在 DSH 原生的不透明表面上,不受影响。
11
+ **任何壁纸上文字都可读。** 遮罩颜色始终与文字颜色相反:深色主题用黑色遮罩,浅色主题用白色遮罩,因此过亮或过暗的壁纸都不会盖住文字。在此基础上,「智能可视」每隔几秒采样一次壁纸亮度,亮度过高或过低时自动加强遮罩(网页壁纸的像素在沙箱中读不到,改用其预览图作为采样依据)。壁纸激活时,下拉菜单、斜杠命令提示框、队列面板、设置弹窗与图片灯箱统一为磨砂玻璃:外壳的菜单原语自身带隔离属性,其内部模糊层在宿主原样下并不生效,插件改为在 surface 元素上施加模糊,并把菜单底色加深,保证浮层文字在任意壁纸上可读;关闭壁纸后恢复宿主原样。
12
12
 
13
- **手动取景。** 先选基础排布(填充、适应、拉伸、原始、自由),再手动调整画面:点「调整画面」将壁纸全屏展开,滚轮缩放,拖动平移。前四种排布下裁剪范围经过限制,画面始终铺满屏幕,不露出边缘;「自由」把壁纸按原始大小放在黑色画布上,可拖动到任意位置,缩放范围 0.1–4×,并可旋转任意角度(±90° 按钮或 Alt+拖动),同时始终保留一小块在屏幕内,不会拖丢。「镜像」水平翻转壁纸,所有排布下都可用——翻转不会破坏铺满。按 Esc 或点「完成」退出,取景设置会保存,「重置裁剪」可一键恢复默认。网页壁纸使用相同的排布下拉与缩放/平移/旋转取景(变换直接作用于 iframe)。
13
+ **手动取景。** 先选基础排布(填充、适应、拉伸、原始、自由),再手动调整画面:点「调整画面」将壁纸全屏展开,滚轮缩放,拖动平移。填充等无缝排布下,画面在 100% 倍率时已铺满屏幕,先滚轮放大后拖动平移才会生效(提示条会同步说明)。前四种排布下裁剪范围经过限制,画面始终铺满屏幕,不露出边缘;「自由」把壁纸按原始大小放在黑色画布上,可拖动到任意位置,缩放范围 0.1–4×,并可旋转任意角度(±90° 按钮或 Alt+拖动),同时始终保留一小块在屏幕内,不会拖丢。「镜像」水平翻转壁纸,所有排布下都可用——翻转不会破坏铺满。按 Esc 或点「完成」退出,取景设置会保存,「重置裁剪」可一键恢复默认。网页壁纸使用相同的排布下拉与缩放/平移/旋转取景(变换直接作用于 iframe)。
14
14
 
15
- **四个实时滑杆。** 壁纸模糊、暗化、边框、玻璃,每一步调节立即生效并保存。模糊在原位渲染:任意模糊度下,画面的比例、排布与取景完全一致;屏幕边缘一个模糊半径内的画面向遮罩过渡,被界面边饰覆盖,通常不可见。模糊时叠加轻微噪声,消除渐变色带;模糊为零时媒体完全绕过滤镜管线,像素保持不变。
15
+ **四个实时滑杆。** 壁纸模糊、暗化、边框、玻璃,每一步调节立即生效并保存。模糊在原位渲染:任意模糊度下,画面的比例、排布与取景完全一致;屏幕边缘一个模糊半径内的画面向遮罩过渡,被界面边饰覆盖,通常不可见。模糊时叠加轻微噪声,消除渐变色带;模糊为零时媒体完全绕过滤镜管线,像素保持不变。玻璃滑杆的「色彩熔融」在 40px 满档时正好等于外壳官方菜单材质的配方(blur(40px) saturate(150%)),满档玻璃与外壳原生磨砂观感一致。
16
16
 
17
17
  **轮播列表。** 可以创建任意多个列表,各自指定壁纸集合、切换间隔(1–120 分钟)与顺序(顺序/随机)。当前列表至少有两张可用壁纸时才会自动轮转;状态行始终显示轮转是否正在运行。首次运行会自动导入第一个可播放的 Wallpaper Engine 播放列表,其他播放列表也可随时导入到任意列表。
18
18
 
@@ -48,6 +48,14 @@ dsh plugin --profile web add link:<克隆文件夹的绝对路径>
48
48
 
49
49
  你的选择与每一项调节都持久化在浏览器的 `localStorage` 中。
50
50
 
51
+ ## 桌面端
52
+
53
+ 桌面端与浏览器共用同一前端和同一注入管道,`platform: "web"` 声明即可生效,无需单独的桌面包。
54
+
55
+ - **Windows**:主窗口不透明,壁纸渲染在 DOM 层。顶部窗口控制按钮条是宿主维护的实色 overlay,插件用一条与 overlay 同色的短渐变把壁纸衔接过去,弱化接缝;进入全屏时自动关闭。
56
+ - **macOS**:外壳侧栏为系统原生 vibrant 材质,壁纸在其后播放时透出的是系统材质而非壁纸本身,为外壳既定行为。
57
+ - **系统关闭透明效果**(`prefers-reduced-transparency`)时,玻璃与模糊全部退为实色表面,壁纸保留,可读性由遮罩与实色表面保证。
58
+
51
59
  ## 工作原理
52
60
 
53
61
  bundle 分为两半:
package/lib/client.js CHANGED
@@ -10,10 +10,11 @@ window.__ModuleLoader__.load({
10
10
  const SETTINGS_KEY = "wallpaper-engine-dsh:selection";
11
11
  const INVENTORY_URL = "/we-background/inventory";
12
12
  const ACTIVE_ATTR = "data-webg-wallpaper";
13
- // Plugin-owned dark-theme signal for CSS. The shell's old dark-mode body
14
- // attribute is gone in DSH >= 0.2.1-rc.5; the client now derives dark from
15
- // the shell's theme service and mirrors it here, so the stylesheet never
16
- // keys off host DOM internals.
13
+ // Plugin-owned dark-theme signal for CSS. The shell's own dark-mode body
14
+ // attribute still exists in 0.2.1-rc.5 (its writer moved to the layout
15
+ // theme presenter), but the stylesheet never keys off host DOM internals:
16
+ // the client derives dark from the shell's theme service and mirrors it
17
+ // here, so a host-side restructure can never silently break the glass.
17
18
  const DARK_ATTR = "data-webg-dark";
18
19
  const LAYER_ID = "wallpaper-engine-dsh-layer";
19
20
  const SCRIM_ID = "wallpaper-engine-dsh-scrim";
@@ -101,6 +102,7 @@ window.__ModuleLoader__.load({
101
102
  adjustDone: "完成",
102
103
  adjustHint: "拖动平移 · 滚轮缩放 · Esc 或点「完成」退出",
103
104
  adjustHintFree: "拖动平移 · 滚轮缩放 · Alt+拖动旋转 · Esc 或点「完成」退出",
105
+ adjustHintZoom: "当前倍数下画面已铺满,先滚轮放大,即可拖动平移",
104
106
  mirror: "镜像",
105
107
  rotateCcw: "⟲",
106
108
  rotateCw: "⟳",
@@ -185,6 +187,7 @@ window.__ModuleLoader__.load({
185
187
  adjustDone: "Done",
186
188
  adjustHint: "Drag to pan · wheel to zoom · Esc or Done to exit",
187
189
  adjustHintFree: "Drag to pan · wheel to zoom · Alt+drag to rotate · Esc or Done to exit",
190
+ adjustHintZoom: "The picture already fills the screen — zoom in with the wheel to unlock panning",
188
191
  mirror: "Mirror",
189
192
  rotateCcw: "⟲",
190
193
  rotateCw: "⟳",
@@ -828,7 +831,15 @@ window.__ModuleLoader__.load({
828
831
  bar.className = "webg-adjust-bar";
829
832
  const hint = document.createElement("span");
830
833
  hint.className = "webg-adjust-hint";
831
- hint.textContent = isFreeFit() ? S().adjustHintFree : S().adjustHint;
834
+ const updateHint = () => {
835
+ // Pan feedback: in the gap-free fits the pan headroom is (zoom-1)*50,
836
+ // so at zoom 1 dragging is pinned BY DESIGN - say so instead of
837
+ // leaving a silent no-op that reads as "pan is broken".
838
+ hint.textContent = isFreeFit() ? S().adjustHintFree
839
+ : selection.zoom > 1 ? S().adjustHint
840
+ : S().adjustHintZoom;
841
+ };
842
+ updateHint();
832
843
  const done = document.createElement("button");
833
844
  done.type = "button";
834
845
  done.className = "webg-btn webg-btn--primary";
@@ -900,6 +911,7 @@ window.__ModuleLoader__.load({
900
911
  clampCrop(); // mode envelope: gap-free pan headroom, or free keep-visible
901
912
  drag = { x: e.clientX, y: e.clientY };
902
913
  applyEffects();
914
+ updateHint();
903
915
  };
904
916
  const endPointer = () => {
905
917
  if (rot) { rot = null; persistSelection(); return; }
@@ -920,6 +932,7 @@ window.__ModuleLoader__.load({
920
932
  selection.zoom *= Math.exp(-(e.deltaY || 0) * 0.0012);
921
933
  clampCrop();
922
934
  applyEffects();
935
+ updateHint();
923
936
  persistSelection();
924
937
  };
925
938
  const onKey = (e) => { if (e.key === "Escape") exitAdjust(); };
@@ -1203,9 +1216,22 @@ window.__ModuleLoader__.load({
1203
1216
  s.setProperty("--webg-scrim-color", veilColor);
1204
1217
  s.setProperty("--webg-border-alpha", String(selection.border));
1205
1218
  s.setProperty("--webg-blur", selection.blur + "px");
1206
- // The glass "colour melt" scales with blur radius: 0 blur → no melt.
1207
- s.setProperty("--webg-saturate", String(1.15 + selection.blur * 0.028));
1219
+ // The glass "colour melt" anchors at the shell's own menu material: the
1220
+ // slider's 40px ceiling reproduces the host recipe blur(40px) saturate(150%)
1221
+ // exactly, so full glass and the host's frosted chrome read as one system.
1222
+ s.setProperty("--webg-saturate", String(1 + selection.blur * 0.0125));
1208
1223
  s.setProperty("--webg-glass-brightness", "1.04");
1224
+ // Modal masks (settings dialog, image lightbox) read the shell's mask-blur
1225
+ // token — wire it to the glass slider so modals frost the app behind them
1226
+ // instead of showing the wallpaper sharply through a translucent mask.
1227
+ // Capped: a 40px blur on a full-viewport backdrop costs more GPU than the
1228
+ // effect is worth.
1229
+ // Gated on an active selection: this is a HOST token, so masks must not
1230
+ // blur the app while no wallpaper runs. At 0 blur: none - no layer, no cost.
1231
+ s.setProperty("--dsw-mask-blur",
1232
+ selection.id && selection.blur > 0
1233
+ ? "blur(" + Math.min(selection.blur, 20) + "px)"
1234
+ : "none");
1209
1235
  // At 0 blur, keep the media OUT of the filter pipeline entirely: even
1210
1236
  // blur(0px) forces an extra raster/compositing pass, and the noise overlay
1211
1237
  // would still occupy a layer at opacity 0. filter:none + display:none keep
@@ -1243,6 +1269,7 @@ window.__ModuleLoader__.load({
1243
1269
  s.removeProperty("--webg-scrim-color");
1244
1270
  s.removeProperty("--webg-border-alpha");
1245
1271
  s.removeProperty("--webg-blur");
1272
+ s.removeProperty("--dsw-mask-blur"); // restore the host's own mask token
1246
1273
  s.removeProperty("--webg-saturate");
1247
1274
  s.removeProperty("--webg-glass-brightness");
1248
1275
  s.removeProperty("--webg-media-filter");
@@ -1881,12 +1908,18 @@ window.__ModuleLoader__.load({
1881
1908
  .webg-adjust {
1882
1909
  position: fixed; inset: 0; z-index: 2147483000;
1883
1910
  cursor: grab; touch-action: none;
1911
+ /* Desktop: the shell titlebar strip is a window-drag region and the
1912
+ union drag region ignores z-order - without no-drag, drags starting
1913
+ near the top of the adjust overlay move the WINDOW instead of
1914
+ panning, and the bar's Done button stops receiving clicks. */
1915
+ -webkit-app-region: no-drag;
1916
+ app-region: no-drag;
1884
1917
  }
1885
1918
  .webg-adjust:active { cursor: grabbing; }
1886
1919
  .webg-adjust .webg-layer { position: absolute; z-index: 0; }
1887
1920
  .webg-adjust-bar {
1888
1921
  position: absolute; top: 18px; left: 50%; transform: translateX(-50%);
1889
- z-index: 1; cursor: default;
1922
+ z-index: 1; cursor: default; -webkit-app-region: no-drag; app-region: no-drag;
1890
1923
  display: flex; align-items: center; gap: 12px;
1891
1924
  padding: 8px 8px 8px 14px; border-radius: 12px;
1892
1925
  background: var(--dsw-alias-bg-overlay, rgba(30, 32, 38, 0.85));
@@ -1952,14 +1985,91 @@ window.__ModuleLoader__.load({
1952
1985
  }
1953
1986
  body[${ACTIVE_ATTR}] [data-composer-card],
1954
1987
  body[${ACTIVE_ATTR}] [class*="_bubble"] {
1955
- background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.05) 38%, rgba(255, 255, 255, 0.02));
1956
- -webkit-backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.8)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
1957
- backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.8)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
1988
+ background-image: linear-gradient(165deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.06) 32%, rgba(255, 255, 255, 0.02));
1989
+ -webkit-backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.2)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
1990
+ backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.2)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
1958
1991
  box-shadow:
1959
- inset 0 1px 0 rgba(255, 255, 255, 0.32),
1960
- inset 0 -1px 0 rgba(255, 255, 255, 0.08),
1961
- inset 0 0 0 0.5px rgba(255, 255, 255, 0.08),
1962
- 0 12px 40px rgba(0, 0, 0, 0.12);
1992
+ inset 0 1px 0 rgba(255, 255, 255, 0.36),
1993
+ inset 0 -1px 0 rgba(255, 255, 255, 0.10),
1994
+ inset 0 0 0 0.5px rgba(255, 255, 255, 0.10),
1995
+ 0 12px 40px rgba(0, 0, 0, 0.14);
1996
+ }
1997
+
1998
+ /* Menu + queue-dock surface repair (wallpaper active). The shell's
1999
+ menu primitive parks fill and blur on a child layer while the
2000
+ surface element itself is isolated - an isolated ancestor forms
2001
+ a backdrop root, so the blur only samples the panel interior.
2002
+ Same on the queue dock panel (:before carries the blur). With a
2003
+ wallpaper active, menus showed sharp content through a 45% fill.
2004
+ An element's OWN backdrop-filter ignores its own isolation, so
2005
+ the filter moves onto the surface element; fill deepened 85%. */
2006
+ body[${ACTIVE_ATTR}] { --dsw-menu-surface-fill: rgba(67, 69, 74, 0.85); }
2007
+ body[${ACTIVE_ATTR}]:not([${DARK_ATTR}]) { --dsw-menu-surface-fill: rgba(248, 249, 250, 0.85); }
2008
+ body[${ACTIVE_ATTR}] [data-menu-material],
2009
+ body[${ACTIVE_ATTR}] [data-composer-dock] [class*="_panel"] {
2010
+ -webkit-backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.2)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
2011
+ backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.2)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
2012
+ }
2013
+
2014
+ /* Settings modal and sibling dialogs: the shell paints dialogs on
2015
+ an opaque layer-2 panel. While a wallpaper is active, dialogs
2016
+ join the glass system - the mask behind them already frosts the
2017
+ app (the mask blur token is wired to the glass slider in
2018
+ applyEffects). color-mix keeps the host hue at 80% opacity.
2019
+ [class*="_dialog_"] matches only the module-suffix panel class;
2020
+ compounds like _dialogHeader lack the underscore segment. */
2021
+ body[${ACTIVE_ATTR}] [class*="_dialog_"] {
2022
+ background-color: color-mix(in srgb, var(--dsw-alias-bg-layer-2) 80%, transparent);
2023
+ -webkit-backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.2)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
2024
+ backdrop-filter: blur(var(--webg-blur, 16px)) saturate(var(--webg-saturate, 1.2)) brightness(var(--webg-glass-brightness, 1.04)) contrast(1.01);
2025
+ }
2026
+
2027
+ /* Windows desktop: the window-controls strip is an opaque host
2028
+ overlay (titleBarOverlay colour, fed from the renderer-measured
2029
+ palette). Blend the wallpaper up into it with a short fade from
2030
+ the overlay's own colour (dark #1b1b1c / light #f9fafb), scoped
2031
+ to the desktop marker html[data-windows-titlebar] (absent in
2032
+ browsers) and off in fullscreen. Pure CSS: the fill var flips
2033
+ with the plugin dark mirror attribute, no JS involved. */
2034
+ body[${DARK_ATTR}] { --webg-titlebar-fill: #1b1b1c; }
2035
+ body:not([${DARK_ATTR}]) { --webg-titlebar-fill: #f9fafb; }
2036
+ html[data-windows-titlebar]:not([data-fullscreen]) body[${ACTIVE_ATTR}] .webg-scrim::before {
2037
+ content: ""; position: absolute; top: 0; left: 0; right: 0;
2038
+ height: var(--dsh-windows-titlebar-height, 40px);
2039
+ background: linear-gradient(var(--webg-titlebar-fill, #1b1b1c), transparent);
2040
+ }
2041
+
2042
+ /* Accessibility: prefers-reduced-transparency (Windows transparency
2043
+ effects off, macOS Reduce transparency). Glass off, surfaces back
2044
+ to solid fills; the wallpaper stays, legibility carried by the
2045
+ veil and the solids. Selectors mirror the glass rules above so
2046
+ this block wins by document order. */
2047
+ @media (prefers-reduced-transparency: reduce) {
2048
+ body[${ACTIVE_ATTR}] {
2049
+ --dsw-specific-input-major: #26272c;
2050
+ --dsw-specific-bubble: #26272c;
2051
+ --dsw-menu-surface-fill: #43454a;
2052
+ --dsw-mask-blur: none !important;
2053
+ }
2054
+ body[${ACTIVE_ATTR}]:not([${DARK_ATTR}]) {
2055
+ --dsw-specific-input-major: #f8f9fa;
2056
+ --dsw-specific-bubble: #f4f5f6;
2057
+ --dsw-menu-surface-fill: #f8f9fa;
2058
+ --dsw-mask-blur: none !important;
2059
+ }
2060
+ body[${ACTIVE_ATTR}] [data-composer-card],
2061
+ body[${ACTIVE_ATTR}] [class*="_bubble"],
2062
+ body[${ACTIVE_ATTR}] [data-menu-material],
2063
+ body[${ACTIVE_ATTR}] [data-composer-dock] [class*="_panel"],
2064
+ body[${ACTIVE_ATTR}] [class*="_dialog_"] {
2065
+ -webkit-backdrop-filter: none;
2066
+ backdrop-filter: none;
2067
+ background-image: none;
2068
+ box-shadow: var(--dsw-elevation-soft, 0 3px 8px rgba(0, 0, 0, 0.08));
2069
+ }
2070
+ body[${ACTIVE_ATTR}] [class*="_dialog_"] {
2071
+ background-color: var(--dsw-alias-bg-layer-2);
2072
+ }
1963
2073
  }
1964
2074
 
1965
2075
  /* ── Picker chrome (token-driven, theme-aware) ── */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wallpaper-engine-dsh",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Wallpaper Engine library as the DSH web GUI background — video/web/still wallpapers, rotation lists, search, resource monitor, bilingual UI.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",