You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make the landing snow actually render on an idle screen (#428)
* Make the landing snow actually render on an idle screen
Three independent gates kept the falling-snow decoration over the landing
mountain from ever drawing: the mount-time paint was still=true, which the
old snowOn check tied directly to snow visibility; paintLanding early-returned
whenever it wasn't re-entered with animating=true, which never happens while
idle; and its only caller was the turn monitor, which deliberately stops
ticking once idle.
Fix: snow visibility no longer depends on `still` (that flag now only freezes
the mountain's own draw/fill/fade timeline, not the flakes over it), the
early-return is gone so idle repaints actually happen, and the shell's
createAppShell now repaints the landing off the renderer's own FRAME event
whenever the landing is up and not mid-turn-animation. That event is already
scoped to shell lifetime (wired at construction, unwired in dispose) and
paintLanding already no-ops once the landing tears down, so this needed no
new timer to arm or leak, and it doesn't touch the turn monitor's cadence at
all. The alternative — a separate timer armed from createLandingAbove and
stopped in the landing teardown — was rejected: it would duplicate the
monitor's own cadence-management responsibility for no real gain, since the
FRAME event already has the right lifetime.
Added a real-mount-path regression test in landing.test.ts that goes through
createAppShell and lets the renderer's FRAME event drive the repaint, unlike
every existing test in that file, which drives the mark by calling
paintLanding directly with a hand-picked clock. That gap is exactly why this
shipped broken and nobody caught it.
This supersedes PR #380, which added the snow-drawing code but never made it
reachable; that PR should stay open until this one is reviewed and can then
be closed in favor of this one.
* Throttle the idle landing repaint to ~8fps
FRAME fires from inside the on-demand render loop, and paintLanding
reassigns a fresh StyledText to every row every call regardless of
whether content changed, which unconditionally dirties renderables and
requests another render. Left unthrottled that turned the idle landing
into a perpetual ~60fps render loop instead of riding an existing one.
Guard the onFrame-driven repaint with a stored last-paint timestamp so
it only actually repaints once every ~125ms, and drop the comment that
falsely claimed only changed rows get touched.
Also thread an explicit reducedMotion input through the mark renderer
(renderMark/markChunks/paintLandingMark/paintLanding), separate from
still, so a future reduced-motion setting has a real plumbing path
instead of overloading still (which only freezes the mountain's own
draw/fill/fade timeline). Defaults to false everywhere; no behavior
change until something sets it. Updates the mark-anim.ts and
landing.ts docblocks that stated still suppressed snow, which PR #428
made no longer true.
* Drive the idle landing repaint off a mount-scoped timer, not a throttled FRAME hook
The FRAME-driven throttle added in the previous commit killed the landing's
self-driving loop entirely: the renderer only keeps rendering because each
paint dirties a row, which schedules the next FRAME; skipping a paint on a
throttled tick breaks that chain on the very next frame and the snow freezes
after the first paint. Any throttle above zero frames has the same effect,
since the throttle and the frame source were the same mechanism.
Replace it with a plain ~125ms interval armed when the shell mounts (the
landing exists for the lifetime of the shell until the first transcript row
tears it down) and cleared on whichever teardown happens first: the landing
going away, or the shell disposing. The timer self-cancels once the renderer
reports destroyed, so headless test harnesses that skip explicit
shell.dispose() don't leave it firing against torn-down renderables.
Also replace the test's manual renderOnce-loop clock with a real wall-clock
wait and no frame pumping at all, so the test can no longer stay green while
production's self-driving mechanism is dead — that blind spot is exactly how
the frozen throttle shipped in the first place.
0 commit comments