Skip to content

fix: terminal sized incorrectly on first load until window resize - #1561

Open
jolly-exe wants to merge 2 commits into
tsl0922:mainfrom
jolly-exe:main
Open

fix: terminal sized incorrectly on first load until window resize#1561
jolly-exe wants to merge 2 commits into
tsl0922:mainfrom
jolly-exe:main

Conversation

@jolly-exe

Copy link
Copy Markdown

Problem

On first opening a ttyd session, the terminal doesn't fill its container —
there's dead space on the right/bottom edges — until the browser window is
resized, which silently corrects it.

Root cause

Xterm.open() calls fitAddon.fit() right after terminal.open(), while
xterm's default dom renderer is active. The SET_PREFERENCES message that
follows switches the renderer to the default webgl, which measures cell
size slightly differently (e.g. 7px vs 7.8px cell width in one repro) — but
nothing re-fits after that renderer swap, so cols/rows stay pinned to the
stale dom-renderer measurement. Any subsequent window resize triggers a
fresh fit() under the correct renderer, masking the bug.

Fix

applyPreferences() now calls fitAddon.fit() once after all preferences
(including rendererType) are applied, replacing the narrower font-only
refit that missed the renderer case.

Also fixes an unrelated pre-existing build break: preact's RefCallback
type now allows an optional cleanup return (void | (() => void)), so the
bare assignment in terminal/index.tsx's ref callback no longer type-checks
against current preact and blocks npm run build. Wrapped it to return
void. src/html.h is regenerated from the fixed frontend.

Verification

Built the actual production bundle and the ttyd C binary, served it against
a mock of ttyd's WS handshake (/token, /ws, SET_WINDOW_TITLE,
SET_PREFERENCES) in headless Chromium at 1000×700:

  • Before fix: loads at cols=125; dispatching a same-viewport resize
    event jumps it to cols=135 — reproduces the reported bug exactly.
  • After fix: loads at cols=135 immediately; a same-viewport resize is a
    no-op (matches the previously resize-only-reachable state).

npx tsc --noEmit and npm run build both pass cleanly.

jolly added 2 commits August 18, 2026 16:26
The initial fitAddon.fit() runs while xterm's dom renderer is active.
The default rendererType preference (webgl) then loads asynchronously
and measures cell size slightly differently, but nothing re-fits after
the swap, so cols/rows stay pinned to the stale dom-renderer size. The
terminal ends up smaller than its container until a window resize
forces a fresh fit under the correct renderer.

Fit once after all preferences (including renderer) are applied,
replacing the narrower font-only refit.
The RefCallback type now allows returning an optional cleanup function
(void | (() => void)), so the bare assignment expression no longer
type-checks and blocks the production build. Wrap it to return void.

Also regenerates src/html.h from the current frontend (includes the
terminal resize fix).
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