Port the frame, not the whole terminal.
Ito is a young declarative interface library for Lua, built over Rust and Ratatui. Its public playground accepts Lua source, runs it in WebAssembly, and paints the resulting terminal cells onto a browser Canvas. The repository describes the native terminal as the default desktop output.
The implementation makes the split concrete. The Canvas output receives a frame made of cells. Each cell carries a row, column, width, text, foreground, background, modifiers, and an optional link. The frame also carries a cursor. The JavaScript painter does not need to understand the application's Lua controls.
A portable interface needs one stable state-and-layout contract. The final pixels can belong to another adapter.
Input travels back through the same seam
The browser owns keyboard, pointer, paste, focus, resize, and frame scheduling. Those events cross into the WebAssembly runtime. The Lua view updates its state and emits another cell frame. Repository tests exercise the same example through a terminal test host, including button, checkbox, slider, and text-field input.
That is more useful than a screenshot of a terminal. The browser output remains interactive because the host translates browser events into Ito's input model. The public playground also keeps the last accepted app running after an invalid edit. This is a practical workshop, not a static renderer.
The browser does not become a terminal
The repository names the missing parts. The Canvas output does not interpret raw ANSI writes. It does not provide a shell or filesystem host. It drops Kitty graphics instead of uploading them. Its drawn controls are not separate semantic DOM elements. The playground adds a readable text fallback, but that does not equal native HTML control accessibility.
The live playground exposes phone-width and full-width previews. In our browser pass, the example selector, Lua editor, reset action, preview-width controls, and fullscreen action were keyboard-visible in the page structure. That proves the hosted workshop exists and responds as a web page. It does not prove every generated Canvas control works with every assistive technology.
Read the API argument as design feedback
The Hacker News thread quickly moved from rendering to Lua style. Commenters questioned whether the chained builder API feels native to Lua and suggested table-based alternatives. The project author linked the discussion to an open design issue. That is a healthy boundary: renderer portability can be real while the authoring API remains unsettled.
For your own TUI, keep four records separate. Pin the view source. Name the runtime host. Define the frame contract. Test each output adapter with the same input sequence. If the terminal and browser land on different state after that sequence, the shared frame is not enough.