aboutsummaryrefslogtreecommitdiffstats
path: root/cli/src
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-12 16:25:18 +0200
committeruser <user@clank>2026-08-12 19:34:35 +0200
commit521212c3afc3db4b7fbce736b8146608f07f5cba (patch)
treef9dd1f52e65564ab53241fe4bd7d59579df8e49d /cli/src
parentchrome: indent the input behind a ❯ prompt glyph (diff)
downloadsl0ppi-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/src')
0 files changed, 0 insertions, 0 deletions