The Console Framework
Build full-stack React apps that render inside console.log.
This page is running in your console. Open it with ⌘⌥JCtrl+Shift+J⌘⌥KCtrl+Shift+K⌘⌥C (turn on developer features first), click the preview below and press ↑ ↓.
1import { useState } from "react";2import { AsciiFont, Box, Text, useInput } from "@textjs/app";34export default function Page() {5 const [count, setCount] = useState(0);6 useInput((e) => {7 if (e.key === "up") setCount((c) => c + 1);8 if (e.key === "down") setCount((c) => c - 1);9 });1011 return (12 <Box className="flex-col gap-1 p-2">13 <AsciiFont text="▼ TEXT.JS" />14 <Text color="muted">React 19 in console.log</Text>15 <Text bold color="accent">count = {count}</Text>16 </Box>17 );18}React 19
Text.js supports concurrent rendering, Suspense and error boundaries.
App Router
Folders in app/ become routes and layouts, and Back, Forward and deep links work.
Responsive grid
The grid fits the docked DevTools panel at any page zoom.
Keyboard input
Keys, paste and IME composition reach the app through one hidden <textarea>.
Tables, charts, forms and shortcuts
Every changed frame is one console.log call
A commit that changes no cells never reaches the console.
- React 19
01Commit
React commits through a custom reconciler.
- Yoga
02Layout
Yoga lays out boxes on whole cells.
- CellBuffer
03Paint
Only damaged rows repaint.
- Row hash
04Dirty gate
Unchanged frames stop here.
- RLE
05Encode
3,200 cells become 149
%cspans. - console.log
06Emit
Frames are appended at least 66ms apart.
Appended frames
Clearing the console before each frame leaves it blank until DevTools paints the next one. Turbolog appends each frame instead.
Read the postclear() + log()70.6% blanklog(), appended1.0% blank%c arguments for 3,200 cellsRender routes on the server
Export runtime = "server" to render a route and its async components on the server. The browser loads a 21 kB (gzip) frame player instead of your app.
1import { Suspense } from "react";2import { Box, Text } from "@textjs/app";3import { db } from "@/lib/db";45export const runtime = "server";67async function Deploys() {8 const rows = await db.deploys.latest(5);9 return rows.map((d) => (10 <Text key={d.id}>{`${d.state} ${d.branch}`}</Text>11 ));12}1314export default function Page() {15 return (16 <Box className="flex-col p-1">17 <Text bold>Deployments</Text>18 <Suspense fallback={<Text color="muted">Loading…</Text>}>19 <Deploys />20 </Suspense>21 </Box>22 );23}- Partial PrerenderingEvery static route’s first frame ships inside its HTML. The console paints before JavaScript loads.
- Middleware
middleware.tsruns before matched requests, withNextRequest,NextResponseandconfig.matcher. - Caching
revalidate,unstable_cacheandrevalidateTagcache route handlers and data, with stale-while-revalidate. - Deploy adapters
text build --adaptertargetsstatic,bun,vercelorcloudflare. Server-rendered routes needbunortext start.
Also runs in terminals and agents
DevToolstext dev
Turbolog writes each frame as %c spans in one console.log.
Terminaltext run
text run renders the same App Router app in truecolor ANSI and runs route handlers in-process.
Coding agentstext mcp
Over MCP, agents navigate routes, press keys and read each frame as plain text.
Code with OpenCode in DevTools
OpenCode Lite is the OpenCode TUI rebuilt with Text.js to run in your browser console.
Sandbox
A scripted agent answers any prompt, with nothing to install.
One command
Run bunx @textjs/opencode@latest proxy and enter the code it prints. The page connects to OpenCode on your machine.
Your models and sessions
Pick any model your server has configured with /models. Sessions, agents and models come from your OpenCode server.
Editor, lint and test tooling
DevTools extension
Adds a panel with the component tree, a frame inspector and a per-frame timeline.
Text.js panelVS Code
Previews the frame next to your code and scaffolds App Router files.
⌘K VESLint
Catches DOM tags in console components, boxes inside text and glyphs Menlo doesn’t have.
eslint-plugin-textjsTesting
Render offscreen, press keys and assert on lastFrame() in any test runner.
Error codes
Errors and warnings with a TX code link to a page that explains the fix.
Console REPL
Pause, resize, wireframe and copy the running app from the console prompt.
window.textRight-to-left
Implements the Unicode Bidirectional Algorithm and passes all 770,241 BidiTest.txt cases.
FIGlet fonts
Parses .flf files and matches 273 outputs recorded from the figlet binary.
Build a deploy dashboard in your console
The free course has 10 chapters and takes about 65 minutes.