soulsync/tests/test_reduce_effects_css.py
BoulderBadgeDad 3207310448 reduce-effects: kill expensive GPU properties, stop freezing functional motion
"Reduce visual effects" was a sledgehammer: body.reduce-effects * forced
animation:none + transition-duration:0s on every element. That froze every CSS loading
spinner mid-rotation — including the dash-header worker-service spinners (musicbrainz /
spotify / deezer / … .active .<svc>-spinner) — which read as BROKEN rather than "off".
It also killed cheap hover feedback like the Quick Actions buttons.

The actual lag (esp. Firefox, see the #935 sweep) is backdrop-filter / box-shadow /
filter re-rasterizing every frame — NOT the animations themselves. Transform- and
opacity-only motion (the spinners) composites for ~free.

So: keep forcing the expensive properties to none (unchanged — that's the real fix),
but drop the blanket animation/transition kills. !important author declarations outrank
animation + transition declarations in the cascade, so any keyframe/transition that
tries to set blur/shadow/filter is still neutralized even while it runs — the spinner
spins, just without the glow. Net: functional spinners stay alive, Quick Actions hover
(transform + border-colour) returns, box-shadow transitions are no-ops (shadow forced
none), and the GPU-heavy rendering that caused the lag stays gone. The worker-orb CANVAS
is unaffected (JS-gated separately) and stays off under reduce-effects, as intended.

Static guard test pins the contract: the global rule must keep the expensive-property
kills and must NOT reintroduce blanket animation:none / transition:0s.
2026-06-28 16:22:10 -07:00

39 lines
1.7 KiB
Python

"""Guard the reduce-visual-effects CSS contract.
Performance mode must kill the GPU-EXPENSIVE properties (backdrop-filter / box-shadow
/ filter — the real lag, esp. on Firefox) but must NOT blanket-freeze animations:
`animation: none` on every element stuck the dash-header worker-service spinners
mid-rotation, which read as "broken" (Discord/Boulder). Pins the surgical rule so a
future edit can't silently re-freeze the functional spinners or kill cheap hover
feedback."""
import re
from pathlib import Path
_STYLE = Path(__file__).resolve().parent.parent / "webui" / "static" / "style.css"
def _reduce_effects_global_body() -> str:
css = _STYLE.read_text(encoding="utf-8")
m = re.search(r"body\.reduce-effects \*,.*?\{([^}]*)\}", css, re.DOTALL)
assert m, "global 'body.reduce-effects *' rule not found"
return m.group(1)
def test_reduce_effects_still_kills_expensive_gpu_properties():
body = _reduce_effects_global_body()
for prop in ("backdrop-filter: none", "box-shadow: none", "filter: none"):
assert prop in body, f"reduce-effects must still force {prop} (the real lag source)"
def test_reduce_effects_does_not_blanket_freeze_animations():
body = _reduce_effects_global_body()
# `animation: none` on * froze the dash-header worker-service spinners mid-spin;
# cheap transform/opacity motion must survive so a spinner still reads as "working".
assert "animation: none" not in body, (
"blanket 'animation: none' re-freezes the worker spinners — keep motion alive, "
"the expensive properties are already neutralized above"
)
assert "transition-duration: 0s" not in body, (
"blanket 'transition-duration: 0s' kills the cheap Quick Actions hover feedback"
)