diff --git a/subwave_nowplaying.star b/subwave_nowplaying.star index ce873e3..1a055d6 100644 --- a/subwave_nowplaying.star +++ b/subwave_nowplaying.star @@ -87,17 +87,22 @@ def main(config): return render.Root(child = content) # Album art gets a slow "Ken Burns" breathing effect: eases from the full -# frame in to a zoomed-in crop of the top-left corner, then back out, on a -# continuous loop -- not a one-shot reveal. A one-shot version (start -# zoomed in, end on the full frame, then hold) looked jumpy: since the app -# re-renders on NOWPLAYING_TTL and each fresh render restarts its own -# animation from tick 0, whatever the *previous* pushed image happened to -# be showing at that moment gets abruptly replaced by a fresh zoomed-in -# frame. The back-and-forth loop doesn't eliminate that (a server-side -# re-render always restarts at tick 0 regardless), but ending exactly where -# it started means the animation also loops seamlessly on-device between -# refreshes, which in practice reads as far less jarring than a one-way -# reveal that snaps back. +# frame in to a zoomed-in crop, then back out, on a continuous loop -- not +# a one-shot reveal. A one-shot version (start zoomed in, end on the full +# frame, then hold) looked jumpy: since the app re-renders on NOWPLAYING_TTL +# and each fresh render restarts its own animation from tick 0, whatever the +# *previous* pushed image happened to be showing at that moment gets +# abruptly replaced by a fresh zoomed-in frame. The back-and-forth loop +# doesn't eliminate that (a server-side re-render always restarts at tick 0 +# regardless), but ending exactly where it started means the animation also +# loops seamlessly on-device between refreshes. +# +# Duration is intentionally short (a handful of seconds each way), not the +# ~60s round-trip originally tried: on the real device/server, a fresh +# render replaces the still-playing animation well before a minute-long +# cycle can complete, so only the outbound half (zoom out) was ever visible +# and it never appeared to "zoom back in". A short loop guarantees at least +# one full out-and-back cycle plays before that happens. # # Art is rendered oversized (45x45, vs. the 32x32 display slot) since # animation.Scale has no visible effect on a widget whose declared size @@ -110,18 +115,11 @@ def main(config): # animation.Scale(1.0, 1.0) -- so scaling *down* from there shrinks the # already-fitted image further, exposing background outside its bounds # (the black border). Scaling *up* only ever crops further into the image, -# which is always safe. animation.Scale's pivot defaults to the top-left -# corner (confirmed empirically; an explicit `origin` param had no effect -# at all, so isn't used here) -- there's no reliable way to zoom into any -# other corner, so this always zooms into the top-left. Duration 1200 -# ticks x the default 50ms/tick = 60s round-trip (30s in, 30s out); -# verified empirically that a slower zoom compresses *smaller*, not -# larger, since more adjacent ticks become pixel-identical at this -# resolution -- well under the 460KB device limit. +# which is always safe. ART_SIZE = 45 ART_SLOT = 32 -ART_ZOOM_SCALE = 1.4 # how far in to zoom on the top-left corner -ART_ZOOM_DURATION = 1200 # 60s at the default 50ms/tick +ART_ZOOM_SCALE = 1.4 # how far in to zoom +ART_ZOOM_DURATION = 200 # 10s round-trip (5s in, 5s out) at the default 50ms/tick def _art_widget(art_bytes): art = render.Image(src = art_bytes, width = ART_SIZE, height = ART_SIZE)