dsh-dream-skin 0.4.13 → 0.4.14

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.
@@ -383,3 +383,15 @@ Ein Sicherheitsproblem gefunden? Öffne kein öffentliches Issue — siehe die [
383
383
 
384
384
  - Architektur- & API-Referenz: das offizielle Client-Paket [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme) von DeepSeek Harness.
385
385
  - Konzept-Hommage: [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).
386
+
387
+ ---
388
+
389
+ ## 📈 Wachstumskurve
390
+
391
+ > Täglich automatisch aktualisiert (GitHub Actions). Linke Achse: **kumulierte Downloads** (türkis); rechte Achse: **Sternezahl** (violett) — sehr unterschiedliche Größenordnungen, daher zwei unabhängige Y-Achsen.
392
+
393
+ <p align="center">
394
+ <img src="../../docs/stats.png" alt="Tägliche Wachstumskurve Star × kumulierte Downloads von dsh-dream-skin" width="900"/>
395
+ </p>
396
+
397
+ *Die Daten werden alle 24 Stunden gesammelt: Downloads über die [offizielle npm-API](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin), Sterne über die [GitHub-API](https://github.com/RevolutionLA/dsh-dream-skin/stargazers).*
@@ -383,3 +383,16 @@ Found a security issue? Don't open a public issue — see the [Security Policy](
383
383
  - Architecture & API reference: the official DeepSeek Harness
384
384
  [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme) client package.
385
385
  - Concept homage: [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).
386
+
387
+ ---
388
+
389
+ ## 📈 Growth chart
390
+
391
+ > Updated automatically every day (GitHub Actions). Left axis: **cumulative downloads** (teal); right axis:
392
+ > **Star count** (purple) — two very different magnitudes, so each has its own independent Y-axis.
393
+
394
+ <p align="center">
395
+ <img src="../../docs/stats.png" alt="dsh-dream-skin daily Stars × cumulative downloads growth chart" width="900"/>
396
+ </p>
397
+
398
+ *Data is collected every 24 hours: downloads from the [npm API](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin), Stars from the [GitHub API](https://github.com/RevolutionLA/dsh-dream-skin/stargazers).*
@@ -390,3 +390,15 @@ que el proyecto se descubra y se mantenga. ¿Quieres contribuir con themes / un
390
390
  - Referencia de arquitectura y API: el paquete de cliente
391
391
  [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme) oficial de DeepSeek Harness.
392
392
  - Homenaje conceptual: [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).
393
+
394
+ ---
395
+
396
+ ## 📈 Curva de crecimiento
397
+
398
+ > Actualizada automáticamente cada día (GitHub Actions). Eje izquierdo: **descargas acumuladas** (verde); eje derecho: **número de Stars** (púrpura) — magnitudes muy distintas, por eso cada uno tiene su propio eje Y independiente.
399
+
400
+ <p align="center">
401
+ <img src="../../docs/stats.png" alt="Curva de crecimiento diario Star × descargas acumuladas de dsh-dream-skin" width="900"/>
402
+ </p>
403
+
404
+ *Los datos se recogen cada 24 horas: las descargas desde la [API oficial de npm](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin), y las Stars desde la [API de GitHub](https://github.com/RevolutionLA/dsh-dream-skin/stargazers).*
@@ -382,3 +382,15 @@ Vous avez trouvé un problème de sécurité ? N'ouvrez pas d'issue publique —
382
382
  - Référence d'architecture & d'API : le package client
383
383
  [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme) officiel de DeepSeek Harness.
384
384
  - Hommage conceptuel : [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).
385
+
386
+ ---
387
+
388
+ ## 📈 Courbe de croissance
389
+
390
+ > Mise à jour automatique chaque jour (GitHub Actions). Axe gauche : **téléchargements cumulés** (turquoise) ; axe droit : **nombre d'étoiles** (violet) — des ordres de grandeur très différents, d'où deux axes Y indépendants.
391
+
392
+ <p align="center">
393
+ <img src="../../docs/stats.png" alt="Courbe de croissance quotidienne Star × téléchargements cumulés de dsh-dream-skin" width="900"/>
394
+ </p>
395
+
396
+ *Les données sont collectées toutes les 24 h : téléchargements via l'[API officielle npm](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin), étoiles via l'[API GitHub](https://github.com/RevolutionLA/dsh-dream-skin/stargazers).*
@@ -347,3 +347,15 @@ Issue と PR は大歓迎です![コントリビューションガイド](../.
347
347
 
348
348
  - アーキテクチャ & API リファレンス:公式 DeepSeek Harness の [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme) クライアントパッケージ。
349
349
  - コンセプトのオマージュ:[Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin)。
350
+
351
+ ---
352
+
353
+ ## 📈 成長カーブ
354
+
355
+ > 毎日自動更新(GitHub Actions)。左軸:**累計ダウンロード数**(青);右軸:**Star 数**(紫)——桁が大きく異なるため、それぞれ独立した双軸を使用しています。
356
+
357
+ <p align="center">
358
+ <img src="../../docs/stats.png" alt="dsh-dream-skin 毎日の Star × 累計ダウンロード数 成長カーブ" width="900"/>
359
+ </p>
360
+
361
+ *データは 24 時間ごとに自動取得:ダウンロード数は [npm 公式API](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin)、Star 数は [GitHub API](https://github.com/RevolutionLA/dsh-dream-skin/stargazers) から取得しています。*
@@ -383,3 +383,15 @@ Issues와 PR을 환영합니다! [기여 가이드](../../CONTRIBUTING.md)를
383
383
  - 아키텍처 & API 참고: 공식 DeepSeek Harness
384
384
  [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme) 클라이언트 패키지.
385
385
  - 컨셉 오마주: [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).
386
+
387
+ ---
388
+
389
+ ## 📈 성장 곡선
390
+
391
+ > 매일 자동 업데이트(GitHub Actions). 왼쪽 축: **누적 다운로드 수**(청록); 오른쪽 축: **Star 수**(보라) — 규모가 크게 달라 각각 독립된 이중 축을 사용합니다.
392
+
393
+ <p align="center">
394
+ <img src="../../docs/stats.png" alt="dsh-dream-skin 매일 Star × 누적 다운로드 수 성장 곡선" width="900"/>
395
+ </p>
396
+
397
+ *데이터는 24시간마다 자동 수집됩니다: 다운로드 수는 [npm 공식 API](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin), Star 수는 [GitHub API](https://github.com/RevolutionLA/dsh-dream-skin/stargazers)에서 가져옵니다.*
@@ -383,3 +383,15 @@ dsh web # восстанавливает официальный вид
383
383
  - Справочник по архитектуре и API: официальный клиентский пакет DeepSeek Harness
384
384
  [ui-theme](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/client/ui-theme).
385
385
  - Концептуальная дань: [Codex-Dream-Skin](https://github.com/Fei-Away/Codex-Dream-Skin).
386
+
387
+ ---
388
+
389
+ ## 📈 Кривая роста
390
+
391
+ > Автоматически обновляется ежедневно (GitHub Actions). Левая ось: **суммарные скачивания** (бирюзовый); правая ось: **число звёзд** (фиолетовый) — сильно разные порядки величин, поэтому у каждого своя независимая ось Y.
392
+
393
+ <p align="center">
394
+ <img src="../../docs/stats.png" alt="Ежедневная кривая роста Star × суммарные скачивания dsh-dream-skin" width="900"/>
395
+ </p>
396
+
397
+ *Данные собираются каждые 24 часа: скачивания — из [официального API npm](https://api.npmjs.org/downloads/range/2026-08-15:2026-12-31/dsh-dream-skin), звёзды — из [API GitHub](https://github.com/RevolutionLA/dsh-dream-skin/stargazers).*
package/lib/client.js CHANGED
@@ -1022,8 +1022,59 @@ window.__ModuleLoader__.load({
1022
1022
  //#region dsh-dream-skin: wallpaper layer + token shading
1023
1023
  /** The fixed backdrop layer (z-index -1), created lazily. */
1024
1024
  let wallpaperEl = null;
1025
- /** Disposer for the current token-override layer. */
1026
- let wallpaperOverrideDispose = null;
1025
+ /**
1026
+ * Dynamic packages are assigned one token-override source by the production
1027
+ * client runner, regardless of the source label passed by the package. Keep
1028
+ * every Dream Skin contribution in one layer so wallpaper, popup opacity and
1029
+ * accent do not replace one another there.
1030
+ */
1031
+ const COMBINED_OVERRIDE_SOURCE = "dsh-dream-skin:appearance";
1032
+ let combinedOverrideDispose = null;
1033
+ let combinedOverrideApplying = false;
1034
+ let wallpaperTokenOverrides = {};
1035
+ let popupTokenOverrides = {};
1036
+ let accentTokenOverrides = {};
1037
+
1038
+ function rawActiveTheme(snapshot) {
1039
+ // `preference` is the authoritative selected theme id. In the production
1040
+ // dynamic-package event facade, `snapshot.active` can already be the
1041
+ // composed presentation object (and has been observed without a usable
1042
+ // third-party id). Looking it up by `active.id` then falls through to the
1043
+ // composed tokens and feeds our previous wallpaper wash back into the next
1044
+ // skin. Prefer the registered definition selected by `preference`; only use
1045
+ // active.id for `system`, where it resolves to the concrete light/dark theme.
1046
+ const savedId = readSavedSkin();
1047
+ const selectedId = typeof savedId === "string" && savedId !== DEFAULT_SKIN
1048
+ ? savedId
1049
+ : snapshot.preference === "system"
1050
+ ? snapshot.active?.id
1051
+ : snapshot.preference;
1052
+ return snapshot.themes?.find((theme) => theme.id === selectedId)
1053
+ || snapshot.themes?.find((theme) => theme.id === snapshot.active?.id)
1054
+ || snapshot.active;
1055
+ }
1056
+
1057
+ function applyCombinedTokenOverrides(ctx) {
1058
+ if (combinedOverrideApplying) return;
1059
+ combinedOverrideApplying = true;
1060
+ try {
1061
+ const overrides = {
1062
+ ...popupTokenOverrides,
1063
+ ...accentTokenOverrides,
1064
+ ...wallpaperTokenOverrides
1065
+ };
1066
+ if (Object.keys(overrides).length > 0) {
1067
+ const previousDispose = combinedOverrideDispose;
1068
+ combinedOverrideDispose = ctx.theme.overrideTokens(COMBINED_OVERRIDE_SOURCE, overrides);
1069
+ previousDispose?.();
1070
+ } else {
1071
+ combinedOverrideDispose?.();
1072
+ combinedOverrideDispose = null;
1073
+ }
1074
+ } finally {
1075
+ combinedOverrideApplying = false;
1076
+ }
1077
+ }
1027
1078
  /** The injected liquid-glass <style> node (leaf-card backdrop blur). */
1028
1079
  let materialStyleEl = null;
1029
1080
 
@@ -1059,12 +1110,12 @@ window.__ModuleLoader__.load({
1059
1110
  return resolveBase(scheme, active);
1060
1111
  }
1061
1112
 
1062
- /** Remove the wallpaper layer and its token overrides (fiber unload). */
1063
- function teardownWallpaper() {
1113
+ /** Remove the wallpaper layer and its token contribution. */
1114
+ function teardownWallpaper(ctx = null) {
1064
1115
  wallpaperEl?.remove();
1065
1116
  wallpaperEl = null;
1066
- wallpaperOverrideDispose?.();
1067
- wallpaperOverrideDispose = null;
1117
+ wallpaperTokenOverrides = {};
1118
+ if (ctx !== null) applyCombinedTokenOverrides(ctx);
1068
1119
  }
1069
1120
 
1070
1121
  //#region dsh-dream-skin: liquid-glass material CSS
@@ -1220,12 +1271,11 @@ window.__ModuleLoader__.load({
1220
1271
  * Pure token override (no backdrop-filter), so it cannot re-trigger the
1221
1272
  * fixed-modal containing-block bug. Called at boot and on every slider move.
1222
1273
  */
1223
- const POPUP_OVERRIDE_SOURCE = "dsh-dream-skin:popup-opacity";
1224
1274
  const POPUP_TOKENS = ["--dsw-alias-bg-overlay", "--dsw-specific-menu"];
1225
- let popupOverrideDispose = null;
1226
1275
  function applyModalOverlay(ctx) {
1227
1276
  const alpha = readModalOpacity();
1228
- const active = ctx.theme.getTheme().active;
1277
+ const current = ctx.theme.getTheme();
1278
+ const active = rawActiveTheme(current);
1229
1279
  const baseFor = (scheme) => {
1230
1280
  if (active && active.colorScheme === scheme && typeof active.tokens["--dsw-alias-bg-base"] === "string") {
1231
1281
  return active.tokens["--dsw-alias-bg-base"];
@@ -1239,8 +1289,8 @@ window.__ModuleLoader__.load({
1239
1289
  dark: toRgba(baseFor("dark"), alpha)
1240
1290
  };
1241
1291
  }
1242
- popupOverrideDispose?.();
1243
- popupOverrideDispose = ctx.theme.overrideTokens(POPUP_OVERRIDE_SOURCE, overrides);
1292
+ popupTokenOverrides = overrides;
1293
+ applyCombinedTokenOverrides(ctx);
1244
1294
  }
1245
1295
  //#endregion
1246
1296
 
@@ -2498,8 +2548,6 @@ window.__ModuleLoader__.load({
2498
2548
  //#endregion
2499
2549
 
2500
2550
  //#region dsh-dream-skin: P0 accent override
2501
- /** Source identity for the per-user accent override layer. */
2502
- const ACCENT_OVERRIDE_SOURCE = "dsh-dream-skin:accent";
2503
2551
  /** Token names the accent override shades (brand + primary surfaces). */
2504
2552
  const ACCENT_TOKENS = [
2505
2553
  "--dsw-alias-brand-primary",
@@ -2507,8 +2555,6 @@ window.__ModuleLoader__.load({
2507
2555
  "--dsw-alias-button-primary-fill",
2508
2556
  "--dsw-alias-button-primary-dimmed"
2509
2557
  ];
2510
- /** Disposer for the active accent override layer. */
2511
- let accentOverrideDispose = null;
2512
2558
  /** Cached accent currently applied (hex or null). */
2513
2559
  let appliedAccent = null;
2514
2560
 
@@ -2528,16 +2574,16 @@ window.__ModuleLoader__.load({
2528
2574
  function applyAccent(ctx) {
2529
2575
  const accent = readAccent();
2530
2576
  if (accent === null) {
2531
- accentOverrideDispose?.();
2532
- accentOverrideDispose = null;
2577
+ accentTokenOverrides = {};
2578
+ applyCombinedTokenOverrides(ctx);
2533
2579
  appliedAccent = null;
2534
2580
  return null;
2535
2581
  }
2536
2582
  const pair = { light: accent, dark: accent };
2537
2583
  const overrides = {};
2538
2584
  for (const name of ACCENT_TOKENS) overrides[name] = pair;
2539
- accentOverrideDispose?.();
2540
- accentOverrideDispose = ctx.theme.overrideTokens(ACCENT_OVERRIDE_SOURCE, overrides);
2585
+ accentTokenOverrides = overrides;
2586
+ applyCombinedTokenOverrides(ctx);
2541
2587
  appliedAccent = accent;
2542
2588
  return accent;
2543
2589
  }
@@ -2550,8 +2596,6 @@ window.__ModuleLoader__.load({
2550
2596
  //#endregion
2551
2597
 
2552
2598
  //#region dsh-dream-skin: P0 wallpaper 2.0 (url / gradient / auto-dim)
2553
- /** Unique source identity for the wallpaper (already composited) layer. */
2554
- const WALLPAPER_OVERRIDE_SOURCE = "dsh-dream-skin:wallpaper";
2555
2599
  /** Read wallpaper kind (image|url|gradient). */
2556
2600
  function readWallpaperKind() {
2557
2601
  const kind = readStorage(WALLPAPER_KIND_KEY);
@@ -2634,7 +2678,7 @@ window.__ModuleLoader__.load({
2634
2678
  const bg = wallpaperBackgroundCss();
2635
2679
  const urlIsSet = bg !== null;
2636
2680
  if (!urlIsSet) {
2637
- teardownWallpaper();
2681
+ teardownWallpaper(ctx);
2638
2682
  return;
2639
2683
  }
2640
2684
  if (wallpaperEl === null || !document.body.contains(wallpaperEl)) {
@@ -2660,7 +2704,7 @@ window.__ModuleLoader__.load({
2660
2704
  // ThemeRuntime composes token override layers into snapshot.active. Reading
2661
2705
  // the active value here would feed our previous wallpaper wash back into the
2662
2706
  // next wash and hide the newly selected skin's raw base/sidebar colors.
2663
- const active = current.themes?.find((theme) => theme.id === current.active.id) || current.active;
2707
+ const active = rawActiveTheme(current);
2664
2708
  // When "link sidebar to main canvas" is on (default), the sidebar wash
2665
2709
  // uses the same alpha as the main canvas so the two halves don't look
2666
2710
  // split; when off, it uses the separately configured sidebar opacity.
@@ -2675,8 +2719,8 @@ window.__ModuleLoader__.load({
2675
2719
  dark: toRgba(resolveSidebar("dark", active), sidebarAlpha)
2676
2720
  }
2677
2721
  };
2678
- wallpaperOverrideDispose?.();
2679
- wallpaperOverrideDispose = ctx.theme.overrideTokens(WALLPAPER_OVERRIDE_SOURCE, overrides);
2722
+ wallpaperTokenOverrides = overrides;
2723
+ applyCombinedTokenOverrides(ctx);
2680
2724
  }
2681
2725
 
2682
2726
  // Wallpaper store bookkeeping lives at module scope so the module-level
@@ -2753,7 +2797,7 @@ window.__ModuleLoader__.load({
2753
2797
  writeStorage(WALLPAPER_URL_KEY, null);
2754
2798
  writeStorage(WALLPAPER_GRADIENT_KEY, null);
2755
2799
  writeStorage(WALLPAPER_KIND_KEY, null);
2756
- teardownWallpaper();
2800
+ teardownWallpaper(ctx);
2757
2801
  syncWallpaper();
2758
2802
  }
2759
2803
 
@@ -3254,8 +3298,11 @@ window.__ModuleLoader__.load({
3254
3298
  teardownWallpaper();
3255
3299
  teardownMaterial();
3256
3300
  disposeAllPacks();
3257
- popupOverrideDispose?.();
3258
- popupOverrideDispose = null;
3301
+ popupTokenOverrides = {};
3302
+ accentTokenOverrides = {};
3303
+ wallpaperTokenOverrides = {};
3304
+ combinedOverrideDispose?.();
3305
+ combinedOverrideDispose = null;
3259
3306
  }, "dsh-dream-skin: wallpaper + material + packs cleanup");
3260
3307
 
3261
3308
  const skinStore = createSkinStore();
@@ -3265,6 +3312,7 @@ window.__ModuleLoader__.load({
3265
3312
  // updates on every click — even if theme/change timing races or the host
3266
3313
  // revision doesn't bump as expected — so the selected card follows instantly.
3267
3314
  let skinRevision = 0;
3315
+ let wallpaperReshadeTimer = null;
3268
3316
  const syncSkinWith = (id) => {
3269
3317
  skinBound?.sync(id, ++skinRevision);
3270
3318
  // Do NOT re-shade the wallpaper here (issue #29): right after
@@ -3279,12 +3327,24 @@ window.__ModuleLoader__.load({
3279
3327
  };
3280
3328
  const syncSkin = (snapshot) => {
3281
3329
  skinBound?.sync(snapshot.preference, ++skinRevision);
3282
- // snapshot.active is the settled target skin here — safe to re-shade the
3283
- // wallpaper wash with the target skin's raw tokens. Pass the full snapshot
3284
- // so shadeTokens2 can ignore its own composed override layer.
3285
- if (wallpaperBackgroundCss() !== null) applyWallpaper2(ctx, snapshot);
3330
+ // Theme events are synchronous. Re-shading inside this listener publishes a
3331
+ // nested theme/change; a presenter registered after us can then apply the
3332
+ // outer (pre-shade) snapshot last, leaving the wallpaper one skin behind.
3333
+ // Run after the current event stack instead. Events emitted by our own
3334
+ // override happen while _applyingWallpaper is true and must not enqueue a
3335
+ // second pass.
3336
+ if (wallpaperBackgroundCss() !== null && !_applyingWallpaper) {
3337
+ if (wallpaperReshadeTimer !== null) clearTimeout(wallpaperReshadeTimer);
3338
+ wallpaperReshadeTimer = setTimeout(() => {
3339
+ wallpaperReshadeTimer = null;
3340
+ applyWallpaper2(ctx, ctx.theme.getTheme());
3341
+ }, 0);
3342
+ }
3286
3343
  };
3287
3344
  ctx.on("theme/change", syncSkin);
3345
+ ctx.effect(() => () => {
3346
+ if (wallpaperReshadeTimer !== null) clearTimeout(wallpaperReshadeTimer);
3347
+ }, "dsh-dream-skin: deferred wallpaper re-shade");
3288
3348
  // Keep the Accent row's base color (the active theme's brand color) in
3289
3349
  // sync when the skin/scheme changes — otherwise a row with no custom
3290
3350
  // accent keeps showing the PREVIOUS skin's brand color until remount.
@@ -3321,8 +3381,11 @@ window.__ModuleLoader__.load({
3321
3381
  syncSkin(ctx.theme.getTheme());
3322
3382
  return {
3323
3383
  setSkin: (id) => {
3324
- ctx.theme.setTheme(id);
3384
+ // Persist first: theme/change is synchronous. Wallpaper re-shading
3385
+ // must see the new selection (and Default must already have cleared
3386
+ // the old skin) while that event is being handled.
3325
3387
  writeSavedSkin(id);
3388
+ ctx.theme.setTheme(id);
3326
3389
  // Deterministically push the new preference into the slot store AND
3327
3390
  // re-shade the wallpaper so the selected card follows immediately,
3328
3391
  // independent of theme/change emission timing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-dream-skin",
3
- "version": "0.4.13",
3
+ "version": "0.4.14",
4
4
  "description": "DeepSeek Harness 换肤插件(Dream Skin for DSH):8 套 iOS / Linear 式清透冷调的高质感主题 + 弥散光壁纸 + 每皮肤智能背景 + 强调色 + 主题包分享,把换肤做成材质与配色克制的高级感工艺,而非贴图 — in the spirit of Codex Dream Skin, elevated.",
5
5
  "license": "MIT",
6
6
  "type": "module",