Claude Code uses a heavily customized fork of Ink, a React renderer for terminal applications. The implementation in src/ink/ provides a full rendering pipeline from React reconciliation through layout computation to terminal output, along with a rich event system for keyboard, mouse, and focus handling.
Architecture Overview
The rendering pipeline flows through four stages:
React Reconciler --> Yoga Layout --> Output Buffer --> Terminal Screen
(reconciler.ts) (flexbox) (render-node-to-output) (render-to-screen)Each frame follows this sequence:
- Reconcile: React reconciler processes component updates, creating/updating DOM nodes
- Layout: Yoga (flexbox engine) computes positions and dimensions for all nodes
- Render to Output: DOM nodes are rendered to an
Outputbuffer with styled text - Render to Screen: The output buffer is diffed against the previous frame and terminal escape sequences are emitted
Ink Class
The Ink class in src/ink/ink.tsx is the root coordinator. It owns the React fiber root, the terminal connection, the rendering scheduler, and the event dispatch system.
class Ink {
private readonly log: LogUpdate
private readonly terminal: Terminal
private scheduleRender: (() => void) & { cancel?: () => void }
// ...
}Initialization
The Ink constructor sets up:
- React fiber root via the custom reconciler with
ConcurrentRootmode - Terminal I/O through a
Terminalabstraction wrapping stdout/stdin - Render scheduling using throttled callbacks at
FRAME_INTERVAL_MS - Signal handling via
onExitfor clean shutdown (cursor restoration, alt-screen exit) - Alt-screen mode for full-screen rendering with cursor parking
Frame Rendering
Rendering is double-buffered with frontFrame and backFrame. Each render:
- Creates an
Outputinstance (reused forcharCachepersistence) - Calls
renderNodeToOutputto walk the DOM tree - Creates a
Screenfrom the output - Diffs the new screen against the previous frame
- Writes only changed regions to the terminal via
writeDiffToTerminal
React Reconciler
src/ink/reconciler.ts implements a React reconciler using react-reconciler. It bridges React's component model to a custom DOM:
import createReconciler from 'react-reconciler'DOM Nodes
The reconciler creates two types of nodes:
DOMElement: element nodes with styles, children, and event handlers. Created bycreateNode()with element names like'ink-box','ink-text','ink-button', etc.TextNode: text content nodes, created bycreateTextNode()
Operations
The reconciler implements the standard React reconciler host config:
createInstance/createTextInstance: create DOM nodesappendChildNode/removeChildNode/insertBeforeNode: tree mutationssetAttribute/setStyle/setTextStyles: property updatesmarkDirty: flags nodes for re-layout
Event Dispatch
A Dispatcher handles event propagation. Event handler props (onClick, onKeyPress, onFocus) are recognized during reconciliation and wired to the dispatch system.
Profiling
The reconciler tracks performance metrics:
getLastCommitMs(): time spent in the last React commit phasegetLastYogaMs(): time spent in the last Yoga layout computationresetProfileCounters(): resets profiling counters between frames
Renderer
src/ink/renderer.ts implements the createRenderer function that produces frame snapshots:
export default function createRenderer(
node: DOMElement,
stylePool: StylePool,
): Renderer {
let output: Output | undefined
return (options: RenderOptions) => {
// Compute layout via Yoga
// Render nodes to output buffer
// Create screen from output
// Return Frame with screen, viewport, and cursor
}
}Safety Checks
The renderer guards against invalid Yoga dimensions (NaN, Infinity, negative values) that would cause RangeError when creating arrays. When detected, it returns an empty frame and logs the issue for debugging.
Double Buffering
The RenderOptions include both frontFrame (current display) and backFrame (in-progress render), plus a prevFrameContaminated flag that indicates when the previous frame's screen buffer was mutated (e.g., by selection overlay) and full redraw is needed instead of incremental diff.
Layout Engine
Layout is computed by Yoga, a cross-platform flexbox implementation. The src/ink/layout/ directory contains layout node types and style mapping.
Key layout concepts:
- Flexbox model: components use flex direction, alignment, padding, margin, and gap
- Computed dimensions:
yogaNode.getComputedWidth()/getComputedHeight() - Display modes:
LayoutDisplayenum controls visibility - Style application:
applyStyles()maps component props to Yoga node properties
Built-in Components
Event System
The event system handles multiple input types:
Keyboard events are parsed from raw terminal input via parse-keypress.ts. The system supports:
- Standard keys and modifiers (Ctrl, Alt, Shift, Meta)
- Kitty keyboard protocol (
ENABLE_KITTY_KEYBOARD/DISABLE_KITTY_KEYBOARD) - Modified key sequences (
ENABLE_MODIFY_OTHER_KEYS) ParsedKeytype with name, ctrl, meta, shift, and sequence fields
Optimization
Several optimization techniques keep rendering performant:
- Node cache (
node-cache.ts): caches computed layout results for unchanged subtrees - Line width cache: avoids recalculating text widths for unchanged lines
- Output char cache: tokenization and grapheme clustering results persist across frames
- Screen pooling:
StylePool,CharPool, andHyperlinkPoolreduce allocation pressure with generational reuse - Optimizer (
optimizer.ts): post-processing pass that merges adjacent cells with identical styles - Throttled rendering: frames are throttled to
FRAME_INTERVAL_MSto avoid overwhelming the terminal
Terminal I/O
The terminal layer handles low-level output:
ANSI/CSI Sequences
src/ink/termio/csi.ts provides cursor control primitives:
CURSOR_HOME: move cursor to top-leftERASE_SCREEN: clear the terminal screencursorMove/cursorPosition: cursor positioning
DEC Private Modes
src/ink/termio/dec.ts manages terminal modes:
ENTER_ALT_SCREEN/EXIT_ALT_SCREEN: alternate screen bufferENABLE_MOUSE_TRACKING/DISABLE_MOUSE_TRACKING: mouse event reportingSHOW_CURSOR: cursor visibility
OSC Sequences
src/ink/termio/osc.ts handles operating system commands:
setClipboard: copy text to system clipboard via OSC 52supportsTabStatus: tab status line supportwrapForMultiplexer: wraps sequences for tmux/screen compatibility
Selection System
The selection system (selection.ts) supports text selection with mouse:
startSelection/extendSelection/updateSelection: selection trackinggetSelectedText: extract selected textapplySelectionOverlay: render selection highlight over the screenselectWordAt/selectLineAt: double-click and triple-click selectionshiftSelection/shiftAnchor: scroll-aware selection adjustmentfindPlainTextUrlAt: URL detection at cursor position