v0.55.0: Kaleidostrobe smooth again; visualizer tile hover controls

The cones move only on the plugin's own 25 fps frames again: driving them
from fresh audio every refresh made bass-heavy songs twitch (a jump on 84%
of refreshes against 41%). The continuous turn, texture crossfade and the
GPU big window stay.

The tile: a click opens it big (and it stays blank while big); hovering
shows a colour wheel (colour / gray / off) and up/down arrows (previous /
next visualizer). No more double-click or click-to-cycle. The big album
art closes on a click or Esc, like the big visualizer.
This commit is contained in:
2026-10-14 12:51:38 -07:00
parent 7ae55e757a
commit 00aa5e7f2e
14 changed files with 414 additions and 95 deletions
+12 -5
View File
@@ -186,6 +186,12 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
share of the width. Since the Library button left the
sidebar, `MainWindow` must hand it the first focus, or the playlist tree
takes it and opens its first playlist at startup.
The transport-bar visualizer tile (`gui/visualizer.py`, Round 86): a
click opens it big, and while big the tile stays blank; hovering paints
two controls over it — a colour wheel (left: colour / gray / off) and ▲/▼
(right: previous/next style, wrapping) — hit-tested on release. No
double-click. Both big windows (visualizer, album art) close on a click
or Esc.
`track_table.py` is the shared track grid (drag/drop, copy/paste, drop
indicator). `playlist_ops.py::add_tracks_with_dup_check` is the single funnel
for every add-to-playlist path. `theme.py` applies the palette (highlight
@@ -281,11 +287,12 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
scale was never published, so `itunes_spectrum` (√magnitude, 43 Hz bins)
is the one calibrated stand-in. **On screen it is 60 fps anyway**
(Round 85): between the 25 Hz frames `_compose` turns the cones by a
fraction of a frame, crossfades the textures, and takes height/depth from
`engine.preview` — the plugin's analysis run on a throwaway copy with the
newest audio, so a beat pumps the cone one refresh later, not one 40 ms
tick later. `preview` must never touch real state (a golden test
interleaves it). Painting: the panel uses QPainter — each GL triangle is
fraction of a frame and crossfades the textures — smoothing only. The
cones' height/depth change **only on the plugin's frames**: Round 85 also
drove them from the newest audio every refresh (snappier beats), and on
bass-heavy songs it twitched — a jump on 84% of refreshes against 41% —
so Round 86 took it out. The 25 fps cap was hiding that jitter; don't
reintroduce fresh-audio geometry between frames. Painting: the panel uses QPainter — each GL triangle is
planar, drawn in texture space through a projective **world** transform
(Qt mis-draws a strongly projective *brush* transform). The **big window
replays the original's GL calls** (`paint_gl` in a `gui/kaleido_gl.py`