fix(css): scope data-app-blurred animation pause away from * (#434)

* fix(css): scope data-app-blurred animation pause away from `*`

The `data-app-blurred="true"` rule used a `*` selector to pause every
animation while the window was unfocused. On WebKitGTK + no-compositing
(Linux dev mode) this triggered a stale rendering bug after Vite HMR
reloads — the sidebar and main content stayed invisible until any user
interaction nudged a re-render.

Splitting the rule:

* `data-app-hidden` and `data-psy-native-hidden` keep `*` because the
  window is fully invisible to the user in those states.
* `data-app-blurred` now lists only the concrete heaviest infinite
  animations (eq bars, marquees, np dot pulse, fullscreen mesh blob /
  portrait, generic spin). The other small animations keep running
  while blurred — minor GPU cost compared to the broken HMR experience.

The JS-side `__psyBlurred` flag in WaveformSeek is unchanged.

* docs(changelog): add #434 entry to [1.45.0] / Fixed
This commit is contained in:
Frank Stellmacher
2026-05-02 23:20:01 +02:00
committed by GitHub
parent e6a20f03cd
commit 402e288a24
2 changed files with 20 additions and 4 deletions
+2
View File
@@ -141,6 +141,8 @@ The currently playing row in the queue list is now indicated by **animated equal
- **Windows playback stutter under GPU load** *(Issue [#334](https://github.com/Psychotoxical/psysonic/issues/334), PR [#426](https://github.com/Psychotoxical/psysonic/pull/426), by [@Psychotoxical](https://github.com/Psychotoxical))*: Audio could stutter and crackle on Windows whenever another app put GPU/CPU pressure on the system (browser, 3D apps, games). The WASAPI render thread is now promoted to MMCSS "Pro Audio" via `AvSetMmThreadCharacteristicsW`, so it survives priority contention from competing graphics work. Reproed and validated under a Half-Life parallel-load stresstest. Companion mitigations for high-GPU situations: cosmetic UI animations now pause when the window loses OS focus, and a new **Reduce animations** toggle in **Settings → Appearance** caps animated seekbar styles (pulsewave, particletrail, liquidfill, retrotape) to 30 fps for users on GPU-constrained machines (off by default). - **Windows playback stutter under GPU load** *(Issue [#334](https://github.com/Psychotoxical/psysonic/issues/334), PR [#426](https://github.com/Psychotoxical/psysonic/pull/426), by [@Psychotoxical](https://github.com/Psychotoxical))*: Audio could stutter and crackle on Windows whenever another app put GPU/CPU pressure on the system (browser, 3D apps, games). The WASAPI render thread is now promoted to MMCSS "Pro Audio" via `AvSetMmThreadCharacteristicsW`, so it survives priority contention from competing graphics work. Reproed and validated under a Half-Life parallel-load stresstest. Companion mitigations for high-GPU situations: cosmetic UI animations now pause when the window loses OS focus, and a new **Reduce animations** toggle in **Settings → Appearance** caps animated seekbar styles (pulsewave, particletrail, liquidfill, retrotape) to 30 fps for users on GPU-constrained machines (off by default).
- **Linux dev — sidebar and main content invisible after HMR** *(PR [#434](https://github.com/Psychotoxical/psysonic/pull/434), by [@Psychotoxical](https://github.com/Psychotoxical))*: The `data-app-blurred="true"` CSS rule introduced in #426 used a `*` selector to pause every animation while the window was unfocused. On WebKitGTK + no-compositing this triggered a stale rendering bug after Vite hot-reloads — the sidebar and main content stayed unpainted until any user interaction nudged a re-render. The rule now targets only the concrete heaviest infinite animations (eq bars, marquees, now-playing dot pulse, fullscreen mesh blob / portrait, `.spin`); release builds are unchanged in behaviour.
## [1.44.0] - 2026-04-29 ## [1.44.0] - 2026-04-29
+18 -4
View File
@@ -11097,15 +11097,29 @@ html.no-compositing .fs-seekbar-played {
background: var(--accent); background: var(--accent);
} }
/* Window completely invisible (tab hidden via Visibility API, or Tauri
`win.hide()`): pausing every animation is safe because the user is not
looking. */
html[data-app-hidden="true"] *, html[data-app-hidden="true"] *,
html[data-app-hidden="true"] *::before, html[data-app-hidden="true"] *::before,
html[data-app-hidden="true"] *::after, html[data-app-hidden="true"] *::after,
html[data-psy-native-hidden="true"] *, html[data-psy-native-hidden="true"] *,
html[data-psy-native-hidden="true"] *::before, html[data-psy-native-hidden="true"] *::before,
html[data-psy-native-hidden="true"] *::after, html[data-psy-native-hidden="true"] *::after {
html[data-app-blurred="true"] *, animation-play-state: paused !important;
html[data-app-blurred="true"] *::before, }
html[data-app-blurred="true"] *::after {
/* Window visible but unfocused (alt-tab, click into another app): only
pause the heaviest known infinite animations to save GPU. The previous
`*`-selector variant fired a repaint over every node and triggered a
stale-blur HMR rendering bug on WebKitGTK + no-compositing. */
html[data-app-blurred="true"] .eq-bars .eq-bar,
html[data-app-blurred="true"] .player-marquee,
html[data-app-blurred="true"] .marquee-text,
html[data-app-blurred="true"] .np-dot-pulse,
html[data-app-blurred="true"] .fs-mesh-blob,
html[data-app-blurred="true"] .fs-portrait-wrap,
html[data-app-blurred="true"] .spin {
animation-play-state: paused !important; animation-play-state: paused !important;
} }