ghostty-webgpu v0.3.21

Ghostty's terminal, in the browser.

The real libghostty-vt core, unpatched, compiled to WebAssembly. Four renderers that draw only what changed, built to run dozens of terminals on one page.

npm install ghostty-webgpu

Runs every terminal in Fregat, an IDE in your browser.

html

Measured

Like for like: each renderer against the same renderer in xterm.js. Losses stay on the chart.

CPU energy, WebGL against xterm.js WebGL

× CPU energy, lower is better
Reviewed round-1 snapshot. Qualified with limits; frozen runtime, not a current-release benchmark.
  • Heavy log output
    ghostty-webgpu 0.3.20
    0.751
    xterm.js 6.0.0
    1.000
  • Heavy Unicode output
    ghostty-webgpu 0.3.20
    0.730
    xterm.js 6.0.0
    1.000
  • One Unicode line per tick
    ghostty-webgpu 0.3.20
    1.320
    xterm.js 6.0.0
    1.000
    Loss: about 32% more CPU energy.
  • One ASCII line per tick
    ghostty-webgpu 0.3.20
    1.361
    xterm.js 6.0.0
    1.000
    Loss: about 36% more CPU energy.
  • Typing-like edits
    ghostty-webgpu 0.3.20
    1.010
    xterm.js 6.0.0
    1.000
    Roughly even.
ghostty-webgpu / xterm.js. Below 1 means ghostty-webgpu uses less.
WorkloadHistoryCPU energyInstructions
Heavy log output8,841 final rows0.7510.690
Heavy Unicode output8,841 final rows0.7300.689
One Unicode line per tickEqual by construction1.3201.348
One ASCII line per tickEqual by construction1.3611.417
Typing-like editsEqual by construction1.0101.048
17 terminals, 40x12 cells each, device pixel ratio 2, 120 warm-up ticks then 900 measured ticks paced at 60 Hz. CPU energy: macOS kernel per-process CPU energy estimate for all Chrome processes; excludes GPU-device, display and whole-system power. Apple M1 MacBook, AC power, quiet load, headed Google Chrome 154.0.8037.93, hardware GPU (Metal). Run 2026-10-07 UTC; reviewed 2026-10-08. xterm.js WebGL addon 0.19.0.
import { Terminal } from 'ghostty-webgpu'

const host = document.getElementById('terminal')!
const terminal = await Terminal.create()
await terminal.open(host)
terminal.write('hello from ghostty\r\n')
terminal.focus()
Connect a WebSocket PTY
const socket = new WebSocket('wss://host/pty')
socket.binaryType = 'arraybuffer'

terminal.onData((bytes) => {
  if (socket.readyState !== WebSocket.OPEN) return
  socket.send(new Uint8Array(bytes))
})

socket.addEventListener('message', ({ data }) => {
  if (!(data instanceof ArrayBuffer)) return
  terminal.write(new Uint8Array(data))
})

The mount needs a height and width. Dispose the terminal and close the socket when the connection ends.

Only what changed is drawn. The renderer tracks damage per cell, so an idle terminal costs nothing and a busy one costs only its busy rows.

Runs anywhere. WebGPU where the browser has it, then WebGL2, then Canvas2D, then plain DOM. Each draws the same cells. This page is drawing with html.

Off the main thread. Import ghostty-webgpu/worker and the emulator, frame builder and renderer run in a worker on an OffscreenCanvas.

Correct because it is Ghostty

Parsing, modes, wrapping, reflow, selection text and Unicode widths come from Ghostty's own core. The renderer and input path are ours, and tested in real browsers.

Unpatched and reproducible. libghostty-vt at revision 7b11f3d, built with Zig 0.16.0, recorded with "patched": false. Anyone can rebuild the same wasm byte for byte.

Modern protocols, built in. Kitty keyboard with press, repeat and release. Grapheme clusters (mode 2027). OSC 8 links. Focus, bracketed paste and color-scheme reports. Programs in the terminal turn them on as they need them, with no addons to install.

Clipboard behind a policy. OSC 52 writes are denied until your app allows them, and clipboard reads are never answered.

Checked against the others. In 169 cases (132 from esctest2, 37 Unicode and delivery cases), ghostty-webgpu 0.3.20 passed 167, xterm.js 6.0.0 passed 126 and ghostty-web 0.4.0 passed 161. Headless Chromium 153, 8 Oct 2026. Every case and failure.

Not there yet: images (Sixel, Kitty graphics), ligatures, search, synchronized output. Still failing in esctest2, inherited from Ghostty's core: test_CHA_RespectsOriginMode and test_TBC_Default.

Coming from xterm.js

Fit, WebGL and Unicode graphemes are built in. Creation is async, and data stays as bytes from the PTY to the screen.

Read the migration guide
xterm.jsghostty-webgpu
new Terminal(opts)await Terminal.create(opts)
term.onData(str => …)terminal.onData(bytes => …)
loadAddon(new FitAddon())built in
loadAddon(new WebglAddon())built in, plus WebGPU
@xterm/headlessGhosttyRuntime.create()

Docs