diff options
| author | user <user@clank> | 2026-08-12 16:25:18 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-12 19:34:35 +0200 |
| commit | 521212c3afc3db4b7fbce736b8146608f07f5cba (patch) | |
| tree | f9dd1f52e65564ab53241fe4bd7d59579df8e49d /cli | |
| parent | chrome: indent the input behind a ❯ prompt glyph (diff) | |
| download | sl0ppi-521212c3afc3db4b7fbce736b8146608f07f5cba.tar.gz sl0ppi-521212c3afc3db4b7fbce736b8146608f07f5cba.tar.xz sl0ppi-521212c3afc3db4b7fbce736b8146608f07f5cba.zip | |
slop-tool-boxes: green heartbeat pulse; unfreeze top border when it fits
Two changes that both come back to "what should an in-flight box look like",
plus the icon that was left out of it.
PULSE: single hue, brightness only. The old pulse interpolated a 4-color
synthwave ring (amber -> pink -> violet -> cyan) over 4s, which at that
period reads as a slow hue *drift*, not a pulse -- you notice the color has
changed, never that it is beating. Now it is one hue (green, i.e. "in
progress") modulated dim <-> bright: #0d4023 to #3bff7a, via a raised
cosine so there is no direction-reversal snap at the turn, then gamma ^1.7
to bias it toward the dim end. The border rests dark and spikes bright,
which is what makes it read as a heartbeat.
CYCLE_MS 4000 -> 800 (1.25Hz), and 800 is now the only pulse-speed knob.
There is a hard floor of ~400ms documented at the constant: a brightness
pulse IS a flicker, and 3-30Hz is the photosensitive-seizure band -- this
repo has already shipped one seizure-grade flicker bug (NOTES.md), so the
constant carries the warning rather than relying on memory. The upper bound
is render cadence, not taste: the pulse never forces a repaint, it samples
wall-clock time on renders that were happening anyway (~10fps while the
spinner runs), so 800ms is ~8 samples per beat. Much faster and consecutive
renders land on distant brightnesses -- the beat degrades into jitter.
TOP BORDER: freeze only when we actually must. 0d671ce stopped the
full-redraw flicker by freezing the call slot's top border for the whole
time the result streams. That was broader than the bug requires. The bug is
specifically "recolor a line that sits ABOVE the viewport": tui.js does
`if (firstChanged < prevViewportTop) fullRender(true)`, so an off-screen
recolor repaints everything, every tick. While the box still fits on
screen, firstChanged lands inside the viewport and tui diffs from there
down -- cheap. So canPulseTopBorder() compares callH + resultH against
rows - RESERVED_ROWS and only freezes past that, which gives short tool
calls their top and bottom borders beating in unison again.
resultH is one frame stale (the call slot renders before the result slot).
Harmless, because a box only grows: worst case is one extra full redraw on
the frame it crosses the threshold, and then it is frozen. RESERVED_ROWS
(14, for input box + footer + topbar) is deliberately generous in the same
direction -- over-estimating freezes a box that could have animated, which
nobody can see; under-estimating buys back the flicker.
A frozen border now holds HOLD_PAINT, a fixed mid-beat green (pulseRGB(0.5)),
instead of whatever phase the pulse happened to be at when content last
changed. Same number of writes, but it looks deliberately held rather than
randomly stuck. Resuming the pulse invalidates callActiveW so the frozen
lines cannot be served stale.
ICON: the pending ◉ takes the border's paint, so it beats with the frame
instead of sitting there as a static amber dot. This is why the label is
built inside build() now -- it has to be rebuilt per paint. It costs
nothing extra: the icon shares the top border's line, which is already
being rewritten.
Also picks up the sl0peration -> turn doc-comment rename in the header,
which is unified into the same hunk as the pulse comment above it.
Diffstat (limited to 'cli')
0 files changed, 0 insertions, 0 deletions
