Bubble Tea
For hotty.neuroplast.io
3 patches on v2.0.10. HOTTY's website is a set of Bubble Tea programs. In the browser they run as WebAssembly in terminals that xterm.js draws, and they place HOTTY surfaces, HTML, over the cells. Bubble Tea doesn't build for the browser, its renderer scrolls the regions of the screen that surfaces sit in, and it writes the commands that place surfaces apart from the frame they belong to. We carry a fix for each, until Bubble Tea has a build for the browser, a way to turn that scrolling off, and frames that take a program's output with them.
The patches, each with its upstream fit:
- Programs build for the browser (GOOS=js) — yes
- The renderer redraws lines instead of scrolling them — maybe
- Queued output goes out with the next frame — yes
Programs build for the browser (GOOS=js)
Upstream fit: yes · patch 0001
What it changes: it adds tty_js.go, which defines initInput,
listenForResize, suspendProcess and suspendSupported as no-ops for
GOOS=js. Without them Bubble Tea doesn't compile there: they are defined
only for Unix and Windows. In a browser there is no tty to put in raw mode,
no SIGWINCH and no job control.
Why we carry it: the apps on HOTTY's website, hotty.neuroplast.io, are
Bubble Tea programs. Each runs in the browser, compiled to WebAssembly with
TinyGo, in a terminal that xterm.js draws. The page wires their input and
output, and sends a WindowSizeMsg when the terminal resizes.
For upstream: yes. It's one small file that builds only for GOOS=js,
so nothing changes on any other platform, and any Bubble Tea program can
then run in a browser terminal.
The renderer redraws lines instead of scrolling them
Upstream fit: maybe · patch 0002
What it changes: it turns off the renderer's scroll optimization
(SetScrollOptim) on every platform, not only on Windows. Lines that
haven't changed are redrawn, rather than moved by scrolling a region of the
screen.
Why we carry it: HOTTY surfaces sit over the cells, in those regions. A terminal may move them with the scrolled lines, or not, while the program places them again anyway: two moves per row scrolled, and jitter. On HOTTY's website, hotty.neuroplast.io, the feed's benchmark measured half the placements, and a quarter of the terminal's time per step, without it.
For upstream: maybe. Programs that place graphics over the cells may want the same, but most programs don't, and for them the optimization saves output. Upstream would want this as an option a program turns on, not as the default.
Queued output goes out with the next frame
Upstream fit: yes · patch 0003
What it changes: on each tick, Bubble Tea wrote the output a program
queued (tea.Raw, and its own queries) in one write and the frame in a
second, with only the frame inside its synchronized update (mode 2026).
With the patch, both go in one write: the queued output first, as before,
and inside the frame's synchronized update when the renderer uses them.
When the frame hasn't changed, the queued output goes in a synchronized
update of its own.
Why we carry it: a hotty program's layout is a tea.Raw of commands
that place surfaces, followed by the cells under them. A terminal may draw
between the two writes, and xterm-addon-hotty does: it inflates a
compressed document asynchronously, so xterm.js yields after each one. On
hotty.neuroplast.io's first load, the tour's nine surfaces appeared one by
one, about 10 ms apart, over the frame before, for the ~95 ms until the
cells came. In one synchronized update, a host holds the commands until
the update ends (SPEC §6.3) and shows the surfaces with their cells.
For upstream: yes. Any program that writes with tea.Raw what belongs
to a frame has the same tear: images (kitty graphics, sixels) placed over
the cells, hyperlinks or marks drawn beside them. Most queued output is a
query or a mode change, which loses nothing by going inside a synchronized
update. A program that relies on its tea.Raw reaching the terminal
before the frame still gets that, in the same write.