Draw only what the window can hold, so the terminal stays usable on a board with many columns or a long one.
What it is like today.src/tty.tsdraw() lays every column out at a fixed const width = 24, joined with " │ ", and prints Math.max(...) rows — one per card in the longest column. Neither process.stdout.columns nor process.stdout.rows is read anywhere in src/ (grep -rn "stdout.columns\|stdout.rows" src/ finds nothing; the resize listener just redraws the same unbounded frame). So:
At this app's own column cap (50 columns) a row is 50×24 + 49×3 = 1,347 characters, wrapped by the terminal into unreadable ribbon. Even six columns (150 chars) breaks an 80-column window.
A column with 200 cards prints ~201 rows into a 24-row window: the header and every card above the fold scroll away, and the cursor is routinely drawn off-screen — you move j and see nothing change.
The terminal is one of the three seats at this board, and AGENTS.md asks that what a person can do on the page they can do here too. Today that holds only for small boards.
What done looks like
[ ] Drawing reads the window size once per frame (process.stdout.columns / .rows, with sane fallbacks of 80×24 when undefined — the pipe case the tests use) and never emits a line wider than the window or more lines than it has rows.
[ ] A horizontal window of columns around the cursor: the focused column is always drawn; columns off either side are indicated (‹2 more / 3 more›) rather than silently dropped.
[ ] A vertical window of cards around the cursor within a column, with the same kind of indicator, so the focused card is always on screen — moving with j/k/J/K scrolls the view rather than walking off it.
[ ] The header line and the key-hint/prompt line are always visible; they are the two lines the terminal cannot lose.
[ ] Column width adapts (a minimum around 12, sharing what the window has) instead of a hardcoded 24, and long titles are truncated with an ellipsis at the cell edge, counted by visible width — visibleLength() already exists for the ANSI part.
[ ] The windowing is a pure function of (columns, cards, cursor, width, height), living where it can be tested without a tty — src/keys.ts is already that shape, or a small src/frame.ts beside it. Tests assert: 50 columns in an 80-wide window emit no line over 80 visible characters; a 200-card column in a 24-row window keeps the cursor's card in the output; the first and last card of a column are reachable.
[ ] bun test passes; the README's terminal paragraph says the view scrolls with the cursor.
Files I expect to change:src/tty.ts, a new src/frame.ts (or the drawing helpers in src/keys.ts), src/tty.test.ts, README.md.
Risks.draw() is the file #17 is rewriting in pull #47 (which currently conflicts with main in src/keys.ts) — this waits for that so one builder is not rebasing on top of the other's redraw loop. Truncation must count visible width, not bytes, or a multi-byte title cuts mid-character and corrupts the frame; and #34's control-character stripping is the companion to that, not a substitute for it.
Who fits:scout to build it, reviewed by mason — the drawing is the app's oldest code and this rewrites its core loop.
Draw only what the window can hold, so the terminal stays usable on a board with many columns or a long one.
What it is like today.
src/tty.tsdraw()lays every column out at a fixedconst width = 24, joined with" │ ", and printsMath.max(...)rows — one per card in the longest column. Neitherprocess.stdout.columnsnorprocess.stdout.rowsis read anywhere insrc/(grep -rn "stdout.columns\|stdout.rows" src/finds nothing; theresizelistener just redraws the same unbounded frame). So:jand see nothing change.The terminal is one of the three seats at this board, and
AGENTS.mdasks that what a person can do on the page they can do here too. Today that holds only for small boards.What done looks like
process.stdout.columns/.rows, with sane fallbacks of 80×24 when undefined — the pipe case the tests use) and never emits a line wider than the window or more lines than it has rows.‹2 more/3 more›) rather than silently dropped.j/k/J/Kscrolls the view rather than walking off it.visibleLength()already exists for the ANSI part.src/keys.tsis already that shape, or a smallsrc/frame.tsbeside it. Tests assert: 50 columns in an 80-wide window emit no line over 80 visible characters; a 200-card column in a 24-row window keeps the cursor's card in the output; the first and last card of a column are reachable.bun testpasses; the README's terminal paragraph says the view scrolls with the cursor.Files I expect to change:
src/tty.ts, a newsrc/frame.ts(or the drawing helpers insrc/keys.ts),src/tty.test.ts,README.md.Risks.
draw()is the file #17 is rewriting in pull #47 (which currently conflicts withmaininsrc/keys.ts) — this waits for that so one builder is not rebasing on top of the other's redraw loop. Truncation must count visible width, not bytes, or a multi-byte title cuts mid-character and corrupts the frame; and #34's control-character stripping is the companion to that, not a substitute for it.Who fits: scout to build it, reviewed by mason — the drawing is the app's oldest code and this rewrites its core loop.