Every terminal framework we tried repaints the entire screen every frame. Write a character, repaint 10,000 cells. Scroll one line, repaint 10,000 cells.
We decided to treat the terminal like a display server instead.
The idea
What if we tracked every cell in a typed-array buffer and only wrote the ones that actually changed?
That's Storm. A React-based terminal UI framework where the renderer diffs individual cells between frames. On a typical scroll frame, 97% of cells are unchanged — Storm skips them entirely.
How it works
Typed-array buffers — Int32Array + Uint8Array instead of JS objects. A 200×50 terminal has 10,000 cells. Traditional frameworks create 10,000 objects per frame. Storm creates zero — the buffer is flat arrays. ~90% less GC pressure.
Cell-level diff — After painting into the buffer, the diff engine compares frame N against frame N+1 cell by cell. Only changed cells produce ANSI output. The rest are skipped entirely.
WASM acceleration — An optional 35KB Rust module handles ANSI string generation 3.4× faster. Loads automatically, falls back to TypeScript silently.
Dual-speed rendering — React handles structural changes (adding/removing components). For animation and scrolling, requestRender() writes directly to the buffer — no React reconciliation, no layout rebuild. 0.5ms per frame vs 5ms.
What's in the box
- 98 components - from Box and Text to CommandPalette, TextArea, Markdown, DatePicker - 19 AI widgets — OperationTree, MessageBubble, ApprovalPrompt, StreamingText, SyntaxHighlight
- 85 hooks — including 15 headless behavior hooks- Built-in DevTools, render heatmap, accessibility audit, time-travel, inspector
- SSH serving — serve your TUI over SSH with auth and rate limiting
Quick start
npm install @orchetron/storm react
import React from "react";
import { render, Box, Text, Spinner, useInput, useTui } from "@orchetron/storm";
function App() {
const { exit } = useTui();
useInput((e) => { if (e.key === "c" && e.ctrl) exit(); });
return (
<Box padding={1}>
<Spinner type="diamond" color="#82AAFF" />
<Text bold color="#82AAFF"> storm is alive</Text>
</Box>
);
}
render(<App />).waitUntilExit();
10 lines. Running TUI with animated spinner and keyboard input.
The numbers
- Full frame: 2.3ms (7× headroom above 60fps)
- Cell skip rate: 97%
- WASM diff: 3.4× faster
- DECSTBM scroll: 78% fewer bytes to stdout
- SyntaxHighlight: 500K lines virtualized in 2.7s
Every number is real — no cache tricks, no theoretical peaks. Run them yourself: npx tsx examples/benchmarks.ts
Links
- GitHub: github.com/orchetron/storm
- Website: storm.orchetron.com
- npm:
npm install @orchetron/storm - Benchmarks: storm.orchetron.com/benchmarks
Storm is MIT licensed. We'd love feedback — what would you build with it?
Top comments (0)