控制台框架

构建在 console.log 中渲染的全栈 React 应用。

开始使用

此页面正在你的控制台中运行。按 ⌘⌥JCtrl+Shift+J⌘⌥KCtrl+Shift+K⌘⌥C 打开控制台(先开启开发者功能),点击下方预览并按 ↑ ↓。

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}
viewport:3

React 19

Text.js 支持并发渲染、Suspense 和错误边界。

App Router

app/ 中的文件夹成为路由和布局,支持后退、前进和深层链接。

响应式网格

网格在任意页面缩放比例下都能适应停靠的 DevTools 面板。

键盘输入

按键、粘贴和输入法组合输入通过一个隐藏的 <textarea> 传入应用。

表格、​图表、​表单和​快捷键

实时
preview://table:1
↑ ↓ 移动 · s 排序 · Space 选择
文档
布局
  • <Box>
  • <Stack>
  • <Grid>
  • <SplitPane>
  • <ScrollBox>
  • <Center>
数据
  • <List>
  • <Table>
  • <Tree>
  • <Markdown>
  • <Code>
  • <Diff>
图表
  • <LineChart>
  • <BarChart>
  • <Sparkline>
  • <ProgressBar>
  • <Gradient>
  • <Image>
控件
  • <Input>
  • <Select>
  • <Checkbox>
  • <Switch>
  • <Slider>
  • <Dialog>
键盘
  • useKeymap
  • <KeyHelp>
  • <KeyHints>
  • <CommandPalette>
  • <StatusBar>
  • useFocus

每个有变化的帧​对应一次 console.log 调用

未改变任何单元格的提交不会到达控制台。

  1. React 19

    01提交

    React 通过自定义协调器提交更新。

  2. Yoga

    02布局

    Yoga 按完整单元格布局盒子。

  3. CellBuffer

    03绘制

    仅重绘受损行。

  4. 行哈希

    04脏帧检查

    未变化的帧到此为止。

  5. RLE

    05编码

    3,200 个单元格转为 149 个 %c span。

  6. console.log

    06输出

    追加帧的间隔至少为 66 ms。

有变化的帧 未变化的帧,0 次调用

追加的帧

每帧前清空控制台,会使其保持空白,直到 DevTools 绘制下一帧。Turbolog 改为追加每一帧。

阅读文章
clear() + log()70.6% 空白
log(), appended1.0% 空白
0.163ms全量重绘(布局、绘制、编码)
0.011ms单行编辑,如按键输入
0 次调用空闲帧
149 个 span3200 个单元格所需的 %c 参数
100×32 仪表盘,1000 帧均值 · Apple M5 Pro · Bun 1.4.4Turbolog 引擎文档

在服务器上​渲染路由

导出 runtime = "server",在服务器上渲染路由及其异步组件。浏览器加载 21 kB(gzip)的帧播放器,而非你的应用。

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}

在 DevTools 中用 OpenCode 编码

OpenCode Lite 用 Text.js 重建 OpenCode TUI,在浏览器控制台中运行。

沙盒

脚本驱动的智能体回应任何提示,无需安装。

一条命令

运行 bunx @textjs/opencode@latest proxy 并输入输出的代码。页面连接到你机器上的 OpenCode。

你的模型​和会话

使用 /models 选择服务器已配置的任意模型。会话、智能体和模型来自你的 OpenCode 服务器。