12k
All articles

O OpenTUI é uma Alternativa Real ao Ink?

OpenTUI vs Ink: compare desempenho de TUI, limites de runtime, componentes встроídos e custo de migração para apps em streaming e ferramentas CLI.

OpenReplay Team
OpenReplay Team
O OpenTUI é uma Alternativa Real ao Ink?

O OpenTUI é uma alternativa real ao Ink para interfaces de terminal que se redesenham continuamente, como saída de agentes em streaming, visualizadores de log e dashboards ao vivo, mas seus requisitos de runtime de ponta e a rotatividade de lançamentos 0.x fazem do Ink a escolha padrão mais segura para uma CLI publicada para usuários comuns de Node.

Se você já viu seu próprio dashboard em Ink engasgar sob um fluxo intenso de logs, já sabe por que as pessoas estão olhando para os lados. É exatamente essa lacuna que o OpenTUI foi construído para fechar.

O que segue aplica os mesmos critérios às duas bibliotecas: onde o renderizador do Ink chega ao limite, o que a arquitetura do OpenTUI muda, como a mesma UI pequena fica em cada um, que crédito de produção o OpenTUI conquistou e quanto custa a troca em termos de runtime, ecossistema e estabilidade. Termina com uma recomendação.

Principais Conclusões

  • O OpenTUI renderiza através de um núcleo nativo escrito em Zig, acessado do TypeScript via FFI, com layout flexbox do Yoga e bindings tanto para React quanto para Solid.
  • O Ink limita os redesenhos a 30 fps por padrão, configurável através da opção de renderização maxFps; o número de “32 FPS” que circula pela internet é uma leitura equivocada do intervalo de throttle de 32 milissegundos no código-fonte do Ink.
  • Uma CLI em OpenTUI exige que cada usuário final execute Bun 1.3+ ou Node.js 26.4+ com a flag experimental --experimental-ffi, o que é uma restrição de distribuição, não apenas um passo de configuração local.
  • O OpenTUI renderiza a interface de terminal do OpenCode em produção através de seu reconciler Solid, substituindo uma implementação em Go e Bubble Tea.
  • A linha 0.5.x do OpenTUI publica múltiplos lançamentos por mês, enquanto o Ink muda muito mais lentamente: seu último lançamento com quebra de compatibilidade, o Ink 7, elevou o piso para Node 22 e React 19.2 e deixou a API de componentes intacta. O Ink também tem um ecossistema de componentes comunitários muito maior.

Onde o Renderizador do Ink Chega ao Limite?

O teto do Ink é seu throttle de renderização: por padrão, ele limita os redesenhos a 30 quadros por segundo, e toda atualização de estado que exceda esse orçamento espera pelo próximo quadro. Para os fundamentos do Ink, veja o guia anterior sobre construção de interfaces de terminal com Node.js, que recomendava o Ink em dezembro de 2025, antes de o OpenTUI ser uma opção séria; este artigo é a atualização daquele veredito.

O throttle está documentado, não é folclore. Historicamente, o Ink fixava um throttle de 32 milissegundos em torno de sua função de renderização, que é a origem do número amplamente repetido de “limite de 32 FPS”: 32 é o intervalo em milissegundos, e a taxa que decorre disso é um teto de 30 quadros por segundo. O Ink atual expõe isso como a opção de renderização maxFps, com padrão 30, junto de uma opção incrementalRendering que limita cada repintura às linhas que mudaram. Portanto, o limite é ajustável. O que não é ajustável é a arquitetura: cada quadro é composto em JavaScript, comparado como strings e escrito no stdout pelo mesmo event loop que executa a lógica da sua aplicação.

Para um spinner, um formulário ou uma barra de progresso, nada disso é perceptível. Torna-se perceptível quando a saída é em streaming: tokens de modelo chegando mais rápido que o orçamento de quadros, um visualizador de log acompanhando um serviço movimentado, um dashboard re-renderizando regiões grandes. Há também um piso de memória. Um processo Ink carrega o runtime do Node mais o reconciler do React para algo que pode ser apenas algumas linhas de saída; não existe medição pública confiável desse overhead, então trate com desconfiança qualquer número específico em megabytes que você leia por aí.

O Que o OpenTUI Adiciona?

O OpenTUI move a renderização inteiramente para fora do JavaScript. Seu núcleo é escrito em Zig e cuida do buffer de tela, do desenho e do parsing de entrada nativamente; o TypeScript o acessa via FFI, bun:ffi no Bun ou o FFI experimental do Node. O layout permanece familiar: dimensionamento e posicionamento passam por flexbox baseado no Yoga, o mesmo motor que o Ink usa, então flexDirection, flexGrow e companhia são transferidos diretamente.

Duas adições importam além do renderizador. Primeiro, os componentes integrados cobrem terreno que o Ink deixa para pacotes de terceiros: um Input e um Textarea focáveis, Select, ScrollBox, realce de sintaxe apoiado em tree-sitter no Code, uma visualização Diff e Markdown. Dois outros, uma tabela de texto e um terminal embutido, existem apenas como renderables do Core, então React e Solid não conseguem acessá-los como elementos JSX. Segundo, a escolha de framework: @opentui/react e @opentui/solid são ambos bindings de primeira classe, então equipes que preferem reatividade granular para atualizações de alta frequência não ficam presas ao reconciler do React. Há também uma integração com Three.js via WebGPU, uma curiosidade para esta comparação e, além disso, exclusiva do Bun.

Como a Mesma UI Fica em Ink e OpenTUI?

O custo de migração é mais fácil de perceber construindo a mesma UI duas vezes: um painel com borda, uma linha de texto, uma tecla alternando estado e uma saída limpa. Os snippets têm como alvo o Ink 7 e o OpenTUI 0.5.x.

Ink, com scaffolding via npx create-ink-app:

import React, { useState } from "react";
import { render, Box, Text, useApp, useInput } from "ink";

function App() {
  const [name, setName] = useState("world");
  const { exit } = useApp();

  useInput((input, key) => {
    if (key.escape) exit();
    if (input === "r") {
      setName((prev) => (prev === "world" ? "terminal" : "world"));
    }
  });

  return (
    <Box borderStyle="round" padding={1} flexDirection="column">
      <Text>Hello, {name}! Press r to toggle, Esc to quit.</Text>
    </Box>
  );
}

render(<App />);

OpenTUI, com scaffolding via bun create tui --template react:

import { useState } from "react";
import { createCliRenderer } from "@opentui/core";
import { createRoot, useKeyboard, useRenderer } from "@opentui/react";

function App() {
  const [name, setName] = useState("world");
  const renderer = useRenderer();

  useKeyboard((key) => {
    if (key.name === "escape") renderer.destroy();
    if (key.name === "r") {
      setName((prev) => (prev === "world" ? "terminal" : "world"));
    }
  });

  return (
    <box style={{ border: true, padding: 1, flexDirection: "column" }}>
      <text>Hello, {name}! Press r to toggle, Esc to quit.</text>
    </box>
  );
}

const renderer = await createCliRenderer();
createRoot(renderer).render(<App />);

O diff é o guia de migração. O ponto de entrada muda da chamada render() do Ink para createCliRenderer() do @opentui/core mais createRoot(renderer).render() do @opentui/react. Os componentes Box e Text capitalizados tornam-se os intrínsecos minúsculos box e text, e nomes de elementos com mais de uma palavra usam hífen, como em <ascii-font>. O useInput e o useApp do Ink mapeiam para o useKeyboard e renderer.destroy() do OpenTUI. O React em si continua inalterado: tanto ink quanto @opentui/react exigem React 19.2 ou superior, e o useState funciona de forma idêntica. Os modelos de foco diferem mais: o Ink oferece useFocus com ciclagem por Tab integrada, enquanto o OpenTUI concede foco através de uma prop focused que você gerencia no estado.

O Crédito: o OpenTUI Renderiza o OpenCode em Produção

O OpenTUI não é um projeto de demonstração. Foi construído pela Anomaly, a empresa por trás do OpenCode, e o README do projeto afirma que o OpenCode é uma implantação em produção atendendo milhões de pessoas. Essa carga de trabalho, um agente de programação transmitindo saída de modelo, diffs e código com realce de sintaxe para um terminal interativo, é precisamente a carga em que o throttle do Ink aparece. A linhagem também importa: a interface do OpenCode foi reescrita de Go e Bubble Tea para o OpenTUI. Uma ressalva para usuários de React: a TUI do OpenCode roda no reconciler do Solid, então o teste de fogo em produção cobre mais o core e o binding Solid do que o @opentui/react, que, diferentemente do Core e do Solid, não é coberto por uma trilha de Node.js na CI.

O Custo: Rotatividade, Runtimes e Ecossistema

Os custos se concentram em três frentes, e o do runtime é um problema de distribuição, não de experiência do desenvolvedor.

CritérioInk 7OpenTUI 0.5.x
RuntimeNode 22+Bun 1.3+ ou Node 26.4+ com --experimental-ffi, apenas ESM
RenderizaçãoJavaScript, 30 fps padrão via maxFpsNúcleo nativo em Zig via FFI
LayoutFlexbox do YogaFlexbox do Yoga
Componentes integradosBox, Text, Static; inputs via pacotes da comunidadeInput, Select, ScrollBox, Code, Diff, Markdown e mais
FrameworksReactReact e Solid
MaturidadeMajors com anos de distância; o Ink 7 quebrou apenas pisos de runtime e eventos de tecladoMúltiplos lançamentos por mês em uma linha 0.x

Uma CLI em Ink roda em qualquer lugar onde o Node 22 ou superior rode. Uma CLI em OpenTUI impõe um requisito de ponta a cada usuário final: conforme a matriz de suporte de runtime, isso significa Bun 1.3.0+ ou Node.js 26.4.0+ com a flag experimental de FFI, apenas ESM, e um require de CommonJS falha completamente. Para uma ferramenta publicada no npm e instalada por desconhecidos, isso ou encolhe seu público ou empurra você para a distribuição via binário compilado.

A estabilidade é o segundo custo. A página de releases mostra da v0.4.4 até a v0.5.8 lançadas em cerca de seis semanas. Em uma linha 0.x, esse ritmo significa versões fixadas e monitoramento de changelog. A API do Ink, em contraste, se manteve estável ao longo de anos e de versões major. Terceiro, o ecossistema: os pacotes comunitários, receitas e respostas no Stack Overflow do Ink ainda não têm equivalente no OpenTUI, embora os componentes integrados mais ricos do OpenTUI compensem parte dessa lacuna. A depuração está mais ou menos em paridade; ambos suportam o React DevTools com DEV=true, e o OpenTUI adiciona um overlay de console e diagnósticos de renderização.

Você Deveria Migrar do Ink para o OpenTUI?

Migre agora se sua TUI se redesenha continuamente e você controla o runtime: um frontend de agente interno, um visualizador de log para sua própria equipe, qualquer coisa distribuída como binário compilado onde a exigência do Bun desaparece dentro do build. O núcleo em Zig, os componentes Code e Diff e a opção Solid são vantagens genuínas nesses casos, e o OpenCode comprova a arquitetura em escala.

Permaneça no Ink se você publica uma CLI no npm para públicos gerais de Node, se sua UI é feita de formulários, prompts e progresso em vez de fluxos contínuos, ou se você não pode absorver quebras de compatibilidade entre versões minor. O padrão de 30 fps do Ink é ajustável via maxFps, e sua lista de casos em produção, incluindo Claude Code, Gemini CLI, GitHub Copilot CLI, Wrangler e Prisma, mostra até onde o modelo com throttle se estica. Bubble Tea e Ratatui permanecem opções para equipes dispostas a abandonar o TypeScript, o que derruba a premissa deste artigo.

Conclusão

O OpenTUI merece o rótulo de “alternativa real” por sua arquitetura e evidências de produção, e o Ink mantém a posição de padrão por estabilidade e alcance. A pergunta decisiva não é qual renderizador é mais rápido; é se seus usuários conseguem executar seu runtime. Prototipe sua tela mais exigente com bun create tui --template react, observe-a sob um fluxo real e deixe a restrição de runtime, não o benchmark, tomar a decisão.

Perguntas Frequentes

O OpenTUI é exclusivo do Bun ou também roda no Node.js?

Não, o OpenTUI não é exclusivo do Bun. Bun 1.3.0 ou superior funciona, e o Node.js 26.4.0 ou superior também, desde que sua aplicação seja ESM e você inicie o Node com a flag experimental de FFI; se você importar o Core através de um require de CommonJS, ele lança erro. Algumas peças ainda são exclusivas do Bun, entre elas o @opentui/three e plugins carregados em tempo de execução, e o suporte a FFI do Node é ele mesmo experimental, então o Bun continua sendo o caminho melhor testado.

O OpenTUI funciona no Windows?

Sim. Pacotes de núcleo nativo pré-compilados são publicados para Windows x64 e Windows arm64, junto com macOS e builds tanto para glibc quanto para musl no Linux. No Windows, os próprios testes do projeto passam pelo Bun em x64, enquanto sua trilha de aceitação em Node.js fica no Linux x64, então teste uma release no Windows em um terminal Windows real antes de publicar, especialmente se seus usuários estiverem em Node em vez de Bun.

O OpenTUI suporta o React DevTools?

Sim, apesar de afirmações em contrário que circulam pela internet. A documentação do @opentui/react descreve a instalação do react-devtools-core@7 como dependência de desenvolvimento, a execução de npx react-devtools@7 e a inicialização da aplicação com DEV=true para inspecionar a árvore de componentes. O Ink suporta o React DevTools da mesma forma, através de DEV=true, então o ferramental de depuração não é um diferencial significativo entre as duas bibliotecas.

Devo usar o binding React ou Solid do OpenTUI?

Escolha o Solid para o caminho mais testado em produção: a interface de terminal do OpenCode roda no reconciler do Solid, e o @opentui/solid tem cobertura de CI em Node.js que falta ao @opentui/react. Escolha o React se sua equipe já trabalha com ele; o binding exige React 19.2.0 ou superior e oferece hooks como useKeyboard e useTimeline. Note que o @opentui/solid fixa o Solid exatamente na versão 1.9.12.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.