Skip to content

Why Silvery?

Silvery started from a single frustration — React terminal components can't know their own size during render — and grew into a ground-up reimplementation with a different architectural commitment: atomic frame rendering. Every frame is either fully committed to the terminal or not at all. No intermediate states. No flicker. No component dropout on scroll. No half-updated trees.

The Core Problem

In existing React terminal frameworks, React renders components first, then a layout engine (like Yoga) calculates positions and sizes. Components render at width: 0 on the first pass, layout runs, and then components re-render with real dimensions. This "two-pass dance" means intermediate states are observable — and when the renderer is interrupted (by React fiber, by the terminal painting mid-emission, by a scroll event triggering re-layout), those broken intermediate states end up on screen.

You see this in real apps: flicker during streaming. Components appearing and disappearing during scroll. Blank cells in the middle of a layout. The app works fine in demo videos but falls apart under real interaction.

This has been a known limitation in existing frameworks since 2016. Addressing it requires a fundamentally different rendering pipeline — one where layout runs before render, and where frame emission commits atomically.

Silvery's Approach

Silvery inverts the order: layout runs first, then components render with actual dimensions available via useBoxRect():

tsx
function Card({ item }: { item: Item }) {
  const { width } = useBoxRect()
  return <Text>{truncate(item.title, width - 4)}</Text>
}

No prop drilling, no post-render measurement, no width: 0 on first paint. This architectural change also unlocks native scrollable containers (overflow="scroll") and automatic text truncation -- features that depend on knowing "how much space do I have?"

Performance

Silvery's atomic layout-first pipeline + cell-level buffer diff make it 3–27× faster than Ink 7.0 (typically 15–20×) in our mounted rerender benchmarks. The output phase emits 10–20× less output (much more for large trees) to the terminal than Ink's line-level diff.

Mounted rerender throughput

ScenarioSilvery advantage
Cursor move 20-item (all visible)2.7×
Cursor move 100-item3.1×
Kanban move editing marker3.3×
Memo'd cursor highlight 100 (inverse)5.3×
Memo'd cursor highlight 1000 (inverse)6.1×
Memo'd 100-item single toggle5.1×
Memo'd 500-item single toggle5.7×
Memo'd kanban 5×20 move editing marker4.3×

Synchronous rerender throughput, mocked stdout. Reproduce: bun run bench. See detailed benchmarks for methodology.

Bundle size — parity with Ink+Yoga

PackageMinified + Gzipped
Ink 7.0 + Yoga WASM (baseline)116.6 KB
silvery/runtime (core + flexily)114.9 KB (tied)

Pure TypeScript, zero WASM, zero native dependencies, instant startup (no async WASM init).

Why the speedup

Silvery tracks 7 independent dirty flags per node. When a user presses a key, only the nodes that actually changed are re-rendered — React reconciliation, layout, and content generation are all skipped for unchanged nodes. The cell-level output phase then emits only the cells that differ from the previous frame, using relative cursor positioning to keep the wire size minimal.

Components

Silvery ships 45+ components organized across several categories:

Layout: Box, Spacer, Fill, Newline, Divider, SplitView

Input: TextInput, TextArea, SelectList, CommandPalette, Form, Toggle, SearchBar

Display: Text, Badge, Spinner, ProgressBar, Table, Tabs, Toast, Tooltip, Skeleton, Typography

Navigation: TreeView, ListView, VirtualList, Breadcrumb

Containers: Screen, ModalDialog, PickerDialog, ScrollbackView, ScrollbackList, ErrorBoundary, Console

Interaction: Mouse events, spatial focus navigation (focusScope on Box), command system with keybindings, input layer stack

Theming: 84 color schemes with semantic color tokens ($primary, $success, $muted, $danger), auto-detection of terminal background color, WCAG-aware contrast. See the theme explorer to preview all palettes.

Terminal Protocol Coverage

Silvery implements comprehensive terminal protocol support for cross-terminal compatibility and modern features:

Styling: 16/256/truecolor SGR, bold, italic, dim, underline, strikethrough, inverse, extended underlines (curly, dotted, dashed) with underline color.

Keyboard: Full Kitty keyboard protocol (all 5 flags -- disambiguate, event types, alternate keys, all keys, associated text), press/repeat/release events, modifier detection including Super/Cmd.

Mouse: X10, button event tracking, SGR extended protocol (coordinates beyond 223), focus in/out reporting, mouse cursor shape via OSC 22.

Graphics: Kitty graphics protocol (PNG transmission with chunking), Sixel encoding with color quantization, automatic fallback (Kitty to Sixel to text placeholder).

Clipboard & Links: OSC 52 clipboard access (works over SSH), OSC 8 hyperlinks.

Output: Synchronized output (DEC mode 2026) for flicker-free rendering, alternate screen buffer, scroll regions (DECSTBM), cursor shape control (DECSCUSR).

Queries: Cursor position (CPR), pixel dimensions (CSI 14t), text area size (CSI 18t), device attributes (DA1/DA2/DA3), terminal identification (XTVERSION). Used at startup for automatic capability detection.

For a feature-by-feature comparison with Ink, see the protocol tables in the detailed comparison.

What Else Comes With It

Beyond responsive layout, the renderer provides:

  • Atomic frame commit — every frame wrapped in DEC mode 2026 (synchronized output). The terminal either sees old frame or new frame, never a half-drawn mixture. No flicker, no tearing, no component dropout during scroll.
  • ANSI-aware cell compositing — proper style stacking, not just string concatenation
  • Pure TypeScript — no WASM, no C++, no native dependencies. Runs on Node, Bun, and Deno
  • Stable memory — normal JavaScript garbage collection, no WASM heap growth
  • ~99% Ink 7.0 test compatibility — 918/931 tests pass. Existing Ink code works with minimal changes via the silvery/ink compatibility layer

Optional packages extend the renderer into a full framework:

  • Rich interaction -- mouse events, spatial focus navigation, command system with keybindings, input layer stack
  • Theming -- 84 color schemes with semantic color tokens, auto-detects terminal colors
  • TEA state machines (@silvery/create, optional) -- pure (action, state) -> [state, effects] for testing, replay, and undo

If you know React, you know Silvery -- the core API (Box, Text, useInput, render) is familiar. See the Getting Started guide to try it, or the detailed comparison for the full technical breakdown.

Get Started

Ready to try Silvery? The quick start guide gets you from zero to a running terminal app in under 5 minutes.