dsh-skin-galactic-opera 0.1.5 → 0.1.7

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/lib/client.js +291 -93
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  All notable changes to this package will be documented in this file.
4
4
 
5
+ ## 0.1.7 - 2026-09-03
6
+
7
+ ### Changed
8
+
9
+ - Moves the decorative visual layer into Shadow DOM to isolate scanner, planet, pulse, and black-hole geometry from DSH host style regressions.
10
+ - Keeps the input-mode black hole visually stable while still reducing high-motion distraction elsewhere.
11
+ - Aligns the hyperspace burst effect to the black-hole center after Shadow DOM isolation.
12
+
13
+ ### Fixed
14
+
15
+ - Prevents Shadow DOM container nesting from shifting the scanner disk, planet, satellite orbit, and other decorative elements toward the viewport edges.
16
+
17
+ ## 0.1.6 - 2026-08-28
18
+
19
+ ### Changed
20
+
21
+ - Further reduces telemetry overhead by using cached candidate geometry, adding a bounded full-rescan TTL, increasing update debounce, and avoiding observer array allocations.
22
+ - Refines telemetry text extraction so hot-path probing uses lightweight text reads while rendered output preserves native visual spacing.
23
+ - Uses pointer movement distance thresholds for parallax updates instead of fixed time throttling.
24
+ - Reuses fixed telemetry row nodes and disables the telemetry backdrop blur while typing.
25
+
26
+ ### Fixed
27
+
28
+ - Prevents occasional telemetry panel disappearance during full rescans by temporarily making hidden native telemetry sources discoverable to `elementsFromPoint`.
29
+
5
30
  ## 0.1.5 - 2026-08-28
6
31
 
7
32
  ### Added
package/lib/client.js CHANGED
@@ -10,6 +10,7 @@ window.__ModuleLoader__.load({
10
10
  const THEME_LABEL = "Galactic Opera";
11
11
  const STYLE_ID = "dsh-skin-galactic-opera-style";
12
12
  const DECOR_ID = "dsh-skin-galactic-opera-decor";
13
+ const DECOR_HOST_CLASS = "dsh-skin-galactic-opera-decor-host";
13
14
  const CSS_TAG_ID = `${PLUGIN_ID}/global.css`;
14
15
 
15
16
  const TOKENS = Object.freeze({
@@ -160,17 +161,13 @@ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active #root::before
160
161
  will-change: auto;
161
162
  }
162
163
 
163
- body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active .dsh-skin-galactic-opera-decor {
164
- opacity: 0.28;
165
- }
166
-
167
- body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active :is(.dsh-skin-nebula-core, .dsh-skin-energy, .dsh-skin-comet, .dsh-skin-starfighter, .dsh-skin-mission-crawl, .dsh-skin-scanner, .dsh-skin-route-map),
164
+ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active :is(.dsh-skin-energy, .dsh-skin-comet, .dsh-skin-starfighter, .dsh-skin-mission-crawl, .dsh-skin-scanner, .dsh-skin-route-map),
168
165
  body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active .dsh-skin-scanner::after {
169
166
  animation-play-state: paused !important;
170
167
  }
171
168
 
172
- body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active :is(.dsh-skin-nebula-core, .dsh-skin-energy, .dsh-skin-comet, .dsh-skin-starfighter, .dsh-skin-mission-crawl) {
173
- opacity: 0.08 !important;
169
+ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active :is(.dsh-skin-energy, .dsh-skin-comet, .dsh-skin-starfighter, .dsh-skin-mission-crawl) {
170
+ opacity: 0.16 !important;
174
171
  }
175
172
 
176
173
  body.dsh-skin-galactic-opera #root > *,
@@ -197,6 +194,7 @@ body.dsh-skin-galactic-opera [class*="Sidebar"] {
197
194
  0 0 40px rgba(125, 227, 255, 0.12) !important;
198
195
  }
199
196
 
197
+ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor-host,
200
198
  body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor {
201
199
  position: fixed;
202
200
  inset: -2vmax;
@@ -206,16 +204,28 @@ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor {
206
204
  mix-blend-mode: screen;
207
205
  }
208
206
 
207
+ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor-host {
208
+ display: block;
209
+ width: auto;
210
+ height: auto;
211
+ border: 0 !important;
212
+ border-radius: 0 !important;
213
+ background: transparent !important;
214
+ }
215
+
209
216
  body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor::before {
210
217
  content: "";
211
218
  position: absolute;
212
- inset: -12vmax;
219
+ left: 48%;
220
+ top: 50%;
221
+ width: 140vmax;
222
+ height: 140vmax;
213
223
  opacity: 0;
214
224
  pointer-events: none;
215
225
  background:
216
226
  repeating-conic-gradient(from 0deg at 50% 50%, transparent 0deg 5deg, rgba(125,227,255,0.72) 5.4deg 6deg, transparent 6.4deg 12deg),
217
227
  radial-gradient(circle at 50% 50%, rgba(255,255,255,0.82), transparent 8vmin, rgba(255,207,92,0.26) 12vmin, transparent 36vmin);
218
- transform: scale(0.5);
228
+ transform: translate(-50%, -50%) scale(0.5);
219
229
  filter: blur(0.2px);
220
230
  }
221
231
 
@@ -223,6 +233,23 @@ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-hyperspace .dsh-skin-galact
223
233
  animation: dsh-skin-galactic-opera-hyperspace-burst 880ms cubic-bezier(.16,.8,.25,1) both;
224
234
  }
225
235
 
236
+ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor,
237
+ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor *,
238
+ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor *::before,
239
+ body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor *::after {
240
+ box-sizing: border-box;
241
+ min-width: 0;
242
+ min-height: 0;
243
+ max-width: none;
244
+ max-height: none;
245
+ margin: 0;
246
+ padding: 0;
247
+ font: inherit;
248
+ line-height: 1;
249
+ text-decoration: none;
250
+ background-clip: border-box;
251
+ }
252
+
226
253
  body.dsh-skin-galactic-opera .dsh-skin-galactic-opera-decor span {
227
254
  position: absolute;
228
255
  display: block;
@@ -584,6 +611,32 @@ body.dsh-skin-galactic-opera .dsh-skin-mission-crawl::before {
584
611
  text-shadow: 0 0 14px rgba(255,207,92,0.46);
585
612
  }
586
613
 
614
+ 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),
615
+ body.dsh-skin-galactic-opera .dsh-skin-satellite::before,
616
+ body.dsh-skin-galactic-opera .dsh-skin-satellite-orbit::before,
617
+ body.dsh-skin-galactic-opera .dsh-skin-satellite-orbit-front::before,
618
+ 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),
619
+ body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-satellite::before,
620
+ body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-satellite-orbit::before,
621
+ body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-satellite-orbit-front::before {
622
+ border-radius: 50% !important;
623
+ border-top-left-radius: 50% !important;
624
+ border-top-right-radius: 50% !important;
625
+ border-bottom-right-radius: 50% !important;
626
+ border-bottom-left-radius: 50% !important;
627
+ }
628
+
629
+ body.dsh-skin-galactic-opera :is(.dsh-skin-energy, .dsh-skin-comet),
630
+ body.dsh-skin-galactic-opera .dsh-skin-scanner::after,
631
+ body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor :is(.dsh-skin-energy, .dsh-skin-comet),
632
+ body.dsh-skin-galactic-opera #dsh-skin-galactic-opera-decor .dsh-skin-scanner::after {
633
+ border-radius: 999px !important;
634
+ border-top-left-radius: 999px !important;
635
+ border-top-right-radius: 999px !important;
636
+ border-bottom-right-radius: 999px !important;
637
+ border-bottom-left-radius: 999px !important;
638
+ }
639
+
587
640
  body.dsh-skin-galactic-opera .dsh-skin-pulse {
588
641
  position: fixed;
589
642
  left: var(--dsh-skin-pulse-x);
@@ -700,6 +753,11 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel {
700
753
  pointer-events: none;
701
754
  }
702
755
 
756
+ body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active .dsh-skin-telemetry-panel {
757
+ backdrop-filter: none;
758
+ -webkit-backdrop-filter: none;
759
+ }
760
+
703
761
  body.dsh-skin-galactic-opera .dsh-skin-telemetry-panel[data-collapsed="true"] {
704
762
  width: 24px;
705
763
  min-height: 24px;
@@ -920,9 +978,9 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
920
978
  }
921
979
 
922
980
  @keyframes dsh-skin-galactic-opera-hyperspace-burst {
923
- 0% { opacity: 0; transform: scale(0.32) rotate(0deg); }
981
+ 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.32) rotate(0deg); }
924
982
  15% { opacity: 0.9; }
925
- 100% { opacity: 0; transform: scale(1.45) rotate(10deg); }
983
+ 100% { opacity: 0; transform: translate(-50%, -50%) scale(1.45) rotate(10deg); }
926
984
  }
927
985
 
928
986
  @keyframes dsh-skin-route-pulse {
@@ -1004,42 +1062,133 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1004
1062
  return tag;
1005
1063
  }
1006
1064
 
1065
+ const DECOR_MARKUP = [
1066
+ "<span class=\"dsh-skin-nebula-core\"></span>",
1067
+ "<span class=\"dsh-skin-twinkle dsh-skin-twinkle-a\"></span>",
1068
+ "<span class=\"dsh-skin-twinkle dsh-skin-twinkle-b\"></span>",
1069
+ "<span class=\"dsh-skin-twinkle dsh-skin-twinkle-c\"></span>",
1070
+ "<span class=\"dsh-skin-orb dsh-skin-orb-primary\"></span>",
1071
+ "<span class=\"dsh-skin-orb dsh-skin-orb-moon-a\"></span>",
1072
+ "<span class=\"dsh-skin-satellite-orbit\"></span>",
1073
+ "<span class=\"dsh-skin-satellite-orbit-front\"></span>",
1074
+ "<span class=\"dsh-skin-satellite\"></span>",
1075
+ "<span class=\"dsh-skin-scanner\"></span>",
1076
+ "<span class=\"dsh-skin-scanner-target\"></span>",
1077
+ "<span class=\"dsh-skin-route-map\"></span>",
1078
+ "<span class=\"dsh-skin-energy dsh-skin-energy-cyan\"></span>",
1079
+ "<span class=\"dsh-skin-energy dsh-skin-energy-red\"></span>",
1080
+ "<span class=\"dsh-skin-energy dsh-skin-energy-gold\"></span>",
1081
+ "<span class=\"dsh-skin-starfighter dsh-skin-starfighter-1\"></span>",
1082
+ "<span class=\"dsh-skin-starfighter dsh-skin-starfighter-2\"></span>",
1083
+ "<span class=\"dsh-skin-starfighter dsh-skin-starfighter-3\"></span>",
1084
+ "<span class=\"dsh-skin-mission-crawl\"></span>",
1085
+ "<span class=\"dsh-skin-comet dsh-skin-comet-1\"></span>",
1086
+ "<span class=\"dsh-skin-comet dsh-skin-comet-2\"></span>",
1087
+ "<span class=\"dsh-skin-comet dsh-skin-comet-3\"></span>",
1088
+ "<span class=\"dsh-skin-comet dsh-skin-comet-4\"></span>",
1089
+ "<span class=\"dsh-skin-comet dsh-skin-comet-5\"></span>",
1090
+ "<span class=\"dsh-skin-comet dsh-skin-comet-6\"></span>"
1091
+ ].join("");
1092
+
1093
+ function getDecorShadowCss() {
1094
+ return `${CSS
1095
+ .replace(/body\.dsh-skin-galactic-opera\.dsh-skin-galactic-opera-input-active\s+/g, ":host-context(body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-input-active) ")
1096
+ .replace(/body\.dsh-skin-galactic-opera\.dsh-skin-galactic-opera-hyperspace\s+/g, ":host-context(body.dsh-skin-galactic-opera.dsh-skin-galactic-opera-hyperspace) ")
1097
+ .replace(/body\.dsh-skin-galactic-opera\s+/g, "")}
1098
+
1099
+ .dsh-skin-galactic-opera-decor {
1100
+ position: absolute !important;
1101
+ inset: 0 !important;
1102
+ width: auto !important;
1103
+ height: auto !important;
1104
+ z-index: auto !important;
1105
+ }
1106
+ `;
1107
+ }
1108
+
1109
+ function setImportantStyle(element, name, value) {
1110
+ if (element instanceof HTMLElement) element.style.setProperty(name, value, "important");
1111
+ }
1112
+
1113
+ function hardenDecorHost(decor) {
1114
+ setImportantStyle(decor, "position", "fixed");
1115
+ setImportantStyle(decor, "inset", "-2vmax");
1116
+ setImportantStyle(decor, "z-index", "2147483645");
1117
+ setImportantStyle(decor, "pointer-events", "none");
1118
+ setImportantStyle(decor, "overflow", "hidden");
1119
+ setImportantStyle(decor, "mix-blend-mode", "screen");
1120
+ setImportantStyle(decor, "display", "block");
1121
+ setImportantStyle(decor, "width", "auto");
1122
+ setImportantStyle(decor, "height", "auto");
1123
+ setImportantStyle(decor, "border", "0");
1124
+ setImportantStyle(decor, "border-radius", "0");
1125
+ setImportantStyle(decor, "border-top-left-radius", "0");
1126
+ setImportantStyle(decor, "border-top-right-radius", "0");
1127
+ setImportantStyle(decor, "border-bottom-right-radius", "0");
1128
+ setImportantStyle(decor, "border-bottom-left-radius", "0");
1129
+ setImportantStyle(decor, "background", "transparent");
1130
+ }
1131
+
1132
+ function getDecorRoot(decor) {
1133
+ return decor?.shadowRoot ?? decor;
1134
+ }
1135
+
1136
+ function getDecorLayer(decor) {
1137
+ const root = getDecorRoot(decor);
1138
+ return root?.querySelector?.(".dsh-skin-galactic-opera-decor") ?? root;
1139
+ }
1140
+
1141
+ function hardenDecorGeometry(decor) {
1142
+ const root = getDecorRoot(decor);
1143
+ if (root === undefined || root === null) return;
1144
+ const roundSelector = ".dsh-skin-twinkle, .dsh-skin-nebula-core, .dsh-skin-orb, .dsh-skin-scanner, .dsh-skin-scanner-target";
1145
+ for (const element of root.querySelectorAll(roundSelector)) {
1146
+ setImportantStyle(element, "border-radius", "50%");
1147
+ setImportantStyle(element, "overflow", "visible");
1148
+ setImportantStyle(element, "box-sizing", "border-box");
1149
+ }
1150
+ for (const element of root.querySelectorAll(".dsh-skin-energy, .dsh-skin-comet")) {
1151
+ setImportantStyle(element, "border-radius", "999px");
1152
+ setImportantStyle(element, "overflow", "visible");
1153
+ setImportantStyle(element, "box-sizing", "border-box");
1154
+ }
1155
+ }
1156
+
1157
+ function populateDecor(decor) {
1158
+ if (typeof decor.attachShadow === "function") {
1159
+ const shadow = decor.shadowRoot ?? decor.attachShadow({ mode: "open" });
1160
+ shadow.replaceChildren();
1161
+ decor.replaceChildren();
1162
+ const style = document.createElement("style");
1163
+ style.textContent = getDecorShadowCss();
1164
+ const layer = document.createElement("div");
1165
+ layer.className = "dsh-skin-galactic-opera-decor";
1166
+ layer.innerHTML = DECOR_MARKUP;
1167
+ shadow.append(style, layer);
1168
+ } else {
1169
+ decor.innerHTML = DECOR_MARKUP;
1170
+ }
1171
+ hardenDecorGeometry(decor);
1172
+ }
1173
+
1007
1174
  function ensureDecor() {
1008
1175
  if (typeof document === "undefined") return undefined;
1009
1176
  let decor = document.getElementById(DECOR_ID);
1010
- if (decor instanceof HTMLDivElement) return decor;
1177
+ if (decor instanceof HTMLDivElement) {
1178
+ decor.className = DECOR_HOST_CLASS;
1179
+ decor.setAttribute("aria-hidden", "true");
1180
+ decor.dataset.plugin = PLUGIN_ID;
1181
+ hardenDecorHost(decor);
1182
+ populateDecor(decor);
1183
+ return decor;
1184
+ }
1011
1185
  decor = document.createElement("div");
1012
1186
  decor.id = DECOR_ID;
1013
- decor.className = "dsh-skin-galactic-opera-decor";
1187
+ decor.className = DECOR_HOST_CLASS;
1014
1188
  decor.setAttribute("aria-hidden", "true");
1015
1189
  decor.dataset.plugin = PLUGIN_ID;
1016
- decor.innerHTML = [
1017
- "<span class=\"dsh-skin-nebula-core\"></span>",
1018
- "<span class=\"dsh-skin-twinkle dsh-skin-twinkle-a\"></span>",
1019
- "<span class=\"dsh-skin-twinkle dsh-skin-twinkle-b\"></span>",
1020
- "<span class=\"dsh-skin-twinkle dsh-skin-twinkle-c\"></span>",
1021
- "<span class=\"dsh-skin-orb dsh-skin-orb-primary\"></span>",
1022
- "<span class=\"dsh-skin-orb dsh-skin-orb-moon-a\"></span>",
1023
- "<span class=\"dsh-skin-satellite-orbit\"></span>",
1024
- "<span class=\"dsh-skin-satellite-orbit-front\"></span>",
1025
- "<span class=\"dsh-skin-satellite\"></span>",
1026
- "<span class=\"dsh-skin-scanner\"></span>",
1027
- "<span class=\"dsh-skin-scanner-target\"></span>",
1028
- "<span class=\"dsh-skin-route-map\"></span>",
1029
- "<span class=\"dsh-skin-energy dsh-skin-energy-cyan\"></span>",
1030
- "<span class=\"dsh-skin-energy dsh-skin-energy-red\"></span>",
1031
- "<span class=\"dsh-skin-energy dsh-skin-energy-gold\"></span>",
1032
- "<span class=\"dsh-skin-starfighter dsh-skin-starfighter-1\"></span>",
1033
- "<span class=\"dsh-skin-starfighter dsh-skin-starfighter-2\"></span>",
1034
- "<span class=\"dsh-skin-starfighter dsh-skin-starfighter-3\"></span>",
1035
- "<span class=\"dsh-skin-mission-crawl\"></span>",
1036
- "<span class=\"dsh-skin-comet dsh-skin-comet-1\"></span>",
1037
- "<span class=\"dsh-skin-comet dsh-skin-comet-2\"></span>",
1038
- "<span class=\"dsh-skin-comet dsh-skin-comet-3\"></span>",
1039
- "<span class=\"dsh-skin-comet dsh-skin-comet-4\"></span>",
1040
- "<span class=\"dsh-skin-comet dsh-skin-comet-5\"></span>",
1041
- "<span class=\"dsh-skin-comet dsh-skin-comet-6\"></span>"
1042
- ].join("");
1190
+ hardenDecorHost(decor);
1191
+ populateDecor(decor);
1043
1192
  document.body.appendChild(decor);
1044
1193
  return decor;
1045
1194
  }
@@ -1098,20 +1247,32 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1098
1247
  let frame = 0;
1099
1248
  let latestX = window.innerWidth / 2;
1100
1249
  let latestY = window.innerHeight / 2;
1250
+ let lastParallaxX = "";
1251
+ let lastParallaxY = "";
1101
1252
  let pulseIndex = 0;
1102
1253
  let hyperspaceTimer;
1103
1254
  let inputFocusTimer;
1104
1255
  let scannerPingTimer;
1105
1256
  let lastHyperspaceAt = 0;
1106
- const scanner = decor.querySelector(".dsh-skin-scanner");
1107
- const scannerTarget = decor.querySelector(".dsh-skin-scanner-target");
1257
+ const decorRoot = getDecorRoot(decor);
1258
+ const decorLayer = getDecorLayer(decor);
1259
+ const scanner = decorRoot?.querySelector?.(".dsh-skin-scanner");
1260
+ const scannerTarget = decorRoot?.querySelector?.(".dsh-skin-scanner-target");
1108
1261
  const pulseColors = ["rgba(125,227,255,0.94)", "rgba(255,207,92,0.92)", "rgba(255,71,120,0.88)"];
1109
1262
  const updatePointer = () => {
1110
1263
  frame = 0;
1111
1264
  const nx = (latestX / Math.max(1, window.innerWidth) - 0.5) * 2;
1112
1265
  const ny = (latestY / Math.max(1, window.innerHeight) - 0.5) * 2;
1113
- document.body.style.setProperty("--dsh-skin-parallax-x", `${Math.round(nx * -10)}px`);
1114
- document.body.style.setProperty("--dsh-skin-parallax-y", `${Math.round(ny * -8)}px`);
1266
+ const nextParallaxX = `${Math.round(nx * -10)}px`;
1267
+ const nextParallaxY = `${Math.round(ny * -8)}px`;
1268
+ if (nextParallaxX !== lastParallaxX) {
1269
+ lastParallaxX = nextParallaxX;
1270
+ document.body.style.setProperty("--dsh-skin-parallax-x", nextParallaxX);
1271
+ }
1272
+ if (nextParallaxY !== lastParallaxY) {
1273
+ lastParallaxY = nextParallaxY;
1274
+ document.body.style.setProperty("--dsh-skin-parallax-y", nextParallaxY);
1275
+ }
1115
1276
  };
1116
1277
  const pingScannerAt = (clientX, clientY) => {
1117
1278
  if (!(scanner instanceof HTMLElement) || !(scannerTarget instanceof HTMLElement)) return;
@@ -1153,6 +1314,9 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1153
1314
  };
1154
1315
  const onPointerMove = (event) => {
1155
1316
  if (isReducedMotion() || isTypingActive()) return;
1317
+ const dx = event.clientX - latestX;
1318
+ const dy = event.clientY - latestY;
1319
+ if (frame === 0 && dx * dx + dy * dy < 9) return;
1156
1320
  latestX = event.clientX;
1157
1321
  latestY = event.clientY;
1158
1322
  if (frame === 0) frame = requestAnimationFrame(updatePointer);
@@ -1172,11 +1336,14 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1172
1336
  if (isReducedMotion() || isEditableTarget(event.target)) return;
1173
1337
  const pulse = document.createElement("span");
1174
1338
  pulse.className = "dsh-skin-pulse";
1339
+ setImportantStyle(pulse, "border-radius", "50%");
1340
+ setImportantStyle(pulse, "box-sizing", "border-box");
1175
1341
  pulse.style.setProperty("--dsh-skin-pulse-x", `${event.clientX}px`);
1176
1342
  pulse.style.setProperty("--dsh-skin-pulse-y", `${event.clientY}px`);
1177
1343
  pulse.style.setProperty("--dsh-skin-pulse-color", pulseColors[pulseIndex % pulseColors.length]);
1178
1344
  pulseIndex += 1;
1179
- decor.appendChild(pulse);
1345
+ if (decorLayer instanceof Element) decorLayer.appendChild(pulse);
1346
+ else decor.appendChild(pulse);
1180
1347
  const remove = () => { pulse.remove(); };
1181
1348
  pulse.addEventListener("animationend", remove, { once: true });
1182
1349
  window.setTimeout(remove, 900);
@@ -1230,6 +1397,10 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1230
1397
  let currentSources = new Set();
1231
1398
  let lastText = "";
1232
1399
  let frame = 0;
1400
+ let forceTelemetryRescan = true;
1401
+ let telemetryRefreshesSinceFullScan = 0;
1402
+ const TELEMETRY_UPDATE_DELAY = 300;
1403
+ const TELEMETRY_FULL_RESCAN_UPDATES = 7;
1233
1404
  let collapsed = false;
1234
1405
  try {
1235
1406
  collapsed = window.localStorage?.getItem("dsh-skin-galactic-opera:telemetry-collapsed") === "true";
@@ -1242,6 +1413,16 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1242
1413
  panel.hidden = true;
1243
1414
  const content = document.createElement("div");
1244
1415
  content.className = "dsh-skin-telemetry-content";
1416
+ const rowMetrics = Array.from({ length: 5 }, () => {
1417
+ const row = document.createElement("div");
1418
+ row.className = "dsh-skin-telemetry-row";
1419
+ row.hidden = true;
1420
+ const metric = document.createElement("span");
1421
+ metric.className = "dsh-skin-telemetry-value dsh-skin-telemetry-value-full";
1422
+ row.append(metric);
1423
+ content.append(row);
1424
+ return { row, metric };
1425
+ });
1245
1426
  panel.append(content);
1246
1427
  const toggle = document.createElement("button");
1247
1428
  toggle.type = "button";
@@ -1251,23 +1432,33 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1251
1432
  const skinMutationSelector = `#${DECOR_ID}, .dsh-skin-pulse, .dsh-skin-telemetry-panel, .dsh-skin-telemetry-toggle`;
1252
1433
  const isSkippable = (element) => element.closest(skipSelector) !== null;
1253
1434
  const hasEditableDescendant = (element) => element.querySelector(editableDescendantSelector) !== null;
1254
- const getTelemetryText = (element) => (element.innerText || element.textContent || "").replace(/\s+/g, " ").trim();
1435
+ const normalizeTelemetryText = (text) => text.replace(/\s+/g, " ").trim();
1436
+ const getTelemetryProbeText = (element) => normalizeTelemetryText(element.textContent || "");
1437
+ const getTelemetryText = (element) => normalizeTelemetryText(element.innerText || element.textContent || "");
1255
1438
  const getMutationElement = (node) => node instanceof Element ? node : node.parentElement;
1256
1439
  const isSkinOwnedNode = (node) => getMutationElement(node)?.closest(skinMutationSelector) !== null;
1257
1440
  const isSkinOwnedMutation = (mutation) => {
1258
1441
  if (isSkinOwnedNode(mutation.target)) return true;
1259
- const touched = [...mutation.addedNodes, ...mutation.removedNodes];
1260
- return touched.length > 0 && touched.every(isSkinOwnedNode);
1442
+ let touched = false;
1443
+ for (const node of mutation.addedNodes) {
1444
+ touched = true;
1445
+ if (!isSkinOwnedNode(node)) return false;
1446
+ }
1447
+ for (const node of mutation.removedNodes) {
1448
+ touched = true;
1449
+ if (!isSkinOwnedNode(node)) return false;
1450
+ }
1451
+ return touched;
1261
1452
  };
1262
- const scoreCandidate = (element) => {
1263
- if (!(element instanceof HTMLElement) || isSkippable(element) || hasEditableDescendant(element)) return 0;
1453
+ const getCandidateInfo = (element) => {
1454
+ if (!(element instanceof HTMLElement) || isSkippable(element) || hasEditableDescendant(element)) return undefined;
1264
1455
  const rect = element.getBoundingClientRect();
1265
1456
  const compactBottomBar = rect.height <= 46 && rect.width <= window.innerWidth && rect.bottom > window.innerHeight - 150;
1266
- if (rect.width < 12 || rect.height < 8 || (!compactBottomBar && rect.width > Math.min(620, window.innerWidth * 0.72)) || rect.height > 86) return 0;
1267
- if (rect.bottom < window.innerHeight - 170) return 0;
1268
- const text = getTelemetryText(element);
1269
- if (text.length < 2 || text.length > 360 || !telemetryPattern.test(text) || !/\d/.test(text)) return 0;
1270
- if (/设置\s+设置\s+通用设置|Cmd\/Ctrl\+Enter|使用另一行|排队发送|Agent\s+预设/i.test(text)) return 0;
1457
+ if (rect.width < 12 || rect.height < 8 || (!compactBottomBar && rect.width > Math.min(620, window.innerWidth * 0.72)) || rect.height > 86) return undefined;
1458
+ if (rect.bottom < window.innerHeight - 170) return undefined;
1459
+ const text = getTelemetryProbeText(element);
1460
+ if (text.length < 2 || text.length > 360 || !telemetryPattern.test(text) || !/\d/.test(text)) return undefined;
1461
+ if (/设置\s+设置\s+通用设置|Cmd\/Ctrl\+Enter|使用另一行|排队发送|Agent\s+预设/i.test(text)) return undefined;
1271
1462
  let score = compactBottomBar ? 4 : 1;
1272
1463
  if (rect.bottom > window.innerHeight - 72) score += 3;
1273
1464
  if (rect.right > window.innerWidth * 0.45) score += 1;
@@ -1275,39 +1466,41 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1275
1466
  if (/调用|消耗|上下文|usage|context|缓存|命中|输入|输出/i.test(text)) score += 2;
1276
1467
  if (/轮次|轮|步骤|步数|步|steps?|rounds?|turns?/i.test(text)) score += 2;
1277
1468
  if (/[·•|;;]/.test(text)) score += 2;
1278
- return score;
1469
+ return { element, rect, score, text };
1279
1470
  };
1280
1471
  const chooseTelemetryElements = () => {
1281
1472
  const xs = [0.10, 0.22, 0.34, 0.46, 0.58, 0.70, 0.82, 0.94];
1282
1473
  const ys = [18, 38, 62, 90, 122, 150];
1283
1474
  const candidates = new Map();
1284
- for (const xRatio of xs) for (const yOffset of ys) {
1285
- const x = window.innerWidth * xRatio;
1286
- const y = window.innerHeight - yOffset;
1287
- if (y < 0) continue;
1288
- for (const base of document.elementsFromPoint(x, y)) {
1289
- let element = base;
1290
- for (let depth = 0; element instanceof HTMLElement && depth < 8; depth += 1, element = element.parentElement) {
1291
- const score = scoreCandidate(element);
1292
- if (score > 0) candidates.set(element, Math.max(candidates.get(element) ?? 0, score));
1475
+ const temporarilyRestoredSources = [...currentSources].filter((source) => source.classList.contains("dsh-skin-telemetry-source-hidden"));
1476
+ // elementsFromPoint ignores pointer-events:none. Temporarily restore the previous source
1477
+ // during the same JS task so full rescans do not miss the hidden native bottom bar.
1478
+ for (const source of temporarilyRestoredSources) source.classList.remove("dsh-skin-telemetry-source-hidden");
1479
+ try {
1480
+ for (const xRatio of xs) for (const yOffset of ys) {
1481
+ const x = window.innerWidth * xRatio;
1482
+ const y = window.innerHeight - yOffset;
1483
+ if (y < 0) continue;
1484
+ for (const base of document.elementsFromPoint(x, y)) {
1485
+ let element = base;
1486
+ for (let depth = 0; element instanceof HTMLElement && depth < 8; depth += 1, element = element.parentElement) {
1487
+ const candidate = getCandidateInfo(element);
1488
+ if (candidate !== undefined) {
1489
+ const previous = candidates.get(element);
1490
+ if (previous === undefined || candidate.score > previous.score) candidates.set(element, candidate);
1491
+ }
1492
+ }
1293
1493
  }
1294
1494
  }
1495
+ } finally {
1496
+ for (const source of temporarilyRestoredSources) if (source.isConnected) source.classList.add("dsh-skin-telemetry-source-hidden");
1295
1497
  }
1296
- return [...candidates]
1297
- .sort(([a, aScore], [b, bScore]) => {
1298
- if (bScore !== aScore) return bScore - aScore;
1299
- const ar = a.getBoundingClientRect();
1300
- const br = b.getBoundingClientRect();
1301
- return ar.top - br.top || ar.left - br.left;
1302
- })
1303
- .filter(([element], index, entries) => !entries.slice(0, index).some(([selected]) => selected.contains(element) || element.contains(selected)))
1498
+ return [...candidates.values()]
1499
+ .sort((a, b) => b.score - a.score || a.rect.top - b.rect.top || a.rect.left - b.rect.left)
1500
+ .filter((candidate, index, entries) => !entries.slice(0, index).some(({ element: selected }) => selected.contains(candidate.element) || candidate.element.contains(selected)))
1304
1501
  .slice(0, 10)
1305
- .map(([element]) => element)
1306
- .sort((a, b) => {
1307
- const ar = a.getBoundingClientRect();
1308
- const br = b.getBoundingClientRect();
1309
- return ar.top - br.top || ar.left - br.left;
1310
- });
1502
+ .sort((a, b) => a.rect.top - b.rect.top || a.rect.left - b.rect.left)
1503
+ .map(({ element }) => element);
1311
1504
  };
1312
1505
  const splitTelemetryRows = (text) => {
1313
1506
  const normalized = text
@@ -1406,22 +1599,18 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1406
1599
  const rows = splitTelemetryRows(telemetryText);
1407
1600
  panel.hidden = rows.length === 0;
1408
1601
  toggle.hidden = rows.length === 0;
1409
- content.replaceChildren(...rows.map((rowText) => {
1410
- const row = document.createElement("div");
1411
- row.className = "dsh-skin-telemetry-row";
1412
- const metric = document.createElement("span");
1413
- metric.className = "dsh-skin-telemetry-value dsh-skin-telemetry-value-full";
1414
- metric.textContent = rowText;
1415
- row.append(metric);
1416
- return row;
1417
- }));
1602
+ rowMetrics.forEach(({ row, metric }, index) => {
1603
+ const rowText = rows[index] ?? "";
1604
+ row.hidden = rowText === "";
1605
+ if (metric.textContent !== rowText) metric.textContent = rowText;
1606
+ });
1418
1607
  };
1419
1608
  const isTelemetryPaused = () => document.activeElement instanceof Element && isInstructionInputTarget(document.activeElement);
1420
1609
  const getSourcesText = (sources) => [...sources].map(getTelemetryText).filter(Boolean).join(" | ");
1421
1610
  const areCachedSourcesUsable = () => {
1422
1611
  if (currentSources.size === 0) return false;
1423
1612
  const sources = [...currentSources];
1424
- if (!sources.every((source) => source.isConnected && scoreCandidate(source) > 0)) return false;
1613
+ if (!sources.every((source) => source.isConnected && getCandidateInfo(source) !== undefined)) return false;
1425
1614
  return splitTelemetryRows(getSourcesText(currentSources)).length > 0;
1426
1615
  };
1427
1616
  const update = () => {
@@ -1429,12 +1618,17 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1429
1618
  if (isTelemetryPaused()) return;
1430
1619
  let nextSources = currentSources;
1431
1620
  let text = getSourcesText(nextSources);
1432
- if (!areCachedSourcesUsable()) {
1621
+ const needsFullScan = forceTelemetryRescan || telemetryRefreshesSinceFullScan >= TELEMETRY_FULL_RESCAN_UPDATES || !areCachedSourcesUsable();
1622
+ if (needsFullScan) {
1433
1623
  nextSources = new Set(chooseTelemetryElements());
1434
1624
  text = getSourcesText(nextSources);
1435
1625
  for (const source of currentSources) if (!nextSources.has(source)) source.classList.remove("dsh-skin-telemetry-source-hidden");
1436
1626
  for (const source of nextSources) if (!currentSources.has(source)) source.classList.add("dsh-skin-telemetry-source-hidden");
1437
1627
  currentSources = nextSources;
1628
+ forceTelemetryRescan = false;
1629
+ telemetryRefreshesSinceFullScan = 0;
1630
+ } else {
1631
+ telemetryRefreshesSinceFullScan += 1;
1438
1632
  }
1439
1633
  if (text === lastText) return;
1440
1634
  lastText = text;
@@ -1442,7 +1636,7 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1442
1636
  };
1443
1637
  const schedule = () => {
1444
1638
  if (isTelemetryPaused()) return;
1445
- if (frame === 0) frame = window.setTimeout(update, 180);
1639
+ if (frame === 0) frame = window.setTimeout(update, TELEMETRY_UPDATE_DELAY);
1446
1640
  };
1447
1641
  const onTelemetryFocusIn = (event) => {
1448
1642
  if (!isInstructionInputTarget(event.target)) return;
@@ -1454,18 +1648,22 @@ body.dsh-skin-galactic-opera .dsh-skin-telemetry-value-full {
1454
1648
  const onTelemetryFocusOut = (event) => {
1455
1649
  if (isInstructionInputTarget(event.target)) window.setTimeout(schedule, 240);
1456
1650
  };
1651
+ const onTelemetryResize = () => {
1652
+ forceTelemetryRescan = true;
1653
+ schedule();
1654
+ };
1457
1655
  const observer = typeof MutationObserver === "undefined" ? undefined : new MutationObserver((mutations) => {
1458
1656
  if (mutations.every(isSkinOwnedMutation)) return;
1459
1657
  schedule();
1460
1658
  });
1461
1659
  schedule();
1462
1660
  observer?.observe(document.body, { childList: true, subtree: true, characterData: true });
1463
- window.addEventListener("resize", schedule, { passive: true });
1661
+ window.addEventListener("resize", onTelemetryResize, { passive: true });
1464
1662
  document.addEventListener("focusin", onTelemetryFocusIn);
1465
1663
  document.addEventListener("focusout", onTelemetryFocusOut);
1466
1664
  return () => {
1467
1665
  observer?.disconnect();
1468
- window.removeEventListener("resize", schedule);
1666
+ window.removeEventListener("resize", onTelemetryResize);
1469
1667
  document.removeEventListener("focusin", onTelemetryFocusIn);
1470
1668
  document.removeEventListener("focusout", onTelemetryFocusOut);
1471
1669
  if (frame !== 0) window.clearTimeout(frame);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-skin-galactic-opera",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Unofficial cinematic space-opera dark skin bundle for the DSH Web GUI.",
5
5
  "repository": {
6
6
  "type": "git",