SturdyGB is an experimental Game Boy emulator written in Rust, focused on correctness, clean architecture, and long-term accuracy.
This project is still in early development. It can already run many commercial DMG (original Game Boy) and CGB (Game Boy Color) titles.
- LR35902 CPU
- Passes blargg’s CPU instruction tests
- Timer
- Interrupt controller
- Memory bus
- Serial I/O
- Functional DMG PPU
- Background, window, and sprite rendering
- OAM DMA
- Pixel FIFO
- Joypad emulation
- Keyboard input in frontend
- ROM-only
- MBC1
- MBC2
- MBC3
- MBC5
- MBC7
- MM01 (not implemented yet)
- Save games supported.
- Sound channels
- Wave pattern generation
- Volume envelope
- Sound output
- Pure Rust frontend
- Uses egui (eframe) for rendering and input
- Pixel-perfect nearest-neighbor scaling
- No native dependencies
- Simple frontend with
egui
- Super Game Boy (SGB) features
- Save states
- Cheats/GameShark
- Rewind
- Customizable keys
You can find release builds here.
Officially supported architectures:
- aarch64-apple-darwin
- aarch64-pc-windows-msvc
- aarch64-unknown-linux-gnu
- x86_64-apple-darwin
- x86_64-pc-windows-msvc
- x86_64-unknown-linux-gnu
To build SturdyGB, you need the Rust toolchain installed. You can install it via rustup.
To build the native desktop application from source, run:
cargo build --releaseYou can run the emulator directly using:
# Run without a ROM
cargo run --release --bin sturdygb_bin
# Run with a specific ROM
cargo run --release --bin sturdygb_bin <rom-name.gb>You can batch-run test ROMs, save their final framebuffers, and generate a report with:
cargo run -p sturdygb --example capture_visual_tests -- --manifest roms/visual-tests.tomlThe manifest supports both explicit cases and directory-based suites, so you can run one ROM at a time or expand an entire folder of related tests with shared stop conditions.
The default manifest includes blargg, acid2, and curated mooneye suites in one aggregate run. Individual suites can write their PNG and metadata files into subfolders under the same output root while still contributing to one top-level summary and HTML report.
By default this writes screenshots and reports into screenshots/visual-tests/:
blargg/,acid2/,mooneye/...: grouped per-case PNG and metadata artifactssummary.tsv: machine-readable batch summaryreport.html: browsable report with embedded screenshots and inline serial or result previews
If a ROM does not reach its configured stop condition within step_limit, the run is still recorded as step-limit-reached so you can inspect the captured state instead of losing the result. For serial-driven ROMs, prefer a serial-based stop condition such as serial-contains or serial-quiet-steps.
SturdyGB can also be compiled to run in a web browser using WebAssembly.
-
Install the
wasm32-unknown-unknowntarget:rustup target add wasm32-unknown-unknown
-
Install
wasm-bindgen-cli: Make sure the version matches the one inCargo.toml.cargo install wasm-bindgen-cli
-
Build the WebAssembly target:
cd crates/frontend cargo build --target wasm32-unknown-unknown --release -
Generate the WASM bindings:
wasm-bindgen --out-dir public/pkg --target web ../../target/wasm32-unknown-unknown/release/sturdygb.wasm
-
Serve the application: You will need a local web server to serve the files in the
crates/frontend/publicdirectory. Assuming you are still incrates/frontendfrom the previous steps:cd crates/frontend/public python -m http.server 8080Then navigate to
http://localhost:8080in your web browser.
The default keys are:
| Key | Action |
|---|---|
| Arrow Up | Up |
| Arrow Down | Down |
| Arrow Left | Left |
| Arrow Right | Right |
| Z | A |
| X | B |
| Return/Enter | Start |
| Space | Select |
You can customize them in the UI (no joypad support yet).
Planned future work includes:
- Pixel-FIFO-based, cycle-accurate PPU
- Correct STAT interrupt edge behavior
- Game Boy Color (CGB) mode
- Debugging tools (PPU viewer, memory viewer, breakpoints)
- Save states
- Libretro core
- Android port (?)
- Customizable keys
- Rewind
This project is based on research and documentation from the Game Boy reverse-engineering community.
Special thanks to the authors and maintainers of:
-
Game Boy opcode tables
https://www.pastraiser.com/cpu/gameboy/gameboy_opcodes.html
https://gbdev.io/gb-opcodes/optables/ -
Game Boy CPU Manual
http://marc.rawer.de/Gameboy/Docs/GBCPUman.pdf -
The Cycle-Accurate Game Boy Docs
https://github.com/geaz/emu-gameboy/blob/master/docs/The%20Cycle-Accurate%20Game%20Boy%20Docs.pdf -
PyBoy documentation
https://github.com/Baekalfen/PyBoy/blob/master/PyBoy.pdf -
Gambatte
https://github.com/pokemon-speedrunning/gambatte-core -
GameBoy-Online
https://github.com/taisel/GameBoy-Online -
Low Level Devel – Game Boy series
https://www.youtube.com/watch?v=e87qKixKFME -
GameBoy Doctor
https://github.com/robert/gameboy-doctor
SturdyGB is an early technical project.
Accuracy, structure, and experimentation are prioritized over performance, UX, or completeness. Expect bugs, missing features, and breaking changes.
Copyright © 2022-2026 Pedrenrique G. Guimarães
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the “Software”), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
The project is licensed under MIT license.