Skip to content

Feat/resize support - #39

Open
btpence wants to merge 2 commits into
const-void:masterfrom
btpence:feat/resize-support
Open

btpence wants to merge 2 commits into
const-void:masterfrom
btpence:feat/resize-support

Conversation

@btpence

@btpence btpence commented Sep 17, 2026

Copy link
Copy Markdown

resize the screen as the terminal resizes.

btpence and others added 2 commits September 17, 2026 14:26
paintBuf() emits the frame as bs[0 .. bs_len - 1], dropping the buffer's
final newline, and the fire paints exactly term_sz.height rows of exactly
term_sz.width glyphs. The cursor therefore ends on the bottom-right cell
with the deferred-wrap flag set, and the SGR that follows does not clear
it. The status text's first character resolves the wrap, scrolling the
whole screen up one line and discarding the top row -- once per frame.

Terminals that present asynchronously can sample the screen between that
scroll and the status text being written, which shows as a flickering
status line. Emitting a CUP to the last row cancels the pending wrap and
puts the status where it was always meant to go, removing both the
per-frame scroll and the flicker.

Verified through a 120x30 pty capture: before this change there are no
CUP sequences in the bytes preceding the status line; after it, the
status is preceded by CSI <height>;1H.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KyxqTVBsjVGPpwFNzLzVPm
The fire was sized once, from the terminal size read at startup: FIRE_W/FIRE_H,
the fire buffer and the string buffer were all derived from it and never revisited.
Resizing the window left the fire painting its original rectangle -- clipped in a
smaller window, an island in a larger one -- until the program was restarted.

Ask the terminal for its size every 50ms and, when it changed, rebuild the fire at
the new size: re-derive FIRE_W/FIRE_H, reallocate the fire and string buffers,
re-seed the white source row, clear the screen and restart the frame statistics
(which are all sizes and rates for the screen that just went away). The check uses
the timestamp paintBuf() already takes each frame, so it costs one size query per
interval rather than one per frame, and responds the same at 30fps or 900fps. A
size of zero (query failed, or the window is minimised) keeps the current fire
rather than allocating an empty screen.

initBuf() also sized the string buffer by width * WIDTH, which is unrelated to the
number of rows painted: in a tall, narrow terminal the allowance is smaller than a
worst-case frame (20x60 allows ~20KB where the worst case is ~30KB). The colour
cache keeps real frames well under that, so it did not bite in practice, but
resizing makes such geometries reachable at runtime. Size it by width * height.

Verified in a pty harness that drives the program through 120x30, 60x20, 200x50 and
20x60 (tall and narrow): after each resize every complete frame contains exactly
cols*rows half-block glyphs and the status line is positioned for the new height,
and the process keeps running throughout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KyxqTVBsjVGPpwFNzLzVPm
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant