devlog.

Project · Emulator

TerminalGB

A Game Boy and Game Boy Color emulator written in Rust. It runs on the desktop, in a terminal, in a browser and on a PSP, and by default it draws the picture one dot at a time, the way the hardware does. Every frame it produces is checked against hardware-captured reference images and public test ROMs on every build.

103/103
Mooneye GB
73/76
SameSuite
243/264
GB Emulator Shootout
29/79
Mealybug pixel-exact

On the default identical picture engine. The Shootout figure is 5th of 19 through their own 264-row manifest.

A terminal window showing the dmg-acid2 test ROM's demon face rendered at full resolution in the left pane, with a Status panel to the right listing ROM, transport, input mode, palette, PPU engine, speed, video, audio and volume, and a Controls panel below it.
dmg-acid2 in a terminal — real pixels through the kitty graphics protocol, not text art. Zero of 23,040 pixels differ from the test author's hardware reference, on both engines and both consoles.

What it does

Everything here is built and shipping.

The machine

Nine consoles, four mappers

  • DMG, DMG 0, Pocket, Color, CGB 0, Advance, Super Game Boy and SGB2 — nine boot profiles, picked from the cartridge header
  • Mappers 1, 2, 3 and 5, with a real-time clock
  • Battery saves in the ecosystem's own format
  • Versioned save states, portable to the browser build
  • An optional boot ROM you supply
  • Two picture engines: standard, or hardware-exact identical

In your terminal

Degrades, never refuses

  • Kitty, Sixel, iTerm2 and half-block rendering
  • Shared-memory frame transport — 87 bytes a frame
  • Four upscalers, palettes, HiDPI correction
  • Runs in any terminal, using whatever that terminal supports

Sound

The whole audio unit

  • Complete APU emulation, 36 ms latency
  • Volume control that never touches emulation
  • Chiptune renderer — instructions in, real audio out
  • Music mode: ROMs as a shelf, with export

Linking

Two consoles on one cable

  • Two local instances linked, with a trade proven end to end
  • BGB's network protocol over TCP
  • A virtual trade partner, so no second cartridge is needed
  • Cable Club battles against that partner

Plugins

Reading the running cartridge

  • Live trainer view: party, stats, sprites, catch rate
  • Shiny hunting from Gen 1's hidden values
  • Battle control — start any battle from outside the game
  • An agent substrate for autonomous play

Beyond the terminal

Desktop, browser, handheld

  • A virtual camera the system sees as a webcam
  • Screenshots, recording, a telemetry stream
  • An MCP server, so any Claude client can drive it
  • An embeddable core with one third-party dependency
  • A WebAssembly build, and a reusable conformance action
  • A PSP frontend

Test scores

Both picture engines, same build. standard paints a whole scanline at once from the registers as they stand at the end of it. identical walks the real pipeline — fetcher, FIFO, sprite fetches, window restart, SCX & 7 discard — so mode 3's length falls out of the machine instead of being asserted. Only the second can represent the wrong tile source for one dot in the middle of a line, and only the second can catch it.

Suite identical (default) standard
Mooneye GB acceptance75 / 7567 / 75
Mooneye GB emulator-only28 / 2828 / 28
Mooneye GB misc (Color)8 / 88 / 8
SameSuite — audio rows66 / 6966 / 69
SameSuite — whole suite73 / 7673 / 76
Gambatte3,622 / 5,3203,176 / 5,320
GBMicrotest339 / 513252 / 513
Mooneye (wilbertpol)82 / 12262 / 122
AGE11 / 593 / 59
Scribbltests9 / 137 / 13
CasualPokePlayer4 / 44 / 4
rtc3test6 / 66 / 6
cgb-acid2 · cgb-acid-hell1 / 1 · 1 / 11 / 1 · 0 / 1
Mealybug Tearoom, pixel-exact rows29 / 793 / 79
Frame cost, Pokémon Blue, picture on, one P-core0.373 ms0.094 ms

The exact engine costs four times as much per frame and still spends only 2.2% of a frame's 16.7 ms budget on a desktop core, which is why it is the default. The PSP frontend pins standard: an exact picture nobody can play is worth nothing. Full throughput figures are on the performance page.

Where the reds are

A PlayStation Portable screen showing the dmg-acid2 demon face rendered by TerminalGB.
The same emulator on a PSP.

Milestones

24 Aug 2026

The double-speed pixel fix

A one-dot LCDC write-commit stagger, calibrated on single-speed ROMs, had no room to land once the CPU clock doubled. The AGE ROM m3-bg-lcdc-ds@cgbBCE went from 2,304 wrong pixels to a pixel-exact pass. Read it →

21 Aug 2026

Object DMA drives the address bus

The transfer controller takes the object-memory address lines, so the object scan reads nothing while a transfer runs. Shootout 238 → 239, Gambatte +4, zero losses. Read it →

20 Aug 2026

The exact engine becomes the default

identical stopped losing rows the fast engine still passed, so it was promoted. Fifteen Shootout rows gained, none lost — 223 → 238 — and cgb-acid2, the one row the per-dot engine used to lose, is pixel-exact on both now.

18 Aug 2026

Object DMA has a bus, and the CPU has to share it

The data half of the same physical rule. Gambatte went 2,682 → 3,083 on the fast engine. Four hundred rows, from modelling a bus conflict instead of a copy.

Writing


Where these numbers come from

Suite scores are the emulator's own checked-in conformance baselines, re-run in CI on every push and red on a change in either direction. Test ROMs are never vendored — they are fetched at run time from pinned commits, and every verdict is the ROM's own or its author's reference image. The Shootout figure comes from a shootout_scout run through their published manifest on 22 Aug 2026.

TerminalGB ships no ROMs, no boot ROM and no extracted game assets. The screenshots here are of test ROMs the project is free to show.

← All projects