Loop art zoom back-and-forth instead of one-shot reveal, to reduce refresh jumpiness

This commit is contained in:
poprhythm committed 2026-09-29 15:21:52 -04:00
1 parent 27e29705c9
commit 83b817c3b2
2 files changed
+57 -21

No files matched your search

+30 -14
View File
@@ -86,20 +86,31 @@ def main(config):
return render.Root(child = content)
# Album art gets a slow "Ken Burns" reveal: starts zoomed into one corner,
# eases out to the full frame over ~1 minute. Art is rendered oversized
# (45x45, vs. the 32x32 display slot) since animation.Scale above 1.0 has no
# visible effect on a widget whose declared size already matches its
# container (confirmed elsewhere this session) -- starting at native 1.0
# scale of the *oversized* image and easing down to ~32/45 achieves the
# "zoom out to reveal everything" effect while only ever using Scale <= 1.0.
# Combining Scale + Translate in one Transformation, and combining that with
# the app's 4 already-scrolling Marquee lines, was verified not to trigger
# any *additional* glitching beyond the already-accepted minor Marquee quirk
# (see README). Duration 1200 ticks x the default 50ms/tick = 60s; verified
# Album art gets a slow "Ken Burns" breathing effect: eases from one corner
# out to the full frame, then back into that same corner, on a continuous
# loop -- not a one-shot reveal. A one-shot version (start in a corner, 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 into a corner" 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.
#
# Art is rendered oversized (45x45, vs. the 32x32 display slot) since
# animation.Scale above 1.0 has no visible effect on a widget whose declared
# size already matches its container (confirmed elsewhere this session) --
# starting at native 1.0 scale of the *oversized* image and easing down to
# ~32/45 achieves "zoom out to reveal everything" while only ever using
# Scale <= 1.0. Combining Scale + Translate in one Transformation, and
# combining that with the app's 4 already-scrolling Marquee lines, was
# verified not to trigger any *additional* glitching beyond the already-
# accepted minor Marquee quirk (see README). Duration 1200 ticks x the
# default 50ms/tick = 60s round-trip (30s out, 30s back); verified
# empirically that a slower zoom compresses *smaller*, not larger, since more
# adjacent ticks become pixel-identical at this resolution -- ~97KB alone,
# ~117KB combined with the full app, both far under the 460KB device limit.
# adjacent ticks become pixel-identical at this resolution -- ~97-264KB
# depending on the art's own complexity, well under the 460KB device limit.
ART_SIZE = 45
ART_SLOT = 32
ART_MAX_OFFSET = (ART_SIZE - ART_SLOT) / 2.0 # 6.5px: centered -> true corner
@@ -134,10 +145,15 @@ def _art_widget(art_bytes, subsonic_id):
transforms = [animation.Scale(1.0, 1.0), animation.Translate(corner_x, corner_y)],
),
animation.Keyframe(
percentage = 1.0,
percentage = 0.5,
transforms = [animation.Scale(ART_END_SCALE, ART_END_SCALE), animation.Translate(0, 0)],
curve = "ease_in_out",
),
animation.Keyframe(
percentage = 1.0,
transforms = [animation.Scale(1.0, 1.0), animation.Translate(corner_x, corner_y)],
curve = "ease_in_out",
),
],
)
return render.Box(width = ART_SLOT, height = ART_SLOT, child = zoom)
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.