wallpaper-engine-dsh 0.1.2 → 0.1.4
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 +1 -0
- package/README.zh.md +1 -0
- package/lib/client.js +103 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ A DSH bundle that turns your local **Wallpaper Engine** library into the live ba
|
|
|
10
10
|
- **Search** — filter the grid instantly by title or workshop id.
|
|
11
11
|
- **Rotation lists** — any number of carousel lists, each with its own wallpapers, interval (1–120 min) and order (sequence/random). Your first playable Wallpaper Engine playlist is imported automatically; others can be imported into any list.
|
|
12
12
|
- **Four live sliders** — wallpaper blur, scrim, border contrast, and glass frosting, all instant and persisted.
|
|
13
|
+
- **Canvas fit** — cover/contain/stretch/original sizing plus five-way alignment for video and still wallpapers.
|
|
13
14
|
- **Resource monitor** — FPS readout with a low-framerate hint, plus auto-pause when the tab is hidden or the battery runs low (both optional).
|
|
14
15
|
- **Bilingual** — the settings UI follows the shell's Language preference (Chinese/English), with a manual override in the picker.
|
|
15
16
|
- **Crossfade** — wallpaper switches and clearing fade smoothly instead of snapping.
|
package/README.zh.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- **搜索** —— 按标题或创意工坊 ID 即时筛选网格。
|
|
11
11
|
- **轮播列表** —— 可建任意多个列表,各自拥有壁纸集合、切换间隔(1–120 分钟)和顺序(顺序/随机)。首次运行自动导入第一个可播放的 Wallpaper Engine 播放列表,其余列表可随时导入。
|
|
12
12
|
- **四个实时滑杆** —— 壁纸模糊、暗化、边框对比、玻璃磨砂,即时生效并持久保存。
|
|
13
|
+
- **画布排布** —— 视频与静态壁纸支持填充/适应/拉伸/原始四种排布和五向对齐。
|
|
13
14
|
- **资源监控** —— 帧率读数与低帧率提示,页面隐藏或电量不足时自动暂停(均可开关)。
|
|
14
15
|
- **中英双语** —— 设置界面跟随 DSH 的"语言"偏好自动切换,也可在面板内手动指定。
|
|
15
16
|
- **交叉淡入** —— 切换与关闭都平滑过渡,不生硬跳变。
|
package/lib/client.js
CHANGED
|
@@ -83,6 +83,17 @@ window.__ModuleLoader__.load({
|
|
|
83
83
|
lowFpsHint: "帧率偏低,可尝试暂停视频、增大壁纸模糊或换用静态壁纸",
|
|
84
84
|
language: "语言",
|
|
85
85
|
langAuto: "自动",
|
|
86
|
+
fit: "排布",
|
|
87
|
+
fitCover: "填充",
|
|
88
|
+
fitContain: "适应",
|
|
89
|
+
fitFill: "拉伸",
|
|
90
|
+
fitNone: "原始",
|
|
91
|
+
position: "对齐",
|
|
92
|
+
posCenter: "居中",
|
|
93
|
+
posTop: "顶部",
|
|
94
|
+
posBottom: "底部",
|
|
95
|
+
posLeft: "居左",
|
|
96
|
+
posRight: "居右",
|
|
86
97
|
statusGroup: (name, total, usable, interval, order) =>
|
|
87
98
|
"列表「" + name + "」:" + total + " 项 · " + usable + " 可用 · 每 " + interval + " 分钟 · " + order,
|
|
88
99
|
statusUsable: (n) => n + " 张可用壁纸",
|
|
@@ -148,6 +159,17 @@ window.__ModuleLoader__.load({
|
|
|
148
159
|
lowFpsHint: "Low frame rate — try pausing the video, raising wallpaper blur, or using a still wallpaper",
|
|
149
160
|
language: "Language",
|
|
150
161
|
langAuto: "Auto",
|
|
162
|
+
fit: "Fit",
|
|
163
|
+
fitCover: "Cover",
|
|
164
|
+
fitContain: "Contain",
|
|
165
|
+
fitFill: "Stretch",
|
|
166
|
+
fitNone: "Original",
|
|
167
|
+
position: "Align",
|
|
168
|
+
posCenter: "Center",
|
|
169
|
+
posTop: "Top",
|
|
170
|
+
posBottom: "Bottom",
|
|
171
|
+
posLeft: "Left",
|
|
172
|
+
posRight: "Right",
|
|
151
173
|
statusGroup: (name, total, usable, interval, order) =>
|
|
152
174
|
"List \"" + name + "\": " + total + " items · " + usable + " usable · every " + interval + " min · " + order,
|
|
153
175
|
statusUsable: (n) => n + " usable wallpapers",
|
|
@@ -193,8 +215,13 @@ window.__ModuleLoader__.load({
|
|
|
193
215
|
pauseOnHidden: true,
|
|
194
216
|
pauseOnBattery: true,
|
|
195
217
|
lang: "auto",
|
|
218
|
+
fit: "cover",
|
|
219
|
+
position: "center",
|
|
196
220
|
};
|
|
197
221
|
|
|
222
|
+
const FIT_MODES = ["cover", "contain", "fill", "none"];
|
|
223
|
+
const POSITIONS = ["center", "top", "bottom", "left", "right"];
|
|
224
|
+
|
|
198
225
|
// ── Persisted selection ─────────────────────────────────────────────────────
|
|
199
226
|
function clampNum(v, lo, hi, fallback) {
|
|
200
227
|
return typeof v === "number" && isFinite(v) && v >= lo && v <= hi ? v : fallback;
|
|
@@ -238,6 +265,8 @@ window.__ModuleLoader__.load({
|
|
|
238
265
|
pauseOnHidden: o.pauseOnHidden !== false,
|
|
239
266
|
pauseOnBattery: o.pauseOnBattery !== false,
|
|
240
267
|
lang: o.lang === "zh" || o.lang === "en" ? o.lang : "auto",
|
|
268
|
+
fit: FIT_MODES.indexOf(o.fit) >= 0 ? o.fit : DEFAULTS.fit,
|
|
269
|
+
position: POSITIONS.indexOf(o.position) >= 0 ? o.position : DEFAULTS.position,
|
|
241
270
|
};
|
|
242
271
|
} catch {
|
|
243
272
|
return { id: "", ...DEFAULTS };
|
|
@@ -287,6 +316,8 @@ window.__ModuleLoader__.load({
|
|
|
287
316
|
pauseOnHidden: selection.pauseOnHidden,
|
|
288
317
|
pauseOnBattery: selection.pauseOnBattery,
|
|
289
318
|
lang: selection.lang,
|
|
319
|
+
fit: selection.fit,
|
|
320
|
+
position: selection.position,
|
|
290
321
|
}));
|
|
291
322
|
} catch { /* storage full / blocked → session-only state, not fatal */ }
|
|
292
323
|
}
|
|
@@ -693,6 +724,10 @@ window.__ModuleLoader__.load({
|
|
|
693
724
|
s.setProperty("--webg-wallpaper-blur", selection.wallpaperBlur + "px");
|
|
694
725
|
// Scaling compensates the transparent fringe CSS blur reveals at edges.
|
|
695
726
|
s.setProperty("--webg-wallpaper-scale", (1 + selection.wallpaperBlur * 0.006).toFixed(4));
|
|
727
|
+
// Canvas fit: object-fit/position for video and still wallpapers (iframes
|
|
728
|
+
// ignore object-fit — web wallpapers always fill their layer).
|
|
729
|
+
s.setProperty("--webg-fit", selection.fit);
|
|
730
|
+
s.setProperty("--webg-position", selection.position);
|
|
696
731
|
|
|
697
732
|
// Write the scrim colour directly too, then force a synchronous layout, so
|
|
698
733
|
// slider feedback lands on this frame even on stalled compositors.
|
|
@@ -712,6 +747,8 @@ window.__ModuleLoader__.load({
|
|
|
712
747
|
s.removeProperty("--webg-glass-brightness");
|
|
713
748
|
s.removeProperty("--webg-wallpaper-blur");
|
|
714
749
|
s.removeProperty("--webg-wallpaper-scale");
|
|
750
|
+
s.removeProperty("--webg-fit");
|
|
751
|
+
s.removeProperty("--webg-position");
|
|
715
752
|
const scrim = document.getElementById(SCRIM_ID);
|
|
716
753
|
if (scrim) scrim.style.background = "";
|
|
717
754
|
}
|
|
@@ -838,6 +875,18 @@ window.__ModuleLoader__.load({
|
|
|
838
875
|
const onBorder = (pct) => { selection.border = pct / 100; persistSelection(); applyEffects(); emit(); };
|
|
839
876
|
const onBlur = (px) => { selection.blur = px; persistSelection(); applyEffects(); emit(); };
|
|
840
877
|
const onWallpaperBlur = (px) => { selection.wallpaperBlur = px; persistSelection(); applyEffects(); emit(); };
|
|
878
|
+
const onFit = (e) => {
|
|
879
|
+
selection.fit = FIT_MODES.indexOf(e.target.value) >= 0 ? e.target.value : "cover";
|
|
880
|
+
persistSelection();
|
|
881
|
+
applyEffects();
|
|
882
|
+
emit();
|
|
883
|
+
};
|
|
884
|
+
const onPosition = (e) => {
|
|
885
|
+
selection.position = POSITIONS.indexOf(e.target.value) >= 0 ? e.target.value : "center";
|
|
886
|
+
persistSelection();
|
|
887
|
+
applyEffects();
|
|
888
|
+
emit();
|
|
889
|
+
};
|
|
841
890
|
|
|
842
891
|
if (!sel.loaded) {
|
|
843
892
|
return React.createElement("div", { className: "webg-picker" },
|
|
@@ -1073,6 +1122,28 @@ window.__ModuleLoader__.load({
|
|
|
1073
1122
|
),
|
|
1074
1123
|
// ── Effects ──
|
|
1075
1124
|
sel.id && React.createElement(React.Fragment, null,
|
|
1125
|
+
// Canvas fit only matters for video/still wallpapers — an iframe
|
|
1126
|
+
// ignores object-fit and always fills its layer.
|
|
1127
|
+
sel.type !== "web" && React.createElement("div", { className: "webg-row webg-fit-row" },
|
|
1128
|
+
React.createElement("span", { className: "webg-hint webg-label" }, t.fit),
|
|
1129
|
+
React.createElement("select", {
|
|
1130
|
+
className: "webg-select webg-fit-select",
|
|
1131
|
+
value: sel.fit,
|
|
1132
|
+
onChange: onFit,
|
|
1133
|
+
},
|
|
1134
|
+
...[t.fitCover, t.fitContain, t.fitFill, t.fitNone].map((label, i) =>
|
|
1135
|
+
React.createElement("option", { key: FIT_MODES[i], value: FIT_MODES[i] }, label),
|
|
1136
|
+
)),
|
|
1137
|
+
React.createElement("span", { className: "webg-hint webg-label" }, t.position),
|
|
1138
|
+
React.createElement("select", {
|
|
1139
|
+
className: "webg-select webg-position-select",
|
|
1140
|
+
value: sel.position,
|
|
1141
|
+
onChange: onPosition,
|
|
1142
|
+
},
|
|
1143
|
+
...[t.posCenter, t.posTop, t.posBottom, t.posLeft, t.posRight].map((label, i) =>
|
|
1144
|
+
React.createElement("option", { key: POSITIONS[i], value: POSITIONS[i] }, label),
|
|
1145
|
+
)),
|
|
1146
|
+
),
|
|
1076
1147
|
SliderRow(t.wallpaperBlur, 0, 60, 1, sel.wallpaperBlur, onWallpaperBlur, sel.wallpaperBlur + "px"),
|
|
1077
1148
|
SliderRow(t.scrim, 0, 90, 5, Math.round(sel.scrim * 100), onScrim, Math.round(sel.scrim * 100) + "%"),
|
|
1078
1149
|
SliderRow(t.border, 0, 90, 5, Math.round(sel.border * 100), onBorder, Math.round(sel.border * 100) + "%"),
|
|
@@ -1128,7 +1199,9 @@ window.__ModuleLoader__.load({
|
|
|
1128
1199
|
.webg-layer--enter { opacity: 0; }
|
|
1129
1200
|
.webg-layer--leave { opacity: 0; }
|
|
1130
1201
|
.webg-layer .webg-media {
|
|
1131
|
-
width: 100%; height: 100%; object-fit: cover;
|
|
1202
|
+
width: 100%; height: 100%; object-fit: var(--webg-fit, cover);
|
|
1203
|
+
object-position: var(--webg-position, center);
|
|
1204
|
+
display: block;
|
|
1132
1205
|
background: transparent; border: 0;
|
|
1133
1206
|
filter: blur(var(--webg-wallpaper-blur, 0px));
|
|
1134
1207
|
transform: scale(var(--webg-wallpaper-scale, 1));
|
|
@@ -1189,11 +1262,14 @@ window.__ModuleLoader__.load({
|
|
|
1189
1262
|
}
|
|
1190
1263
|
|
|
1191
1264
|
/* ── Picker chrome (token-driven, theme-aware) ── */
|
|
1192
|
-
|
|
1265
|
+
/* padding-top lifts the first row off the settings-section divider so the
|
|
1266
|
+
search/language row breathes; gap keeps every row evenly spaced.
|
|
1267
|
+
Type scale follows the shell: 14px body → 13px controls → 12px hints. */
|
|
1268
|
+
.webg-picker { display: flex; flex-direction: column; gap: 12px; padding-top: 10px; }
|
|
1193
1269
|
.webg-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
|
1194
|
-
.webg-hint { font-size:
|
|
1270
|
+
.webg-hint { font-size: 12px; opacity: 0.7; color: var(--dsw-alias-label-tertiary, inherit); }
|
|
1195
1271
|
.webg-error {
|
|
1196
|
-
font-size:
|
|
1272
|
+
font-size: 13px;
|
|
1197
1273
|
color: var(--dsw-alias-state-error-primary, #d44);
|
|
1198
1274
|
}
|
|
1199
1275
|
.webg-label { min-width: 28px; }
|
|
@@ -1206,21 +1282,26 @@ window.__ModuleLoader__.load({
|
|
|
1206
1282
|
border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));
|
|
1207
1283
|
background: var(--dsw-alias-bg-layer-1, rgba(128, 128, 128, 0.12));
|
|
1208
1284
|
color: var(--dsw-alias-label-primary, inherit);
|
|
1209
|
-
font-size:
|
|
1285
|
+
font-size: 12px;
|
|
1210
1286
|
transition: background-color 120ms ease, border-color 120ms ease;
|
|
1211
1287
|
}
|
|
1288
|
+
/* Ghost-button hover rides the shell's own interactive-hover token. */
|
|
1212
1289
|
.webg-btn:hover:not(:disabled) {
|
|
1213
|
-
background: var(--dsw-alias-bg-
|
|
1290
|
+
background: var(--dsw-alias-interactive-bg-hover,
|
|
1291
|
+
var(--dsw-alias-bg-layer-2, rgba(128, 128, 128, 0.2)));
|
|
1214
1292
|
border-color: var(--dsw-alias-border-l1, rgba(128, 128, 128, 0.5));
|
|
1215
1293
|
}
|
|
1216
1294
|
.webg-btn:disabled { opacity: 0.45; cursor: not-allowed; }
|
|
1295
|
+
/* brand-primary is monochrome (near-black light / near-white dark), so
|
|
1296
|
+
the label must use its inverse token — never a hardcoded white. */
|
|
1217
1297
|
.webg-btn--primary {
|
|
1218
|
-
background: var(--dsw-alias-brand-primary,
|
|
1298
|
+
background: var(--dsw-alias-brand-primary, rgb(15, 17, 21));
|
|
1219
1299
|
border-color: transparent;
|
|
1220
|
-
color:
|
|
1300
|
+
color: var(--dsw-alias-brand-primary-invert, rgb(249, 250, 251));
|
|
1221
1301
|
}
|
|
1222
1302
|
.webg-btn--primary:hover:not(:disabled) {
|
|
1223
|
-
background: var(--dsw-alias-brand-primary
|
|
1303
|
+
background: var(--dsw-alias-brand-primary, rgb(15, 17, 21));
|
|
1304
|
+
opacity: 0.85;
|
|
1224
1305
|
}
|
|
1225
1306
|
|
|
1226
1307
|
.webg-select, .webg-text {
|
|
@@ -1229,7 +1310,7 @@ window.__ModuleLoader__.load({
|
|
|
1229
1310
|
border: 1px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.35));
|
|
1230
1311
|
background: var(--dsw-alias-bg-layer-1, rgba(128, 128, 128, 0.12));
|
|
1231
1312
|
color: var(--dsw-alias-label-primary, inherit);
|
|
1232
|
-
font-size:
|
|
1313
|
+
font-size: 13px;
|
|
1233
1314
|
}
|
|
1234
1315
|
.webg-text { flex: 1; min-width: 0; }
|
|
1235
1316
|
.webg-search { max-width: 320px; }
|
|
@@ -1238,11 +1319,11 @@ window.__ModuleLoader__.load({
|
|
|
1238
1319
|
.webg-rotation-interval { margin-left: auto; }
|
|
1239
1320
|
.webg-toggle {
|
|
1240
1321
|
display: inline-flex; align-items: center; gap: 6px;
|
|
1241
|
-
accent-color: var(--dsw-alias-brand-primary,
|
|
1242
|
-
font-size:
|
|
1322
|
+
accent-color: var(--dsw-alias-brand-primary, rgb(15, 17, 21));
|
|
1323
|
+
font-size: 13px; cursor: pointer;
|
|
1243
1324
|
}
|
|
1244
1325
|
|
|
1245
|
-
.webg-slider { flex: 1; accent-color: var(--dsw-alias-brand-primary,
|
|
1326
|
+
.webg-slider { flex: 1; accent-color: var(--dsw-alias-brand-primary, rgb(15, 17, 21)); }
|
|
1246
1327
|
.webg-slider-row { display: flex; align-items: center; gap: 8px; }
|
|
1247
1328
|
|
|
1248
1329
|
.webg-monitor-row { gap: 14px; }
|
|
@@ -1268,23 +1349,23 @@ window.__ModuleLoader__.load({
|
|
|
1268
1349
|
}
|
|
1269
1350
|
.webg-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
1270
1351
|
.webg-card--selected {
|
|
1271
|
-
outline: 2px solid var(--dsw-alias-brand-primary,
|
|
1352
|
+
outline: 2px solid var(--dsw-alias-brand-primary, rgb(15, 17, 21));
|
|
1272
1353
|
outline-offset: -2px;
|
|
1273
1354
|
}
|
|
1274
1355
|
.webg-card-close {
|
|
1275
1356
|
position: absolute; inset: 0;
|
|
1276
1357
|
display: flex; align-items: center; justify-content: center;
|
|
1277
|
-
font-size:
|
|
1358
|
+
font-size: 12px; color: var(--dsw-alias-label-secondary, #888);
|
|
1278
1359
|
}
|
|
1279
1360
|
.webg-card-type {
|
|
1280
1361
|
position: absolute; top: 4px; right: 4px;
|
|
1281
1362
|
padding: 1px 6px; border-radius: 4px;
|
|
1282
|
-
font-size:
|
|
1363
|
+
font-size: 10px; line-height: 1.5;
|
|
1283
1364
|
color: #fff; background: rgba(0, 0, 0, 0.5);
|
|
1284
1365
|
}
|
|
1285
1366
|
.webg-card-title {
|
|
1286
1367
|
position: absolute; left: 0; right: 0; bottom: 0; padding: 3px 6px;
|
|
1287
|
-
font-size:
|
|
1368
|
+
font-size: 11px; line-height: 1.2; color: #fff;
|
|
1288
1369
|
background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
|
|
1289
1370
|
text-overflow: ellipsis; white-space: nowrap; overflow: hidden;
|
|
1290
1371
|
text-align: left;
|
|
@@ -1292,7 +1373,7 @@ window.__ModuleLoader__.load({
|
|
|
1292
1373
|
.webg-card-placeholder {
|
|
1293
1374
|
position: absolute; inset: 0;
|
|
1294
1375
|
display: flex; align-items: center; justify-content: center;
|
|
1295
|
-
font-size:
|
|
1376
|
+
font-size: 11px; opacity: 0.55;
|
|
1296
1377
|
}
|
|
1297
1378
|
|
|
1298
1379
|
/* Rotation group editor. */
|
|
@@ -1318,12 +1399,14 @@ window.__ModuleLoader__.load({
|
|
|
1318
1399
|
.webg-editor-card:hover { transform: translateY(-1px); }
|
|
1319
1400
|
.webg-editor-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
|
1320
1401
|
.webg-editor-card--checked {
|
|
1321
|
-
outline: 2px solid var(--dsw-alias-brand-primary,
|
|
1402
|
+
outline: 2px solid var(--dsw-alias-brand-primary, rgb(15, 17, 21));
|
|
1322
1403
|
outline-offset: -2px;
|
|
1323
1404
|
}
|
|
1324
1405
|
.webg-editor-check {
|
|
1325
1406
|
position: absolute; top: 4px; left: 4px; width: 18px; height: 18px;
|
|
1326
|
-
border-radius: 4px;
|
|
1407
|
+
border-radius: 4px;
|
|
1408
|
+
background: var(--dsw-alias-brand-primary, rgb(15, 17, 21));
|
|
1409
|
+
color: var(--dsw-alias-brand-primary-invert, rgb(249, 250, 251));
|
|
1327
1410
|
font-size: 12px; line-height: 18px; text-align: center;
|
|
1328
1411
|
}
|
|
1329
1412
|
`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wallpaper-engine-dsh",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Wallpaper Engine Video/Web wallpapers as the DSH web GUI background — discovery, sandboxed rendering, rotation lists, liquid-glass tuning.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|