Revert centered zoom; Scale+Translate causes a periodic rendering pop
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.
This commit is contained in:
1 parent
5f42319e26
commit
9f63adbfbf
3 files changed
+79
-77
No files matched your search
+17
-29
@@ -91,16 +91,12 @@ COLOR_SCHEMES = {
|
||||
DEFAULT_COLOR_SCHEME = "cyberpunk" # matches the station's own site theme
|
||||
|
||||
# How far in the album art zoom goes, relative to its fully-zoomed-out rest
|
||||
# state (see _art_widget below for why scale never goes below 1.0). "strong"
|
||||
# is capped at 1.45, not pushed further: with the centering Translate in
|
||||
# _art_widget, empirically anything above ~1.46 starts revealing a real
|
||||
# black border in the bottom-right corner (verified with the calibration
|
||||
# tool) -- this is the safe ceiling, not an arbitrary choice.
|
||||
# state (see _art_widget below for why scale never goes below 1.0).
|
||||
ZOOM_LEVELS = {
|
||||
"off": 1.0,
|
||||
"subtle": 1.15,
|
||||
"moderate": 1.4,
|
||||
"strong": 1.45,
|
||||
"strong": 1.7,
|
||||
}
|
||||
DEFAULT_ZOOM_LEVEL = "moderate"
|
||||
|
||||
@@ -229,43 +225,35 @@ def _art_widget(art_bytes, zoom_scale):
|
||||
# state and the rest state of every zoom level line up exactly.
|
||||
#
|
||||
# animation.Scale's pivot is fixed at the top-left corner (confirmed
|
||||
# empirically; an explicit `origin` param has no effect at all). Left
|
||||
# alone, that means zooming in crops progressively *more* off the
|
||||
# bottom and right than the top and left -- most of the animation's
|
||||
# duration is spent between keyframes, not sitting at the symmetric
|
||||
# rest state, so this read as a persistent bottom/right crop. Pairing
|
||||
# Scale with a Translate re-centers the zoom so it crops evenly from
|
||||
# all sides instead -- verified against a calibration grid image.
|
||||
#
|
||||
# shift = (1-s)*(ART_SIZE/2) is linear in the scale value, which keeps
|
||||
# it moving smoothly in lockstep with Scale's own eased interpolation
|
||||
# throughout the animation. A tempting "fix" for a black-border bug at
|
||||
# strong zoom was dividing this by `top_scale` to pull the shift in at
|
||||
# high scale values -- that avoided the border, but made the shift a
|
||||
# *nonlinear* function of the scale being interpolated, so partway
|
||||
# through the animation the pan no longer tracked the zoom at a
|
||||
# constant rate -- visibly jerky. Reverted: instead, ZOOM_LEVELS caps
|
||||
# "strong" at a value where this plain linear formula is already safe
|
||||
# (verified via the calibration tool), rather than changing the
|
||||
# formula's shape.
|
||||
# empirically; an explicit `origin` param has no effect at all). That
|
||||
# means zooming in crops progressively more off the bottom and right
|
||||
# than the top and left -- a real cosmetic asymmetry. Pairing Scale
|
||||
# with a Translate to re-center it was tried (and visually worked),
|
||||
# but introduced a worse problem: combining Scale + Translate causes
|
||||
# pixlet to periodically re-rasterize the whole image with a visible
|
||||
# "pop" (confirmed with both WebP and GIF output, and independent of
|
||||
# zoom amplitude -- so it's pixlet's animation engine, not this app's
|
||||
# math). Scale *alone*, with no Translate at all, has none of that
|
||||
# popping. Given the choice between a subtle, constant crop asymmetry
|
||||
# and a periodic visible pop, the asymmetry is the lesser issue, so
|
||||
# this uses Scale only.
|
||||
top_scale = max(zoom_scale, 1.0)
|
||||
shift = (1.0 - top_scale) * (ART_SIZE / 2.0)
|
||||
zoom = animation.Transformation(
|
||||
child = art,
|
||||
duration = ART_ZOOM_DURATION,
|
||||
keyframes = [
|
||||
animation.Keyframe(
|
||||
percentage = 0.0,
|
||||
transforms = [animation.Scale(1.0, 1.0), animation.Translate(0, 0)],
|
||||
transforms = [animation.Scale(1.0, 1.0)],
|
||||
),
|
||||
animation.Keyframe(
|
||||
percentage = 0.5,
|
||||
transforms = [animation.Scale(top_scale, top_scale), animation.Translate(shift, shift)],
|
||||
transforms = [animation.Scale(top_scale, top_scale)],
|
||||
curve = "ease_in_out",
|
||||
),
|
||||
animation.Keyframe(
|
||||
percentage = 1.0,
|
||||
transforms = [animation.Scale(1.0, 1.0), animation.Translate(0, 0)],
|
||||
transforms = [animation.Scale(1.0, 1.0)],
|
||||
curve = "ease_in_out",
|
||||
),
|
||||
],
|
||||
|
||||