29136d815d
Closes the cursor-pulse half of the splash polish arc deferred in
cacb19c. The "▌ ready_" boot-log line now ends with a 6×12 px cyan
Node that pulses on a 1 s sine cadence — matching the mockup at
docs/ui-mockups/splash-mobile.html. The pulse alpha is multiplied
with the global splash fade timeline rather than fighting it: the
cursor can't reach full alpha while the rest of the splash is still
fading in, and it fades out cleanly with everything else.
Implementation:
- New SplashCursorPulse marker on the trailing Node. Carries
SplashFadableBg too so it picks up the global fade for free; the
pulse system overwrites the per-tick BackgroundColor afterward
(last writer wins, both values are commensurate so the override
is correct, not a fight).
- New pulse_splash_cursor system, scheduled .chain()'d AFTER
advance_splash so the pulse multiplication is the final write.
No-op when no SplashRoot exists (post-despawn or under a test
fixture without one).
- New pure helper cursor_pulse_factor(age, period, min) returns a
sine-driven multiplier in [min..1.0]. Defensive zero/negative
period guard returns 1.0 so a misconfiguration produces a
steady cursor instead of a divide-by-zero NaN.
- Two splash-local consts: MOTION_PULSE_PERIOD_SECS = 1.0 (terminal-
blink cadence) and PULSE_ALPHA_MIN = 0.4 (the cursor never fully
extinguishes — matches a real terminal's blink that dips but
stays visible).
Used Node-with-explicit-dimensions rather than a `█` text glyph so
the 6×12 px size doesn't drift with line font; the leading `▌`
glyph stays a character (textual) while the trailing pulse is a
Node (geometric) — different primitives for different intents.
One new test (1182 → 1183): cursor_pulse_factor_corners pins the
peak (factor = 1 at age = period/4), trough (factor = min at age =
period * 3/4), and the defensive zero/negative-period guard.
Scanline overlay (the other half of cacb19c's skipped polish)
remains open — separate commit.