Combining animation.Scale with animation.Translate to center the zoom
(two commits back) visually fixed the top-left crop bias, but introduced
a worse problem: pixlet periodically re-rasterizes the whole image with a
visible "pop" roughly every 0.7-1s, confirmed with both WebP and GIF
output and independent of zoom amplitude -- a property of pixlet's
animation engine when Scale and Translate are combined, not something
fixable from this app's math. Scale alone, with no Translate, has none of
this popping (confirmed via isolated testing).
Reverted _art_widget to Scale-only (as it was before centering), and
restored ZOOM_LEVELS["strong"] to 1.7 (the strong-zoom black border only
applied to the Translate-based centering, not plain Scale). This brings
back the original top-left crop bias as a known, accepted cosmetic
trade-off -- better than a periodic visible pop. Updated the README and
dev/calibration_test.star to match and documented the full history for
anyone who wants to revisit centering later.
dev/calibration.png is a synthetic grid (concentric color rings, corner
markers, a crosshair) and dev/calibration_test.star runs it through the
same zoom logic as the real _art_widget, so cropping can be checked
visually without depending on what a live station happens to be playing.
This is what was used to find and verify the centered-zoom fix.
Zoom level is a dropdown (Off/Subtle/Moderate/Strong) controlling how far
the album art zooms in during its breathing effect; Off skips the
animation.Transformation entirely and just shows a static crop.
Color schemes now match SUB/WAVE's own web UI theme picker (Blueprint,
Classic Dark, Classic Light, Cyberpunk, Flare, Recon, Signal, Vinyl) so a
station can mirror its own site theme on the device, including a
background fill that was previously hardcoded to black.
The corner-reveal zoom scaled down from 1.0 toward ~0.71 (via Translate
to shift toward a corner), which showed up on a real device as a black
border cutting into the art. Empirical testing against the actual Row
layout at native canvas size showed the outer Box auto-fits an oversized
child at Scale(1.0, 1.0), so scaling down from there shrinks the already-
fitted image further and exposes background outside its bounds. Scaling
up only ever crops further into the image, which is always safe.
This drops Translate and the per-track corner selection (animation.Scale
pivots at the top-left corner by default with no way to change it -- an
explicit origin parameter was tried and had no effect), so the effect now
always zooms into the top-left corner instead of a track-dependent one.