Fix scanlines going blank instead of regenerating; reduce count; animate sweep
Reduced visible scanlines from 8 to 6 per window (dropping the last two of the 8 evenly-spaced SCANLINE_PERIOD positions, rather than changing the period itself, so it keeps dividing evenly into ART_SLOT). Also animated the scanlines to sweep downward (previously static), matching SUB/WAVE's own continuously-animated scanlines. A first attempt built a buffer twice the art slot's height, pre-shifted with a negative render.Padding so the middle 32 rows lined up with the window at rest, then swept the full ART_SLOT distance in one pass. That's what produced "scanlines disappearing at the bottom without regenerating at the top": empirically, negative Padding didn't behave like the (well-proven elsewhere in this file) positive case, which reliably grows a widget's size -- confirmed via an isolated test that it went blank partway through a static sweep instead of revealing new rows. Replaced with a repeating sawtooth instead of one big sweep: the buffer is only one extra SCANLINE_PERIOD taller than the art slot (the same small, already-proven-safe oversized margin used throughout this file, e.g. the zoom's own ART_SIZE vs. ART_SLOT), and the animation ramps down by exactly one period, snaps back to 0, and repeats -- since the pattern repeats every period anyway, the snap is invisible (a standard infinite- scrolling-texture trick), and the translate distance never leaves the confirmed-safe small range. Verified via an isolated test (translating a plain Column child by small amounts, mirroring the technique already used for the zoom/jitter) before building this in, and via the real render: no black border across all 125 frames of a real render, payload well under budget (193KB).
This commit is contained in:
1 parent
29b0505dc7
commit
ef38fabebb
1 file changed
+53
-9
+53
-9
@@ -522,20 +522,64 @@ def _glitch_jitter(zoom):
|
||||
jittered = animation.Transformation(child = zoom, duration = total_ticks, keyframes = keyframes)
|
||||
return render.Box(width = ART_SLOT, height = ART_SLOT, child = jittered)
|
||||
|
||||
SCANLINE_PERIOD = 4 # 1px line, 3px gap
|
||||
SCANLINE_SWEEP_DURATION = 160 # 8s total at the default 50ms/tick
|
||||
SCANLINE_CYCLES = 8 # how many times the sawtooth below repeats over that
|
||||
_SCANLINE_CYCLE_TICKS = SCANLINE_SWEEP_DURATION // SCANLINE_CYCLES
|
||||
|
||||
def _glitch_scanlines():
|
||||
# render.Sequence doesn't loop (it just stops painting once its total
|
||||
# frame count is exhausted -- confirmed in pixlet's own source), so
|
||||
# the RGB-split jitter above plays once per show_static window and
|
||||
# then goes quiet; these persist for the whole window as a constant
|
||||
# texture rather than a one-shot burst, closer to how SUB/WAVE's
|
||||
# scanlines sweep continuously while its live class is applied.
|
||||
# Modeled on SUB/WAVE's own scanlines, which sweep continuously via
|
||||
# an animated `background-position-y` rather than sitting still.
|
||||
#
|
||||
# An earlier version tried a single large sweep across a buffer built
|
||||
# twice as tall as the art slot, pre-shifted with a *negative*
|
||||
# render.Padding so the pattern's middle 32 rows lined up with the
|
||||
# window at rest. That didn't work how a positive Padding (which
|
||||
# reliably *grows* a widget's declared size -- used elsewhere in this
|
||||
# file, e.g. _glitch_band) does; empirically it went blank partway
|
||||
# through instead of revealing new rows at the top, which is what
|
||||
# "scanlines disappearing at the bottom without regenerating at the
|
||||
# top" looked like.
|
||||
#
|
||||
# This avoids all of that: the buffer is only ONE extra
|
||||
# SCANLINE_PERIOD taller than the art slot (the same small, proven-
|
||||
# safe oversized margin used everywhere else in this file -- e.g. the
|
||||
# zoom's own ART_SIZE vs. ART_SLOT), and instead of one big sweep it's
|
||||
# a repeating sawtooth -- ramp down by exactly one SCANLINE_PERIOD,
|
||||
# then snap back to 0 and repeat. Since the pattern repeats every
|
||||
# SCANLINE_PERIOD anyway, a one-period displacement looks identical to
|
||||
# the starting position, so the snap is invisible -- a standard
|
||||
# infinite-scrolling-texture trick -- while the translate distance
|
||||
# never has to leave the small range already confirmed safe.
|
||||
tall = ART_SLOT + SCANLINE_PERIOD
|
||||
lines = []
|
||||
for y in range(ART_SLOT):
|
||||
if y % 4 == 0:
|
||||
for y in range(tall):
|
||||
# SCANLINE_PERIOD=4 over ART_SLOT=32 gives 8 evenly-spaced lines
|
||||
# per window; skipping 2 of those 8 positions (dropping the last
|
||||
# two in each 32-row repeat, rather than changing the period
|
||||
# itself) keeps the period dividing evenly into things cleanly.
|
||||
if y % SCANLINE_PERIOD == 0 and (y % ART_SLOT) < ART_SLOT - 2 * SCANLINE_PERIOD:
|
||||
lines.append(render.Box(width = ART_SLOT, height = 1, color = "#00000080"))
|
||||
else:
|
||||
lines.append(render.Box(width = ART_SLOT, height = 1, color = "#00000000"))
|
||||
return render.Column(children = lines)
|
||||
pattern = render.Column(children = lines)
|
||||
|
||||
keyframes = []
|
||||
for cycle in range(SCANLINE_CYCLES):
|
||||
cycle_start = cycle * _SCANLINE_CYCLE_TICKS
|
||||
ramp_end = cycle_start + _SCANLINE_CYCLE_TICKS - 1 # last tick of the cycle is the snap back to 0
|
||||
keyframes.append(animation.Keyframe(
|
||||
percentage = float(cycle_start) / SCANLINE_SWEEP_DURATION,
|
||||
transforms = [animation.Translate(0, 0)],
|
||||
))
|
||||
keyframes.append(animation.Keyframe(
|
||||
percentage = float(ramp_end) / SCANLINE_SWEEP_DURATION,
|
||||
transforms = [animation.Translate(0, SCANLINE_PERIOD)],
|
||||
curve = "linear",
|
||||
))
|
||||
|
||||
sweeping = animation.Transformation(child = pattern, duration = SCANLINE_SWEEP_DURATION, keyframes = keyframes)
|
||||
return render.Box(width = ART_SLOT, height = ART_SLOT, child = sweeping)
|
||||
|
||||
def _glitch_corner_ticks(color):
|
||||
tick_size = 5
|
||||
|
||||