Open-source project
joamag/boytacean avatar
joamag/boytacean

boytacean: a Game Boy emulator written in Rust for reading, not just playing

A GB emulator that is written in Rust 🦀!

683 stars34 forksRustApache-2.0

At a glance

What is it?
boytacean is a Rust emulator for Game Boy and Game Boy Color hardware with SDL, Libretro and Web front-ends, a PPU that passes the acid2 tests, and a codebase the author explicitly asks readers to treat as educational material.
Who is it for?
boytacean fits a developer who wants to read an emulator written in Rust, to embed a Game Boy core in a Python program or a browser, or to play most Game Boy games from a stable web build. It does not fit a researcher chasing cycle accurate hardware behaviour, a collector needing the Game Boy Camera, or a user expecting netplay between two machines, since all three are listed as still missing.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 17 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The author asks you to treat this as a teaching project

boytacean is a Game Boy emulator written in Rust, and the project description leads with that fact rather than with a feature list. The README is unusually direct about intent: the emulator has been written for educational purposes and should not be taken too seriously, while adding that it does play most Game Boy games.

That framing explains a lot about the repository shape. The top level is a Cargo workspace with a root crate, a crates/ directory holding common, encoding and hashing sub-crates, and a frontends/ directory with console, libretro and sdl members. There are benches/, examples/, build.rs and a doc/ folder, plus setup.py and requirements.txt for the Python binding. A project built to be read tends to have the emulator core separated from the presentation layer, and that is what the workspace layout shows.

The audience is therefore two groups at once. One group wants to run games, and the web deployment at boytacean.joao.me is a stable, public build. The other group wants to understand how a Game Boy is emulated in a modern systems language, and for them the source and the examples/ directory are the real product.

DMG and CGB coverage, four memory bank controllers, and a link cable

The hardware surface covered is broad for a project of this age. Both Game Boy (DMG) and Game Boy Color (CGB) are emulated, and the memory bank controllers list includes MBC1, MBC2, MBC3 and MBC5, which is what lets games with large save regions work at all. Serial Data Transfer, the link cable feature, is supported, and so is Game Boy Printer emulation, which is a less common target and shows the serial port is treated as a real peripheral rather than a stub.

Audio is present with what the README calls a pretty accurate APU, and there is an optional high-pass audio filter with three settings: Preserve, Accurate or Disabled. The filter choice exists because the real hardware output is not the same as the ideal signal, and different users want different compromises.

Two features are aimed squarely at people who move between emulators. Save states use the BESS Specification, which the README names as a way to stay cross-compatible with other emulators. Cheats can be entered with Game Genie and GameShark codes. The variable CPU clock speed is a third practical item, letting a slow or busy scene run at a different rate than a real Game Boy would allow.

The web build adds transparent RAM saving through the Web Storage API, GamePad support through the Web Gamepad API, rumble and haptic feedback, an on-screen gamepad, custom display palettes, a fullscreen mode, and a debug mode showing VRAM and registers.

The PPU passes the acid2 tests, and full cycle accuracy is still missing

Accuracy is claimed in a narrow and checkable way. The README states that the PPU is accurate and passes the dmg-acid2 and cgb-acid2 tests, the well known homebrew ROMs that exercise picture processing edge cases. Naming the test suite matters, because it converts a marketing adjective into something a reader can look up and judge.

The same honesty runs the other way. The list of what is still missing starts with low-level cycle accurate system emulation, followed by Game Boy Camera emulation and NetPlay gaming support. The first entry is the one that constrains expectations most. Without cycle accurate behaviour, the emulator reproduces what games look and sound like rather than what the hardware does at instruction granularity, so timing sensitive software and homebrew that depends on precise bus behaviour are the weak spots.

The absence of NetPlay is the practical one for anyone who wants to use the link cable feature across two machines. Serial support exists inside a single process, but there is no networking layer to join two emulators, so that feature is currently local only. The Game Boy Camera gap is narrower, since it affects a small number of cartridges.

SDL, Libretro and the browser are three different ways in

The front-end choice is the main decision a user makes, and the three options differ in approach rather than in features. The SDL front-end is a standalone desktop window that talks to the emulator library directly. The Libretro front-end exposes the same core through the Libretro interface, which is how an emulator core gets loaded by a host that already manages controllers, memory cards and video output. The web front-end is built on EmuKit, a UI toolkit the author also maintains specifically for emulation interfaces in a browser.

That middle option is worth a paragraph of its own. Running the same Rust core inside a host that already handles the surrounding duties means you inherit that host's input mapping and configuration conventions, and you avoid writing a front-end at all. Someone who wants the emulator as a component inside an existing setup has a different reason to prefer boytacean than someone who just wants a window on their desktop.

The web deployment table lists several Cloudflare hosted builds with a Stable column: boytacean.joao.me, boytacean.pages.dev, prod.boytacean.pages.dev and stable.boytacean.pages.dev are all marked stable, while master.boytacean.pages.dev is not. The separation between a stable URL and a master URL means you can follow development without it touching the address your bookmarks point at.

Building the Rust library, the Python binding and the WASM targets

The core builds as a normal Rust library, and Cargo.toml declares the crate type as both cdylib and rlib, which is what allows the same code to be linked into a shared object for a Python extension or a WASM module and also used as a normal Rust dependency. The Rust edition is 2021 with a rust-version floor of 1.86.0.

The library build is one command:

bash
cargo build

The Python distribution is built from setup.py, which uses setuptools-rust with a PyO3 binding under the name boytacean.boytacean, and it pulls in setuptools-rust, wheel and pillow as build requirements:

bash
pip install .

The README also lists the older invocation, python setup.py install, as an alternative. setup.py will install setuptools and setuptools-rust on the fly if they are missing, so a clean Python environment works without a separate dependency step.

For the web target, the build needs wasm-pack and a feature flag. The Node.js variant and the browser variant differ in target and output directory:

bash
cargo install wasm-pack
wasm-pack build --release --target=nodejs -- --features wasm
bash
cargo install wasm-pack
wasm-pack build --release --target=web --out-dir=frontends/web/lib -- --features wasm
cd frontends/web
npm install && npm run build
cd dist && python3 -m http.server

The final command serves the built site locally, which is how you can check your own build before deploying it to Cloudflare.

Feature flags and a workspace split into common, encoding and hashing

The Cargo features section shows how the same source targets very different environments. The default is empty, and each capability is opt-in:

toml
[features]
default = []
wasm = ["wasm-bindgen", "js-sys", "boytacean-common/wasm"]
python = ["pyo3", "boytacean-common/python"]
simd = ["boytacean-encoding/simd", "boytacean-hashing/simd"]
debug = []
pedantic = []
cpulog = []
profile = []
gen-mock = []

The simd flag is worth noting because it propagates into the encoding and hashing sub-crates rather than switching a single module. The crate also carries a cpulog feature, a profile feature and a gen-mock flag, which read as instrumentation and test scaffolding rather than user features.

The release profile is tuned hard, with link time optimisation on, opt-level 3 and codegen-units set to 1, and there is a separate release-safe profile that inherits from release but keeps debug information. Debug info in a safe build is a deliberate choice for a project that wants to be profiled and read.

The workspace members are the root package, frontends/console, frontends/libretro, frontends/sdl, crates/common, crates/encoding and crates/hashing. That split is the structural answer to the question of where the emulation logic ends and the presentation begins.

Three releases on a single day, and a push on 2026-10-06

The repository is not archived, and the last push was on 2026-10-06. The release list is unusual: 0.13.0, 0.13.1 and 0.13.2 were all published on 2026-07-27, within about forty minutes of each other, which reads as a batch of fixes cut and tagged together rather than a cadence of separate features. The current version 0.13.2 appears in both Cargo.toml and setup.py, so the Rust crate and the Python package are released in step.

Deployment is not left to the maintainer alone. The repository has a .github/ directory and a .gitlab-ci.yml, so there are two CI configurations, and the README carries build badges for the GitHub workflow, crates.io, npm and PyPI. The crates.io, npm and PyPI badges matter for anyone consuming the project as a dependency, since the Rust crate, the JavaScript package and the Python package are all published.

Licensing is Apache-2.0, with the licence file in the repository root and the same terms declared in the package metadata. A CHANGELOG.md is present for release history, and CONTRIBUTING.md collects outside contributions, including translation of the Chinese and other localised documentation.

Editorial conclusion

boytacean fits a developer who wants to read an emulator written in Rust, to embed a Game Boy core in a Python program or a browser, or to play most Game Boy games from a stable web build. It does not fit a researcher chasing cycle accurate hardware behaviour, a collector needing the Game Boy Camera, or a user expecting netplay between two machines, since all three are listed as still missing. Before you depend on it, check the version 0.13.2 release, the rust-version 1.86.0 floor in Cargo.toml, and the specific front-end you intend to use, since the Web, SDL and Libretro builds are separate targets with separate build steps.

Frequently asked questions

How do I build boytacean from source?

Run cargo build in the repository root to build the Rust library. The crate type is declared as both cdylib and rlib, so the same core can be used as a Rust dependency or linked into a shared object.

Can I use boytacean from Python?

Yes. The project ships a setup.py that builds a PyO3 extension named boytacean.boytacean through setuptools-rust, and pip install . installs it. The python feature flag in Cargo.toml activates the pyo3 binding.

Which front-ends does boytacean provide?

The project lists Web, SDL and Libretro front-ends, with the web version built on the EmuKit UI toolkit. The workspace also lists a console front-end as a workspace member.

How accurate is the boytacean PPU?

The README states that the PPU is accurate and passes the dmg-acid2 and cgb-acid2 tests. Low-level cycle accurate system emulation is listed as still missing, as are Game Boy Camera emulation and NetPlay support.

How are boytacean save states shared with other emulators?

Save states use the BESS Specification, which the README points to for cross-compatibility with other emulators. Cheat codes in Game Genie and GameShark formats are also supported.

Official sources

  1. joamag/boytacean on GitHub
  2. License: Apache-2.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/joamag-boytacean.svg)](https://hysenlabs.com/projects/joamag-boytacean)

Was this useful?