Claude Code has a big problem
Based on Theo - t3․gg's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.
Claude Code targets ~60 fps, leaving only about 5 ms for converting the computed UI into ANSI output after scene-graph work.
Briefing
Claude Code’s flicker and sluggishness trace back to a tight rendering budget and a terminal environment that punishes “React-style” updates—especially when the app must redraw or re-layout large portions of the UI under real-world conditions like resizing, long scrollback, and frequent garbage collection.
A key detail from the internal engineering discussion is the frame budget: Claude Code targets roughly a 16-millisecond cadence, leaving only about 5 milliseconds for the terminal-specific work that turns the computed UI into ANSI sequences. That narrow window matters because terminal rendering isn’t just “slower DOM.” Terminals are effectively byte- and escape-sequence limited: updating earlier content requires sending additional control codes to reposition the cursor and overwrite prior lines, which can balloon the amount of data sent and the amount of state the renderer must track. When the renderer misses its frame budget, flicker and jitter show up.
The performance debate also hinges on how React’s virtual DOM model behaves in an append-only output system. React’s strength comes from diffing and committing changes when it can update the “real world” representation efficiently. In a terminal, the “real world” is built by writing text and escape sequences; to change something, the system often has to locate the right region in scrollback and overwrite it. That means React-driven re-renders can translate into large bursts of terminal output—even when only a small part of the UI changed—because the terminal must be coerced into the right state via escape commands.
Resizing exposes another mismatch. Browsers provide explicit resize events and well-defined layout feedback loops. Terminals don’t offer the same standardized signals, so Claude Code has to infer dimensions and patch behavior around terminal quirks. The discussion points to intercepting SIGWINCH, disabling scrolling while measuring the pseudo-terminal size, recalculating layout, then patching differences and restoring scroll behavior. This is the kind of work that makes the experience feel “browser-like,” but it also increases complexity and the chance that rendering falls behind.
Garbage collection becomes a practical failure mode. In some terminal/OS combinations, the rendering pipeline triggered GC too often—an issue that only appears after shipping to diverse environments. When GC pauses land inside the frame window, the renderer misses deadlines, producing flicker.
The transcript also contrasts Claude Code with other terminal UI approaches. Libraries like ncurses and modern Rust TUIs (e.g., ratatouille, used by OpenAI’s Codex alternative) can rely on a standard scroll buffer and different rendering strategies. Some apps use “alt mode” to avoid polluting the terminal’s normal scrollback, which changes selection, copy/paste, and scroll behavior—often requiring custom selection logic and clipboard handling.
Overall, the argument isn’t that React is inherently wrong for terminals, but that the terminal’s constraints make React’s diff-and-rasterize pipeline expensive in ways that are easy to underestimate. The engineering goal, as framed here, is less about raw milliseconds and more about maintainability and safe iteration—keeping changes from breaking other parts of a large codebase while still meeting a 60 fps target. The result: Claude Code can be usable day-to-day, but its worst-case rendering paths are where the system’s architectural tradeoffs show up as lag, flicker, and jitter.
Cornell Notes
Claude Code’s rendering problems come from a mismatch between React-style UI diffing and the realities of terminal output. With a 16-millisecond frame budget, only about 5 milliseconds remain for converting the computed UI into ANSI sequences, so any extra work—like large re-renders, escape-sequence-heavy updates, or garbage collection pauses—can cause flicker. Terminals also lack browser-like resize events and standardized layout signals, forcing Claude Code to intercept SIGWINCH, measure pseudo-terminal dimensions, and patch scroll behavior. The transcript argues that these constraints make “small UI changes” potentially translate into large bursts of terminal bytes, especially when the app must overwrite earlier content in scrollback. The engineering tradeoff is maintainability and safe iteration using React, even if some terminal rendering paths are slower than ideal.
Why does a 16-millisecond frame budget matter for Claude Code’s flicker?
How does React’s virtual DOM model become costly in a terminal compared with a browser?
What makes terminal resizing particularly hard for terminal UIs?
Why does garbage collection show up as a rendering bug in some setups?
What’s the practical difference between using the standard scroll buffer and terminal alt mode?
How does the transcript connect maintainability to the choice of React for Claude Code?
Review Questions
- What specific steps in a terminal rendering pipeline can consume the limited ~5 ms available after the React/scene-graph stage?
- Why might a terminal UI that relies on escape-sequence overwrites send far more data than the number of visible characters suggests?
- How do SIGWINCH handling and scrollback behavior interact during terminal resizing, and why can that lead to missed frames?
Key Points
- 1
Claude Code targets ~60 fps, leaving only about 5 ms for converting the computed UI into ANSI output after scene-graph work.
- 2
Terminal rendering is constrained by bytes and escape-sequence operations, not just by the number of visible characters.
- 3
React-style re-rendering can translate into large bursts of terminal output because terminals require cursor positioning and overwriting to update earlier content.
- 4
Resizing is harder in terminals than in browsers because apps must infer pseudo-terminal dimensions and patch scroll behavior without standardized resize events.
- 5
Garbage collection pauses can directly cause missed frame deadlines, producing flicker in some terminal/OS combinations.
- 6
Using standard scrollback versus alt mode changes user interaction behavior (selection, scrolling, clipboard) and often forces custom logic.
- 7
The engineering tradeoff prioritizes safe, fast iteration and maintainability while still aiming to meet a 60 fps experience target.