The Renderer Graveyard
╔═══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ 🪦 REST IN PEACE 🪦 ║
║ ║
║ Here lie the renderers that couldn't render. ║
║ ║
║ "They didn't fix the terminal. They fixed our expectations." ║
║ ║
║ ║
║ Cause of Death: React in a Terminal ║
║ ║
║ Last Words: "We've achieved 85% improvement!" ║
║ ║
╚═══════════════════════════════════════════════════════════════════════════════╝
The Eternal Cycle
┌─────────────────────────────────────────────────────────────────┐
│ THE ANTHROPIC DEVELOPMENT CYCLE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ │ │
│ ▼ │ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┤ │
│ │ React │────▶│ Flicker│────▶│Rewrite │────▶│ Still │ │
│ │ is the │ │ like │ │renderer│ │ React │ │
│ │ answer!│ │ seizure│ │ v(n) │ │ │ │
│ └────────┘ └────────┘ └────────┘ └────────┘ │
│ │
│ │
│ Current iteration: v(∞) │
│ Expected fix date: When React learns to be a terminal │
│ Probability: 0% │
│ │
└─────────────────────────────────────────────────────────────────┘
How Anthropic Engineers
┌─────────────────────────────────────────────────────────────────┐
│ STEP 1: CHOOSE TECHNOLOGY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Q: What framework should we use for a CLI tool? │
│ │
│ Option A: Native terminal handling │
│ → Boring, but works │
│ → Every terminal ever uses this │
│ → We'd have to learn something │
│ │
│ Option B: React (Ink) │
│ → Exciting! Modern! Familiar! │
│ → Never been done for CLI at scale! │
│ → Must be a good reason nobody does this... │
│ → ...NAH, we're smarter than everyone │
│ │
│ ANTHROPIC: "B! Obviously B! We love React!" │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STEP 2: DISCOVER THE PROBLEM │
├─────────────────────────────────────────────────────────────────┤
│ │
│ User: "My screen looks like a slot machine" │
│ User: "VSCode crashed again" │
│ User: "I can't read the output, it's flickering" │
│ User: "Is this... supposed to happen?" │
│ │
│ ANTHROPIC: "Hmm. Interesting. We're aware of the issue." │
│ │
│ Internal meeting: │
│ "Maybe we should... no, React is fine." │
│ "The terminals are just slow." │
│ "Users should use faster terminals." │
│ "Have they tried Alacritty at 240fps?" │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STEP 3: REWRITE (STILL REACT) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ "We'll add differential rendering!" │
│ → Still React │
│ → Still 60fps game loop │
│ → Still 4,000 redraws/sec │
│ → Marginally better │
│ │
│ "We'll add synchronized output patches!" │
│ → Still React │
│ → Still JSX allocations │
│ → Still GC pauses │
│ → Marginally better │
│ │
│ "We'll add double-buffering!" │
│ → Still React │
│ → Now uses 2x memory │
│ → Still fundamentally broken │
│ → Marginally better │
│ │
│ Pattern: Add complexity, keep the disease │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STEP 4: THE BREAKTHROUGH 💡 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Engineer 1: "What if... we just delete the scrollback?" │
│ │
│ Engineer 2: "But users need to see their history..." │
│ │
│ Engineer 1: "Less history = less flickering = problem solved" │
│ │
│ Manager: "Ship it. Call it '85% improvement'." │
│ │
│ PR Team: "We've achieved 85% reduction in flickering │
│ through innovative rendering improvements!" │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ User: "I can't copy my previous output anymore..." │
│ │
│ Anthropic: *radio silence* │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ STEP 5: CLAIM VICTORY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Blog post: │
│ "We're proud to announce significant improvements │
│ to Claude Code's terminal experience!" │
│ │
│ Translation: │
│ "We deleted your scrollback. You're welcome." │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ Meanwhile, the community built "Claude Chill" │
│ because waiting for Anthropic was pointless. │
│ │
│ But sure, "85% improvement". 🎉 │
│ │
└─────────────────────────────────────────────────────────────────┘
The Beautiful Logic
┌─────────────────────────────────────────────────────────────────┐
│ ANTHROPIC PROBLEM-SOLVING FLOWCHART │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ │
│ │ Problem │ │
│ │ Reported │ │
│ └───────┬───────┘ │
│ │ │
│ ▼ │
│ ┌───────────────┐ │
│ │ Is it React's │ │
│ ┌────│ fault? │────┐ │
│ │ └───────────────┘ │ │
│ │ │ │
│ YES│ │NO │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Blame │ │ Blame │ │
│ │ something │ │ something │ │
│ │ else │ │ else │ │
│ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │
│ └──────────┬─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Rewrite │ │
│ │ renderer │ │
│ │ (keep React)│ │
│ └──────┬──────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ Still broke?│ │
│ ┌───│ │───┐ │
│ │ └─────────────┘ │ │
│ YES│ │NO (never happens) │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Delete │ │ Celebrate │ │
│ │ features │ │ (dream) │ │
│ └──────┬──────┘ └─────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ "85% │ │
│ │ improvement"│ │
│ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
The “85% Fixed” Lie
┌─────────────────────────────────────────────────────────────────┐
│ THE 85% CLAIM DECODED │
├─────────────────────────────────────────────────────────────────┤
│ │
│ MARKETING: │
│ "85% reduction in flickering through differential rendering" │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ REALITY: │
│ │
│ Before: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ [Full scrollback history] │ │
│ │ [1000+ lines visible] │ │
│ │ [Entire buffer redraws on each chunk] │ │
│ │ [4,000+ scroll events/sec] │ │
│ │ [FLICKER FLICKER FLICKER] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ After "fix": │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ [Limited scrollback] │ │
│ │ [~200 lines visible] │ │
│ │ [Less to redraw = less flicker] │ │
│ │ [Still redraws everything] │ │
│ │ [Still fundamentally broken] │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ 85% less history to flicker = "85% less flickering" │
│ │
│ The architecture is unchanged. │
│ The disease remains. They just amputated the limb. │
│ │
└─────────────────────────────────────────────────────────────────┘
The Scrollback Deletion Solution
┌─────────────────────────────────────────────────────────────────┐
│ ISSUES #2479 AND #16310: THE EVIDENCE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ User complaint #2479: │
│ "Can't copy previous command output from terminal" │
│ │
│ User complaint #16310: │
│ "Scrollback history disappears during AI streaming" │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ The connection: │
│ │
│ Problem: Full buffer redraws cause flickering │
│ Solution A: Fix the renderer (hard) │
│ Solution B: Delete the buffer (easy) │
│ │
│ They chose B. │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ Result: │
│ │
│ • Less flickering (because less to flicker) │
│ • Can't copy previous output (because it's gone) │
│ • Can't review AI reasoning (because it's gone) │
│ • Can't learn from mistakes (because they're gone) │
│ │
│ "We fixed the flickering by deleting your ability to scroll" │
│ │
└─────────────────────────────────────────────────────────────────┘
The React Problem They Won’t Admit
┌─────────────────────────────────────────────────────────────────┐
│ THE "GAME ENGINE" ANTI-PATTERN │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Claude Code's architecture (as described by developers): │
│ │
│ 1. React component graph │
│ ↓ │
│ 2. Element layout (~2400 characters) │
│ ↓ │
│ 3. 2D rasterization │
│ ↓ │
│ 4. Diff with previous frame │
│ ↓ │
│ 5. Generate ANSI string │
│ ↓ │
│ 6. Output to terminal │
│ │
│ Layout alone takes ~11ms for ~2400 characters. │
│ This runs continuously at 60fps target. │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ THE QUESTION: │
│ │
│ Why does a TEXT UI need 60fps continuous rendering? │
│ │
│ • LLM responses take seconds to minutes │
│ • Humans can't type 60 characters per second │
│ • When nothing happens, CPU should be 0% │
│ │
│ But React's model requires continuous computation. │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ They didn't build a terminal. │
│ They built a game engine that displays text. │
│ │
└─────────────────────────────────────────────────────────────────┘
TUI Should Be Event-Driven
┌─────────────────────────────────────────────────────────────────┐
│ TWO PARADIGMS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ FRAME-DRIVEN (Game Engine / Claude Code): │
│ ───────────────────────────────────────── │
│ │
│ while (true) { │
│ updateState(); // Always runs │
│ calculateLayout(); // Always runs │
│ renderFrame(); // Always runs │
│ waitForNextFrame(); // 16ms budget │
│ } │
│ │
│ CPU usage: Always > 0%, even when idle │
│ Appropriate for: Games, animations, video │
│ NOT for: Text terminals, CLIs │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ EVENT-DRIVEN (Traditional TUI / Monolex): │
│ ───────────────────────────────────────── │
│ │
│ waitForEvent() { // Blocks until event │
│ on(input) -> render(); │
│ on(output) -> render(); │
│ on(resize) -> render(); │
│ } │
│ │
│ CPU usage: 0% when idle, spikes only on events │
│ Appropriate for: Text editors, terminals, CLIs │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ Claude Code chose the wrong paradigm. │
│ Then spent a year patching symptoms. │
│ │
└─────────────────────────────────────────────────────────────────┘
The Performance Gap
┌─────────────────────────────────────────────────────────────────┐
│ MEASURED PERFORMANCE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ React/Ink layout for ~2400 chars: ~11ms │
│ GPU terminal render thousands chars: < 1ms │
│ │
│ Difference: 11x slower at minimum │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ The problem is NOT hardware. │
│ The problem is NOT terminal speed. │
│ │
│ The problem IS forcing a browser UI framework │
│ onto a text-based interface. │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ Developer commentary (Hacker News): │
│ │
│ "React was designed for browser UI complexity, │
│ not terminal UIs." │
│ │
│ "We've lost the tech. They use familiar tools │
│ instead of appropriate tools." │
│ │
│ "TypeScript + React is comfortable. │
│ But comfortable ≠ correct." │
│ │
└─────────────────────────────────────────────────────────────────┘
What Monolex Does Differently
┌─────────────────────────────────────────────────────────────────┐
│ ARCHITECTURAL DIFFERENCE │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Claude Code (Coupled): │
│ ────────────────────── │
│ │
│ Chunk → Parse → Render → Display │
│ ↓ ↓ ↓ ↓ │
│ Chunk → Parse → Render → Display │
│ ↓ ↓ ↓ ↓ │
│ Chunk → Parse → Render → Display │
│ ...4,000 times per second... │
│ │
│ Every chunk triggers full pipeline. │
│ Parsing and rendering are COUPLED. │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ Monolex (Decoupled): │
│ ──────────────────── │
│ │
│ Chunk → Parse ─┐ │
│ Chunk → Parse ─┼─▶ Grid State ─┐ │
│ Chunk → Parse ─┤ (current) │ │
│ Chunk → Parse ─┘ ▼ │
│ ...4,000/sec... Frame Boundary │
│ ↓ │
│ Render │
│ ↓ │
│ Display │
│ ...60/sec... │
│ │
│ Parsing: Unlimited speed (Rust, native) │
│ Rendering: 60fps (only current state) │
│ They are DECOUPLED. │
│ │
└─────────────────────────────────────────────────────────────────┘
This is not optimization. This is different architecture.Claude Code optimizes rendering. Monolex eliminates unnecessary rendering.
Claude Code diffs React trees. Monolex has no trees to diff.
Claude Code runs 60fps loop. Monolex is event-driven.You can’t optimize your way out of wrong architecture.
The Graveyard Epitaph
┌─────────────────────────────────────────────────────────────────┐
│ LESSONS FROM THE GRAVEYARD │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 1. Rewriting the renderer while keeping React = rearranging │
│ deck chairs on the Titanic. │
│ │
│ 2. "85% fixed" by deleting features is not fixing, │
│ it's retreating. │
│ │
│ 3. A 60fps game loop for text output is a category error. │
│ │
│ 4. When community builds workarounds, leadership has failed. │
│ │
│ 5. Silence is not a communication strategy. │
│ │
│ ─────────────────────────────────────────────────────────── │
│ │
│ The renderer graveyard grows. │
│ The React architecture remains. │
│ The flickering continues (in 15% of sessions). │
│ The scrollback stays deleted. │
│ │
│ And somewhere in an Anthropic meeting room: │
│ "Let's try differential rendering v3!" │
│ │
└─────────────────────────────────────────────────────────────────┘
Constitutional AI, Flickering UX
The beautiful irony of soul without body
Father Like Son
When in doubt, delete it out
References
| Source | Description |
|---|---|
| GitHub Issue #2479 | ”Can’t copy previous output” |
| GitHub Issue #16310 | ”Scrollback disappears during streaming” |
| GitHub Issue #769 | Original flickering report (278 upvotes) |
| December Revert Thread | Post-revert community discussion |
| Claude Chill | Community-built workaround |
Dear Anthropic. This letter is written in your son’s hand only, never touched a single letter.