Voltar ao portfólio

Projeto

Terminal Engine

Uma console engine. Escreva para o terminal, rode no browser também.

Um terminal virtual construído em volta de uma classe, a BasicConsole. Output, eventos de input, controle de cursor, limpar a tela e medir colunas ficam atrás da API dela. O app se liga uma vez; trocar os hooks do host leva ele do terminal do Node para o xterm.js no browser, ou para os testes, sem reescrever o código de render. Dois apps rodam nela hoje: Console Adventure e RTSim.

Demos públicas · sem conta

Dois programas, uma interface de console

  • Console Adventure

    RPG de fantasia no terminal: explore as Terras Mágicas, enfrente inimigos, ache equipamento. Orientado a objetos, só Node.

  • RTSim

    Simulador de escalonamento preemptivo em tempo discreto para uma ou mais CPUs: EDF, FCFS, HRRN, Priority, Round Robin, SJF e PriorityRR, desenhado a até 60 fps.

Por que separar o console do host

Os dois apps foram escritos para o terminal do Node, e cada um desenhava as telas com os próprios helpers de console. O README do RTSim já dizia que o pequeno motor de render dele precisava ser desacoplado.

Tirar essa camada para uma engine só, com o host plugado por baixo, é o que deixa o mesmo código de render rodar num terminal de verdade e no browser, e dá ao próximo app de console um ponto de partida.

O que os adapters permitem

  • Renderiza uma vez, qualquer host

    O código de render pede a um objeto só para escrever, limpar, mostrar o cursor ou medir a tela. Ele nunca sabe se é Node, xterm.js ou um teste.

  • Layout que entende cor

    Centralizar, quebrar, cortar e fatiar texto com segurança mesmo com códigos de cor ANSI, então um quadro colorido continua alinhado.

  • Teclas em que o app confia

    Eventos de tecla do browser viram strings estáveis como enter, space, esc e as setas antes de chegar no app.

  • Redimensiona e redesenha

    Primeiro o terminal do host se ajusta, depois o app redesenha no tamanho novo. O console continua sendo a única fonte de largura e altura.

Onde fica o limite do host

  • O código de render nunca sabe o host

    A única dependência de uma tela é a classe de console. Node, xterm.js e os testes fornecem cada um um adapter para os mesmos métodos. O custo é um adapter por host, e uma API pequena dentro da qual todo app tem que ficar.

  • O input é normalizado na borda

    O input fica ao lado da classe de console, não dentro dela. O host do browser transforma eventos de tecla em strings estáveis de nível de app, com os modificadores ao lado quando precisa, então a lógica do jogo e do simulador nunca lida com evento do DOM.

  • Build determinístico em vez de submódulo ao vivo

    A produção não busca submódulos, não segue branch flutuante e não depende do checkout git do host. Ela compila a partir de snapshots commitados de cada app. O custo: os snapshots são atualizados na mão.

Apps, console e adapters

Os apps renderizam pela classe de console da engine, a BasicConsole. Adapters de host ligam essa classe ao terminal do Node, ao xterm.js no browser ou aos testes.Terminal EnginerenderrenderConsole AdventureRPGRTSimsimuladorBasicConsoleuma API de consoleAdapter Nodeprocess.stdoutAdapter xterm.jsbrowserAdapter de testetests
  • O site é um host React + Vite para o lado xterm.js da engine: / lista os apps, /console-adventure e /rtsim rodam eles.
  • Cada app mantém o próprio repositório, fixado no catálogo como submódulo git.
  • A produção compila a partir de snapshots do código commitados, então o Stackport nunca precisa de clone recursivo.

Contexto do projeto

Time
Sozinho, do design ao deploy
Período
2024-09 – atual
Status
No ar em terminal.mattediworks.com
Stack
JavaScript, Node.js, React, xterm.js

O que ainda está acoplado

  • A engine mora dentro do código dos apps; ainda não é um pacote extraído.
  • Os snapshots de código da produção são atualizados na mão.
  • O repositório precisa de uma revisão: a branch padrão está atrás da branch de produção.