dsh-skin-galactic-opera 0.1.7 → 0.1.9

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,32 @@
2
2
 
3
3
  All notable changes to this package will be documented in this file.
4
4
 
5
+ ## 0.1.9 - 2026-09-03
6
+
7
+ ### Changed
8
+
9
+ - Replaces the README with separate English and Simplified Chinese sections linked from a language switcher at the top.
10
+ - Refreshes the bottom-right telemetry HUD promptly when switching conversations or navigating between sessions.
11
+
12
+ ### Fixed
13
+
14
+ - Keeps navigation-triggered telemetry refreshes active even when the instruction input still has focus.
15
+
16
+ ## 0.1.8 - 2026-09-03
17
+
18
+ ### Added
19
+
20
+ - Adds a subtle black-hole infall effect using a lightweight pseudo-element particle layer and a send-time pull animation.
21
+
22
+ ### Changed
23
+
24
+ - Reduces idle black-hole animation cost by slowing the new infall layer, shrinking its paint area, lowering opacity, and removing animated filters.
25
+ - Keeps telemetry panel chrome clipped through the same cutout layer in both typing and idle states.
26
+
27
+ ### Fixed
28
+
29
+ - Fixes telemetry panel cutout artifacts that could show a filled or rectangular top-left corner while typing.
30
+
5
31
  ## 0.1.7 - 2026-09-03
6
32
 
7
33
  ### Changed
package/README.md CHANGED
@@ -1,37 +1,51 @@
1
1
  # dsh-skin-galactic-opera
2
2
 
3
- Unofficial cinematic space-opera dark skin bundle for the DSH Web GUI.
3
+ <p align="center">DSH Web GUI 非官方 太空歌剧风 暗色 动态 皮肤插件</p>
4
+
5
+ <p align="center">
6
+ <a href="#english">English</a> · <a href="#简体中文">简体中文</a>
7
+ </p>
4
8
 
5
- 非官方 DSH Web GUI 太空歌剧暗色皮肤插件。它使用通用科幻视觉语言,包括深空背景、霓虹 HUD、黑洞吸积盘、行星与卫星轨道、流星、V 形战机剪影和提交消息时的超空间跃迁效果。
9
+ ---
6
10
 
7
- This package does not include or recreate any official franchise logos, characters, ship designs, quotes, or proprietary names.
11
+ ## English
12
+
13
+ Unofficial cinematic space-opera dark skin bundle for the DSH Web GUI.
8
14
 
9
- 本插件不包含也不复刻任何特定影视作品的官方 logo、角色、飞船设计、台词或专有名称。
15
+ It uses generic sci-fi visual language: deep-space backgrounds, neon HUD chrome, a central black-hole accretion disk, a planet with orbital elements, scanner UI, comet trails, energy beams, subtle starfighter silhouettes, telemetry chrome, and a hyperspace-style send effect.
10
16
 
11
- ## Features
17
+ > This package is not affiliated with, endorsed by, or derived from any specific franchise. It does **not** include or recreate official logos, characters, ship designs, quotes, proprietary names, or protected visual designs.
18
+
19
+ ### Features
12
20
 
13
21
  - Registers and enables the `galactic-opera` dark theme.
14
22
  - Overrides DSH Web GUI theme tokens for backgrounds, borders, text, brand colors, state colors, scrollbars, and sidebar surfaces.
15
- - Adds global visual styling for star fields, diagonal hyperspace lanes, hover glow, selection highlight, and code block glow.
16
- - Adds decorative space-opera elements:
17
- - Central black-hole accretion disk.
18
- - Top-right planet, one moon, and an elliptical satellite orbit.
19
- - Bottom-left rotating scanner HUD and holographic route map.
20
- - Red, cyan, and gold energy beams.
21
- - Sparse twinkling stars, comets, and generic V-shaped starfighter silhouettes.
22
- - Gold mission-briefing crawl panel.
23
+ - Adds global space-opera styling:
24
+ - deep-space background layers;
25
+ - diagonal hyperspace lanes;
26
+ - hover glow for buttons, inputs, messages, and code blocks;
27
+ - sci-fi text selection and code block glow.
28
+ - Adds decorative visual elements:
29
+ - central black-hole accretion disk with subtle infall particles;
30
+ - top-right planet, moon, and elliptical satellite orbit;
31
+ - bottom-left rotating scanner HUD and holographic route map;
32
+ - red, cyan, and gold energy beams;
33
+ - sparse twinkling stars, comets, and generic V-shaped starfighter silhouettes;
34
+ - gold mission-briefing crawl panel.
23
35
  - Adds interactions:
24
- - Subtle mouse parallax.
25
- - Click energy pulse.
26
- - Hover energy outlines on buttons, inputs, messages, and code blocks.
27
- - Bottom telemetry/status information is mirrored into a fixed bottom-right sci-fi panel.
28
- - Scanner target dot projected from the pointer direction relative to the viewport center; the target lights only when the scanner sweep passes it.
29
- - Automatic hyperspace burst after submitting a new instruction or message.
36
+ - subtle pointer parallax;
37
+ - click energy pulse;
38
+ - scanner target ping projected from the clicked position;
39
+ - automatic hyperspace burst after submitting a new instruction or message;
40
+ - fixed bottom-right telemetry/status HUD panel.
41
+ - Uses Shadow DOM for the decorative layer to reduce interference from host application styles.
30
42
  - Respects `prefers-reduced-motion: reduce` by disabling major animations.
31
43
 
32
- ## Telemetry panel
44
+ ### Telemetry panel
45
+
46
+ When DSH Web exposes bottom status/usage data, the skin keeps the original UI layout in place and mirrors the detected global telemetry into a non-interactive bottom-right HUD panel.
33
47
 
34
- When DSH Web exposes bottom status/usage data, the skin keeps the original UI layout in place and mirrors the detected global telemetry into a non-interactive bottom-right HUD panel. The panel is intended to show a consistent five-line status block:
48
+ The panel is intended to show a consistent five-line status block:
35
49
 
36
50
  ```text
37
51
  312 轮 · 8732 步
@@ -43,9 +57,9 @@ LLM 2253m42s · 工具调用 972m8s
43
57
 
44
58
  The skin treats each original pipe-separated bottom-bar segment as a complete information block, so combined items such as `首 token 平均 ... · ... tok/s` and `输入 ... · 输出 ...` remain intact. It also filters nearby message-level timing text and settings/menu text so the panel stays focused on global session telemetry.
45
59
 
46
- ## Installation
60
+ ### Installation
47
61
 
48
- ### From npm
62
+ #### From npm
49
63
 
50
64
  Recommended for most users:
51
65
 
@@ -59,13 +73,13 @@ npm package page:
59
73
  https://www.npmjs.com/package/dsh-skin-galactic-opera
60
74
  ```
61
75
 
62
- ### From GitHub
76
+ #### From GitHub
63
77
 
64
78
  ```powershell
65
79
  dsh plugin --profile web add https://github.com/xmnathan/dsh-skin-galactic-opera.git
66
80
  ```
67
81
 
68
- ### From a local checkout
82
+ #### From a local checkout
69
83
 
70
84
  From the parent directory of this package:
71
85
 
@@ -91,7 +105,7 @@ If the browser keeps an older client bundle, use a hard refresh:
91
105
  Ctrl + F5
92
106
  ```
93
107
 
94
- ## Uninstall
108
+ ### Uninstall
95
109
 
96
110
  ```powershell
97
111
  dsh plugin --profile web remove dsh-skin-galactic-opera
@@ -99,7 +113,7 @@ dsh plugin --profile web remove dsh-skin-galactic-opera
99
113
 
100
114
  Refresh the Web GUI after uninstalling.
101
115
 
102
- ## Development
116
+ ### Development
103
117
 
104
118
  Check browser-side JavaScript syntax:
105
119
 
@@ -119,7 +133,7 @@ Publish to npm:
119
133
  npm publish
120
134
  ```
121
135
 
122
- ## Package structure
136
+ ### Package structure
123
137
 
124
138
  ```text
125
139
  dsh-skin-galactic-opera/
@@ -138,6 +152,160 @@ dsh-skin-galactic-opera/
138
152
  - `lib/index.js`: host-side no-op entry.
139
153
  - `lib/client.js`: browser-side theme, decoration, and interaction implementation.
140
154
 
141
- ## License
155
+ ### License
156
+
157
+ MIT
158
+
159
+ <p align="right"><a href="#dsh-skin-galactic-opera">Back to top ↑</a></p>
160
+
161
+ ---
162
+
163
+ ## 简体中文
164
+
165
+ DSH Web GUI 的非官方电影感太空歌剧暗色皮肤插件。
166
+
167
+ 它使用通用科幻视觉语言:深空背景、霓虹 HUD、中央黑洞吸积盘、行星与轨道元素、扫描器界面、彗星轨迹、能量束、克制的战机剪影、遥测信息面板,以及发送消息时的超空间风格特效。
168
+
169
+ > 本插件不隶属于、不受认可于、也不派生自任何特定影视或游戏系列。它**不包含也不复刻**任何官方 logo、角色、飞船设计、台词、专有名称或受保护视觉设计。
170
+
171
+ ### 功能特性
172
+
173
+ - 注册并启用 `galactic-opera` 暗色主题。
174
+ - 覆盖 DSH Web GUI 的主题 token,包括背景、边框、文本、品牌色、状态色、滚动条和侧边栏表面。
175
+ - 添加全局太空歌剧风格:
176
+ - 深空背景层;
177
+ - 斜向超空间航道;
178
+ - 按钮、输入框、消息和代码块的悬停辉光;
179
+ - 科幻风格文本选中与代码块辉光。
180
+ - 添加装饰性视觉元素:
181
+ - 带轻微吸入粒子的中央黑洞吸积盘;
182
+ - 右上角行星、卫星和椭圆卫星轨道;
183
+ - 左下角旋转扫描盘 HUD 和全息路线图;
184
+ - 红、青、金三色能量束;
185
+ - 稀疏闪烁星点、彗星和通用 V 形战机剪影;
186
+ - 金色任务简报滚动面板。
187
+ - 添加交互效果:
188
+ - 轻微鼠标视差;
189
+ - 点击能量脉冲;
190
+ - 根据点击位置投影到扫描盘的目标 ping;
191
+ - 提交新指令或消息后的自动超空间爆发;
192
+ - 固定在右下角的 telemetry / 状态 HUD 面板。
193
+ - 装饰层使用 Shadow DOM,减少宿主应用样式对行星、扫描盘、点击脉冲等几何形态的污染。
194
+ - 遵循 `prefers-reduced-motion: reduce`,会关闭主要动画。
195
+
196
+ ### Telemetry 面板
197
+
198
+ 当 DSH Web 暴露底部状态/用量信息时,皮肤会保留原始 UI 布局,并将检测到的全局 telemetry 镜像到右下角的非交互 HUD 面板中。
199
+
200
+ 面板目标是稳定显示五行状态信息:
201
+
202
+ ```text
203
+ 312 轮 · 8732 步
204
+ LLM 2253m42s · 工具调用 972m8s
205
+ 首 token 平均 10.5s · 58 tok/s
206
+ 缓存命中 97%
207
+ 输入 1369M tok · 输出 2.5M tok
208
+ ```
209
+
210
+ 皮肤会把原始底栏中用竖线分隔的每一段都视为完整信息块,因此 `首 token 平均 ... · ... tok/s`、`输入 ... · 输出 ...` 这类组合信息不会被拆散。同时也会过滤附近的单条消息耗时、设置菜单文本等内容,让面板聚焦于全局会话 telemetry。
211
+
212
+ ### 安装
213
+
214
+ #### 通过 npm 安装
215
+
216
+ 推荐大多数用户使用:
217
+
218
+ ```powershell
219
+ dsh plugin --profile web add dsh-skin-galactic-opera
220
+ ```
221
+
222
+ npm 包页面:
223
+
224
+ ```text
225
+ https://www.npmjs.com/package/dsh-skin-galactic-opera
226
+ ```
227
+
228
+ #### 通过 GitHub 安装
229
+
230
+ ```powershell
231
+ dsh plugin --profile web add https://github.com/xmnathan/dsh-skin-galactic-opera.git
232
+ ```
233
+
234
+ #### 通过本地源码安装
235
+
236
+ 在本包的上级目录执行:
237
+
238
+ ```powershell
239
+ dsh plugin --profile web add ./dsh-skin-galactic-opera
240
+ ```
241
+
242
+ 也可以使用绝对路径:
243
+
244
+ ```powershell
245
+ dsh plugin --profile web add D:\path\to\dsh-skin-galactic-opera
246
+ ```
247
+
248
+ 然后刷新 DSH Web GUI,通常地址为:
249
+
250
+ ```text
251
+ http://127.0.0.1:3080
252
+ ```
253
+
254
+ 如果浏览器仍然缓存旧的客户端 bundle,请使用硬刷新:
255
+
256
+ ```text
257
+ Ctrl + F5
258
+ ```
259
+
260
+ ### 卸载
261
+
262
+ ```powershell
263
+ dsh plugin --profile web remove dsh-skin-galactic-opera
264
+ ```
265
+
266
+ 卸载后刷新 Web GUI。
267
+
268
+ ### 开发
269
+
270
+ 检查浏览器端 JavaScript 语法:
271
+
272
+ ```powershell
273
+ npm run check
274
+ ```
275
+
276
+ 发布前预览 npm 包内容:
277
+
278
+ ```powershell
279
+ npm run pack:dry
280
+ ```
281
+
282
+ 发布到 npm:
283
+
284
+ ```powershell
285
+ npm publish
286
+ ```
287
+
288
+ ### 包结构
289
+
290
+ ```text
291
+ dsh-skin-galactic-opera/
292
+ ├─ package.json
293
+ ├─ cordis.patch.yml
294
+ ├─ README.md
295
+ ├─ LICENSE
296
+ ├─ CHANGELOG.md
297
+ └─ lib/
298
+ ├─ index.js
299
+ └─ client.js
300
+ ```
301
+
302
+ - `package.json`:包元数据、npm 发布设置、DSH bundle 声明和 Web client 插件声明。
303
+ - `cordis.patch.yml`:将 `dsh-skin-galactic-opera` client 插件插入 Web profile。
304
+ - `lib/index.js`:宿主侧空实现入口。
305
+ - `lib/client.js`:浏览器侧主题、装饰层和交互实现。
306
+
307
+ ### 许可证
142
308
 
143
309
  MIT
310
+
311
+ <p align="right"><a href="#dsh-skin-galactic-opera">返回顶部 ↑</a></p>
package/lib/client.js CHANGED
@@ -324,7 +324,32 @@ body.dsh-skin-galactic-opera .dsh-skin-nebula-core {
324
324
  0 0 112px rgba(255,71,120,0.10);
325
325
  filter: blur(0.55px) saturate(1.22);
326
326
  mix-blend-mode: screen;
327
- animation: dsh-skin-blackhole-breathe 7.2s ease-in-out infinite;
327
+ animation: dsh-skin-blackhole-breathe 9.6s ease-in-out infinite;
328
+ }
329
+
330
+ body.dsh-skin-galactic-opera .dsh-skin-nebula-core::after {
331
+ content: "";
332
+ position: absolute;
333
+ pointer-events: none;
334
+ border-radius: 50%;
335
+ mix-blend-mode: screen;
336
+ inset: -22%;
337
+ opacity: 0;
338
+ background:
339
+ radial-gradient(circle at 50% 14%, rgba(255,255,255,0.72) 0 1px, transparent 1.8px),
340
+ radial-gradient(circle at 80% 44%, rgba(125,227,255,0.58) 0 1.1px, transparent 2px),
341
+ radial-gradient(circle at 24% 66%, rgba(255,207,92,0.48) 0 1px, transparent 1.8px);
342
+ -webkit-mask-image: radial-gradient(circle, transparent 0 16%, #000 24% 68%, transparent 82%);
343
+ mask-image: radial-gradient(circle, transparent 0 16%, #000 24% 68%, transparent 82%);
344
+ animation: dsh-skin-blackhole-infall 9.8s cubic-bezier(.42,0,.18,1) infinite;
345
+ }
346
+
347
+ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-hyperspace .dsh-skin-nebula-core {
348
+ animation: dsh-skin-blackhole-warp-pull 880ms cubic-bezier(.16,.8,.25,1) both;
349
+ }
350
+
351
+ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-hyperspace .dsh-skin-nebula-core::after {
352
+ animation: dsh-skin-blackhole-infall-burst 880ms cubic-bezier(.16,.8,.25,1) both;
328
353
  }
329
354
 
330
355
  body.dsh-skin-galactic-opera .dsh-skin-orb {
@@ -612,10 +637,12 @@ body.dsh-skin-galactic-opera .dsh-skin-mission-crawl::before {
612
637
  }
613
638
 
614
639
  body.dsh-skin-galactic-opera :is(.dsh-skin-twinkle, .dsh-skin-nebula-core, .dsh-skin-orb, .dsh-skin-scanner, .dsh-skin-scanner-target, .dsh-skin-pulse),
640
+ body.dsh-skin-galactic-opera .dsh-skin-nebula-core::after,
615
641
  body.dsh-skin-galactic-opera .dsh-skin-satellite::before,
616
642
  body.dsh-skin-galactic-opera .dsh-skin-satellite-orbit::before,
617
643
  body.dsh-skin-galactic-opera .dsh-skin-satellite-orbit-front::before,
618
644
  body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor :is(.dsh-skin-twinkle, .dsh-skin-nebula-core, .dsh-skin-orb, .dsh-skin-scanner, .dsh-skin-scanner-target, .dsh-skin-pulse),
645
+ body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-nebula-core::after,
619
646
  body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-satellite::before,
620
647
  body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-satellite-orbit::before,
621
648
  body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-satellite-orbit-front::before {
@@ -732,28 +759,21 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel {
732
759
  gap: 4px;
733
760
  width: min(260px, 36vw);
734
761
  max-height: none;
735
- overflow: visible;
762
+ overflow: hidden;
736
763
  padding: 19px 12px 12px;
737
- border: 1px solid rgba(125,227,255,0.48);
738
- border-left-color: rgba(255,207,92,0.62);
739
- border-bottom-color: rgba(255,71,120,0.36);
764
+ border: 0;
740
765
  clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 13px), calc(100% - 13px) 100%, 0 100%, 0 14px);
741
766
  color: rgba(248,251,255,0.92);
742
- background:
743
- linear-gradient(135deg, rgba(255,207,92,0.20) 0 10px, transparent 11px),
744
- linear-gradient(315deg, rgba(125,227,255,0.18) 0 12px, transparent 13px),
745
- linear-gradient(180deg, rgba(6,10,26,0.92), rgba(10,17,42,0.84));
746
- box-shadow:
747
- inset 0 0 0 1px rgba(255,255,255,0.07),
748
- inset 0 0 24px rgba(125,227,255,0.09),
749
- 0 0 28px rgba(125,227,255,0.22),
750
- 0 0 52px rgba(255,71,120,0.10);
751
- backdrop-filter: blur(12px) saturate(1.35);
752
- -webkit-backdrop-filter: blur(12px) saturate(1.35);
767
+ background: transparent;
768
+ box-shadow: none;
753
769
  pointer-events: none;
754
770
  }
755
771
 
756
772
  body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active .dsh-skin-telemetry-panel {
773
+ clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 13px), calc(100% - 13px) 100%, 0 100%, 0 14px);
774
+ }
775
+
776
+ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active .dsh-skin-telemetry-panel::after {
757
777
  backdrop-filter: none;
758
778
  -webkit-backdrop-filter: none;
759
779
  }
@@ -778,6 +798,7 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel[data-collapsed="true"] .d
778
798
  body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel::before {
779
799
  content: "TELEMETRY";
780
800
  position: absolute;
801
+ z-index: 1;
781
802
  left: 14px;
782
803
  top: 5px;
783
804
  color: rgba(255,207,92,0.82);
@@ -789,12 +810,24 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel::before {
789
810
  body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel::after {
790
811
  content: "";
791
812
  position: absolute;
792
- inset: 4px;
793
- border: 1px solid rgba(125,227,255,0.16);
794
- clip-path: polygon(11px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 11px);
813
+ z-index: 0;
814
+ inset: 0;
815
+ border: 1px solid rgba(125,227,255,0.48);
816
+ border-left-color: rgba(255,207,92,0.62);
817
+ border-bottom-color: rgba(255,71,120,0.36);
818
+ clip-path: polygon(14px 0, 100% 0, 100% calc(100% - 13px), calc(100% - 13px) 100%, 0 100%, 0 14px);
795
819
  background:
796
820
  repeating-linear-gradient(90deg, transparent 0 18px, rgba(125,227,255,0.045) 19px, transparent 20px 36px),
797
- linear-gradient(90deg, rgba(125,227,255,0.10), transparent 30%, rgba(255,71,120,0.06));
821
+ linear-gradient(90deg, rgba(125,227,255,0.10), transparent 30%, rgba(255,71,120,0.06)),
822
+ linear-gradient(315deg, rgba(125,227,255,0.18) 0 12px, transparent 13px),
823
+ linear-gradient(180deg, rgba(6,10,26,0.92), rgba(10,17,42,0.84));
824
+ box-shadow:
825
+ inset 0 0 0 1px rgba(255,255,255,0.07),
826
+ inset 0 0 24px rgba(125,227,255,0.09),
827
+ 0 0 28px rgba(125,227,255,0.22),
828
+ 0 0 52px rgba(255,71,120,0.10);
829
+ backdrop-filter: blur(12px) saturate(1.35);
830
+ -webkit-backdrop-filter: blur(12px) saturate(1.35);
798
831
  pointer-events: none;
799
832
  }
800
833
 
@@ -938,8 +971,29 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
938
971
  }
939
972
 
940
973
  @keyframes dsh-skin-blackhole-breathe {
941
- 0%, 100% { opacity: 0.18; transform: translate(-50%, -50%) scale(0.96) rotate(0deg); filter: blur(0.65px) saturate(1.08); }
942
- 50% { opacity: 0.30; transform: translate(-50%, -50%) scale(1.05) rotate(7deg); filter: blur(0.45px) saturate(1.36); }
974
+ 0%, 100% { opacity: 0.18; transform: translate(-50%, -50%) scale(0.97) rotate(0deg); }
975
+ 50% { opacity: 0.28; transform: translate(-50%, -50%) scale(1.03) rotate(5deg); }
976
+ }
977
+
978
+ @keyframes dsh-skin-blackhole-infall {
979
+ 0% { opacity: 0; transform: rotate(-16deg) scale(1.12); }
980
+ 18% { opacity: 0.22; }
981
+ 64% { opacity: 0.12; transform: rotate(20deg) scale(0.78); }
982
+ 100% { opacity: 0; transform: rotate(32deg) scale(0.60); }
983
+ }
984
+
985
+ @keyframes dsh-skin-blackhole-warp-pull {
986
+ 0% { opacity: 0.24; transform: translate(-50%, -50%) scale(1) rotate(0deg); filter: blur(0.55px) saturate(1.22); }
987
+ 16% { opacity: 0.34; transform: translate(-50%, -50%) scale(0.88) rotate(-8deg); filter: blur(0.42px) saturate(1.55) brightness(1.12); }
988
+ 46% { opacity: 0.40; transform: translate(-50%, -50%) scale(1.12) rotate(12deg); filter: blur(0.38px) saturate(1.62) brightness(1.18); }
989
+ 100% { opacity: 0.24; transform: translate(-50%, -50%) scale(1.02) rotate(0deg); filter: blur(0.55px) saturate(1.22); }
990
+ }
991
+
992
+ @keyframes dsh-skin-blackhole-infall-burst {
993
+ 0% { opacity: 0; transform: rotate(-24deg) scale(1.42); }
994
+ 18% { opacity: 0.62; transform: rotate(10deg) scale(0.72); }
995
+ 42% { opacity: 0.48; transform: rotate(26deg) scale(0.50); }
996
+ 100% { opacity: 0; transform: rotate(58deg) scale(0.34); }
943
997
  }
944
998
 
945
999
  @keyframes dsh-skin-orb-hover {
@@ -978,9 +1032,10 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
978
1032
  }
979
1033
 
980
1034
  @keyframes dsh-skin-galactic-opera-hyperspace-burst {
981
- 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.32) rotate(0deg); }
982
- 15% { opacity: 0.9; }
983
- 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.45) rotate(10deg); }
1035
+ 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.82) rotate(-8deg); filter: blur(0.8px) brightness(0.82); }
1036
+ 12% { opacity: 0.88; transform: translate(-50%, -50%) scale(0.24) rotate(0deg); filter: blur(0.2px) brightness(1.52); }
1037
+ 28% { opacity: 0.9; transform: translate(-50%, -50%) scale(0.42) rotate(4deg); filter: blur(0.12px) brightness(1.36); }
1038
+ 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.5) rotate(12deg); filter: blur(0.4px) brightness(0.9); }
984
1039
  }
985
1040
 
986
1041
  @keyframes dsh-skin-route-pulse {
@@ -1397,9 +1452,14 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1397
1452
  let currentSources = new Set();
1398
1453
  let lastText = "";
1399
1454
  let frame = 0;
1455
+ let frameIgnoresTelemetryPause = false;
1400
1456
  let forceTelemetryRescan = true;
1401
1457
  let telemetryRefreshesSinceFullScan = 0;
1458
+ let lastTelemetryLocationKey = typeof window.location === "undefined" ? "" : `${window.location.pathname}${window.location.search}${window.location.hash}`;
1459
+ const telemetryNavigationTimers = new Set();
1402
1460
  const TELEMETRY_UPDATE_DELAY = 300;
1461
+ const TELEMETRY_NAV_UPDATE_DELAY = 48;
1462
+ const TELEMETRY_NAV_FOLLOWUP_DELAY = 220;
1403
1463
  const TELEMETRY_FULL_RESCAN_UPDATES = 7;
1404
1464
  let collapsed = false;
1405
1465
  try {
@@ -1613,9 +1673,10 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1613
1673
  if (!sources.every((source) => source.isConnected && getCandidateInfo(source) !== undefined)) return false;
1614
1674
  return splitTelemetryRows(getSourcesText(currentSources)).length > 0;
1615
1675
  };
1616
- const update = () => {
1676
+ const update = ({ ignorePause = false } = {}) => {
1617
1677
  frame = 0;
1618
- if (isTelemetryPaused()) return;
1678
+ frameIgnoresTelemetryPause = false;
1679
+ if (!ignorePause && isTelemetryPaused()) return;
1619
1680
  let nextSources = currentSources;
1620
1681
  let text = getSourcesText(nextSources);
1621
1682
  const needsFullScan = forceTelemetryRescan || telemetryRefreshesSinceFullScan >= TELEMETRY_FULL_RESCAN_UPDATES || !areCachedSourcesUsable();
@@ -1634,13 +1695,78 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1634
1695
  lastText = text;
1635
1696
  renderPanel(text);
1636
1697
  };
1637
- const schedule = () => {
1638
- if (isTelemetryPaused()) return;
1639
- if (frame === 0) frame = window.setTimeout(update, TELEMETRY_UPDATE_DELAY);
1698
+ const schedule = ({ delay = TELEMETRY_UPDATE_DELAY, force = false, ignorePause = false } = {}) => {
1699
+ if (!ignorePause && isTelemetryPaused()) return;
1700
+ if (force) forceTelemetryRescan = true;
1701
+ if (frame !== 0) {
1702
+ if (!force && delay >= TELEMETRY_UPDATE_DELAY) return;
1703
+ window.clearTimeout(frame);
1704
+ frameIgnoresTelemetryPause = false;
1705
+ }
1706
+ frameIgnoresTelemetryPause = ignorePause;
1707
+ frame = window.setTimeout(() => update({ ignorePause }), delay);
1708
+ };
1709
+ const getTelemetryLocationKey = () => `${window.location.pathname}${window.location.search}${window.location.hash}`;
1710
+ const setTelemetryNavigationTimer = (callback, delay) => {
1711
+ const timer = window.setTimeout(() => {
1712
+ telemetryNavigationTimers.delete(timer);
1713
+ callback();
1714
+ }, delay);
1715
+ telemetryNavigationTimers.add(timer);
1716
+ return timer;
1717
+ };
1718
+ const refreshTelemetryForNavigation = () => {
1719
+ lastTelemetryLocationKey = getTelemetryLocationKey();
1720
+ schedule({ delay: TELEMETRY_NAV_UPDATE_DELAY, force: true, ignorePause: true });
1721
+ setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
1722
+ };
1723
+ const checkTelemetryLocation = () => {
1724
+ const nextKey = getTelemetryLocationKey();
1725
+ if (nextKey !== lastTelemetryLocationKey) refreshTelemetryForNavigation();
1726
+ };
1727
+ const onTelemetryNavigationClick = (event) => {
1728
+ if (isSkinOwnedNode(event.target) || isEditableTarget(event.target)) return;
1729
+ const target = event.target instanceof Element ? event.target.closest("a[href], button, [role=button], [aria-current], [data-active]") : null;
1730
+ if (target === null) return;
1731
+ schedule({ delay: TELEMETRY_NAV_UPDATE_DELAY, force: true, ignorePause: true });
1732
+ setTelemetryNavigationTimer(checkTelemetryLocation, 0);
1733
+ setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
1640
1734
  };
1735
+ const isPotentialTelemetryNavigationMutation = (mutation) => {
1736
+ if (mutation.type !== "childList") return false;
1737
+ const nodes = [...mutation.addedNodes, ...mutation.removedNodes];
1738
+ return nodes.some((node) => {
1739
+ const element = getMutationElement(node);
1740
+ if (!(element instanceof Element) || isSkinOwnedNode(element) || isEditableTarget(element)) return false;
1741
+ const text = normalizeTelemetryText(element.textContent || "");
1742
+ return element.matches?.("main, section, article, aside, nav, [role=main], [role=navigation], [data-active], [aria-current]")
1743
+ || element.querySelector?.("main, section, article, aside, nav, [role=main], [role=navigation], [data-active], [aria-current]") !== null
1744
+ || telemetryPattern.test(text);
1745
+ });
1746
+ };
1747
+ const originalPushState = window.history?.pushState;
1748
+ const originalReplaceState = window.history?.replaceState;
1749
+ let telemetryPushState;
1750
+ let telemetryReplaceState;
1751
+ if (typeof originalPushState === "function") {
1752
+ telemetryPushState = function dshSkinTelemetryPushState(...args) {
1753
+ const result = originalPushState.apply(this, args);
1754
+ setTelemetryNavigationTimer(checkTelemetryLocation, 0);
1755
+ return result;
1756
+ };
1757
+ window.history.pushState = telemetryPushState;
1758
+ }
1759
+ if (typeof originalReplaceState === "function") {
1760
+ telemetryReplaceState = function dshSkinTelemetryReplaceState(...args) {
1761
+ const result = originalReplaceState.apply(this, args);
1762
+ setTelemetryNavigationTimer(checkTelemetryLocation, 0);
1763
+ return result;
1764
+ };
1765
+ window.history.replaceState = telemetryReplaceState;
1766
+ }
1641
1767
  const onTelemetryFocusIn = (event) => {
1642
1768
  if (!isInstructionInputTarget(event.target)) return;
1643
- if (frame !== 0) {
1769
+ if (frame !== 0 && !frameIgnoresTelemetryPause) {
1644
1770
  window.clearTimeout(frame);
1645
1771
  frame = 0;
1646
1772
  }
@@ -1654,19 +1780,35 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1654
1780
  };
1655
1781
  const observer = typeof MutationObserver === "undefined" ? undefined : new MutationObserver((mutations) => {
1656
1782
  if (mutations.every(isSkinOwnedMutation)) return;
1783
+ if (isTelemetryPaused() && mutations.some(isPotentialTelemetryNavigationMutation)) {
1784
+ schedule({ delay: TELEMETRY_NAV_UPDATE_DELAY, force: true, ignorePause: true });
1785
+ setTelemetryNavigationTimer(() => schedule({ delay: 0, force: true, ignorePause: true }), TELEMETRY_NAV_FOLLOWUP_DELAY);
1786
+ return;
1787
+ }
1657
1788
  schedule();
1658
1789
  });
1659
1790
  schedule();
1660
1791
  observer?.observe(document.body, { childList: true, subtree: true, characterData: true });
1661
1792
  window.addEventListener("resize", onTelemetryResize, { passive: true });
1793
+ window.addEventListener("popstate", checkTelemetryLocation, { passive: true });
1794
+ window.addEventListener("hashchange", checkTelemetryLocation, { passive: true });
1795
+ document.addEventListener("click", onTelemetryNavigationClick, true);
1662
1796
  document.addEventListener("focusin", onTelemetryFocusIn);
1663
1797
  document.addEventListener("focusout", onTelemetryFocusOut);
1664
1798
  return () => {
1665
1799
  observer?.disconnect();
1800
+ if (telemetryPushState !== undefined && window.history.pushState === telemetryPushState) window.history.pushState = originalPushState;
1801
+ if (telemetryReplaceState !== undefined && window.history.replaceState === telemetryReplaceState) window.history.replaceState = originalReplaceState;
1666
1802
  window.removeEventListener("resize", onTelemetryResize);
1803
+ window.removeEventListener("popstate", checkTelemetryLocation);
1804
+ window.removeEventListener("hashchange", checkTelemetryLocation);
1805
+ document.removeEventListener("click", onTelemetryNavigationClick, true);
1667
1806
  document.removeEventListener("focusin", onTelemetryFocusIn);
1668
1807
  document.removeEventListener("focusout", onTelemetryFocusOut);
1669
1808
  if (frame !== 0) window.clearTimeout(frame);
1809
+ frameIgnoresTelemetryPause = false;
1810
+ for (const timer of telemetryNavigationTimers) window.clearTimeout(timer);
1811
+ telemetryNavigationTimers.clear();
1670
1812
  for (const source of currentSources) source.classList.remove("dsh-skin-telemetry-source-hidden");
1671
1813
  toggle.remove();
1672
1814
  panel.remove();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-skin-galactic-opera",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Unofficial cinematic space-opera dark skin bundle for the DSH Web GUI.",
5
5
  "repository": {
6
6
  "type": "git",