Retro Boy: simple Game Boy emulator written in Rust, can be played on the web
107 comments
·March 20, 2025zeta0134
diggan
> I hear a few problems with the audio emulation, (mostly clicks that shouldn't be there)
Almost anything WASM+Audio seems to do that in browsers today, unless you're really really careful about what you're doing and leverage multiple threads. I think the issue is mostly around single-thread contexts, where it has to switch between playing audio and other things.
I hit the very same issue myself with Bevy not too long time ago, and tracking this issue which has some further links if you wanna go down a rabbit-hole: https://github.com/bevyengine/bevy/issues/4078
samiv
I've had the same issue in my engine.
What I've found is that essentially WebAudio has such a terrible performance that the audio buffers need to be at minimum 100ms. And if you have a bad frame or any jank in your RAF is likely to glitch at least occasionally.
Compare this to when running natively 20ms audio buffers are fine.
I've settled on a design where I run all the audio graphs and audio decoding in a separate thread and then queue the audio buffers for the main JS thread to pick up and make the WebAudio calls. The same has to be done for the graphics (WebGL) as well. This can be major paradigm shift if the initial design has been done around doing stuff independently on the background. On the web.. no can do.
Bonus tip, if you're planning to use the OpenAL implementation that Emscripten provides my only advice is.. don't.
2c2c2c
i combed through quite a few hobbyist gb emulators while writing mine and found audio to be pretty rarely finished or finished without issues. not sure if it's the same for NES
zeta0134
Audio is *surprisingly* tricky on both platforms. NES has DPCM, which cheerfully interrupts the CPU and causes untold issues with controller reading. Gameboy has envelopes that are semi-required with phase-resets, and a wave channel which you in theory cannot write new samples to, and developer hacks to work around both. Both systems have various hardware revisions that have subtly different behavior, and a handful of games that will break on that specific model. It's fun!
gblargg
It's also more involved to verify operation. Graphics are easier to "measure" and compare. Sound is also much more timing-dependent, e.g. when timers are running on their own all the time. It's disconcerting when sound is slightly off in games.
jvanderbot
Enthusiast noob question. What do you use for display / rendering / gui when doing emulators for wasm?
zxvkhkxvdvbdxz
Wasm executes as its own VM, so you'll need some js glue to display something in the browser.
This means you can go both ways, either embed something like imgui in your wasm, or build a ui using html.
darknavi
Or go full circle and use something like GameFace to render react in your app, in the browser!
maybeOneDay
Tangentially related - I recently picked up a retro gaming handheld from Aliexpress for the meagre sum of £50, which is capable of playing consoles from gameboy to snes to playstation 1, and apparently even a smattering of N64 and dreamcast (with poor performance).
There are a dizzying array of options (game boy form factor, horizontal, clamshell design ala the advance SP), and although I'm sure the build quality leaves a lot to be desired, for my personal circumstances of "I'm travelling a lot but can't quite justify a steam deck right now" it has truly been an utter delight. There's a scene of various custom firmwares to install, and apps for these firmwares to add various functionality.
I'd encourage anyone who feels a desire to play some emulated games check out /r/SBCGaming to see what's out there!
Just don't ignore the warnings that these devices don't negotiate USB C charging correctly, and also buy yourself a very small weak charger...
fernandotakai
if people want more info on these devices, russ from retro game corps does a ton of reviews on them, from the cheapest (that are less than 30 euro) to the really expensive ones (600+!).
i myself own a retroid pocket 5, one trimui brick (which my wife adores) and a steam deck (yes, it's an amazing retro gaming machine).
(retro catalog also has a ton of technical information, including ratings)
tracker1
Thanks for the share... been using a Beelink SER8 for about 6 months or so with Chimera, which has been mostly okay... I have to reset audio out to hdmi each boot and a couple other niggles with the Bluetooth controllers. May need to switch to ones that use custom/proprietary USB dongles with lower latency.
jcjmcclean
Hi there! I'm running the exact same setup and have encountered the same issues.
I have a little bash script [1] which I run on startup to fix the HDMI audio issue. I haven't got crontab working yet so I ssh in and run it manually.
I've tried 3 different controllers and ended up buying the 8bitDo ultimate as it supports 2.4g as well as Bluetooth. Also purchased a separate Bluetooth dongle and a usb extension cable to keep it away from any interference from the Beelink. Still have major issues with connectivity over a reasonably short distance (3-4m) in either mode.
Love the SER8 though, it's a great little machine and is well priced when on offer.
[1] https://gist.github.com/jcjmcclean/a59362a01a7f421e4fa020823...
drakythe
+1 for Retro Game Corps, not only are his videos well made and informative he puts together guides for everything from basic retroarch configuration to how to install alternative OSes for specific devices (and why you might want to do that).
criddell
I bought an Analogue Pocket which sounds similar to what you have and I've found the games... underwhelming. I've tried a lot of games (the internet archive has them for some reason) and the only ones I've wanted to play more than once is the original Tetris and a game I don't remember the name of but it has numbers at the top and sides which you use to deduce which cells are on and eventually you reveal a pixel image.
I never had one of these devices while they were current which makes me wonder if the key ingredient to enjoying one is nostalgia?
I also have a Sony PSP (bought around 2010) which is a great bit of hardware, but I have yet to find a game that appeals to me.
tracker1
I've had the best luck with the Argon USB C power supplies for RaspberryPi 3/4 connected to USB/SATA adapters with SSDs. Most other power supplies I've tried get low power warnings constantly. The inline power switch is cool to, though less useful with the cases I've used.
Keyframe
Miyoo Mini Plus. It's fantastic!
maybeOneDay
Nice! I went for the Anbernic 40xxH and it's a joy to use. The only thing I wish worked differently was Retro Achievements working offline!
smparsons
Hi guys, original creator of the emulator here. I am shocked by how much attention my little hobby project is getting. Thanks for the support.
yoyohello13
Thanks for posting this! Your repo is very nicely organized.
I've been wanting to get in to making an emulator (chip8). I decided early I wanted it to run on wasm, but have been stuck in the weeds of what framework/tools to use to actually get it done. I've looked into game engines and egui, but they just add so much extra complexity.
I think seeing your repo I'm just going to try the straight wasm-bindgen + canvas route. So thanks again for making this.
smparsons
Actually I didn't post this on HackerNews. Somebody else did. But I'm glad to hear you got inspiration from my emulator. Yeah I found wasm-bindgen pretty easy to use.
rollcat
I feel like the GB/GBC/GBA are pretty much what the VT102 is to writing grid-cell software. The demo scene keeps cranking. Chiptune is still in love with the hardware - especially with the OG DMG, with a pro sound mod. Writing new software for the GBA feels a lot like targeting a tiny, modern ARM microcontroller. The hardware is well documented and understood by the enthusiasts, and it's a stable target.
Plus there are plenty of emulators focusing on different aspects: one is focusing on perfect emulation; another will try to squeeze out performance; another might offer memory inspection and "cheat codes"; this one makes it available on the web. There's beauty in all of that.
araes
List of links and support documents for those interested in Gameboy Development (and example Homebrew ROMs)
Gameboy Dev: https://gbdev.io/
PanDocs (tech reference): https://gbdev.io/pandocs/
Gameboy Tech Ref Doc (gekkio): https://gekkio.fi/files/gb-docs/gbctr.pdf
Game Boy Development Kit 2020 (GBDK-2020) Reboot: https://gbdk-2020.github.io/gbdk-2020/docs/api/
GBDK-2020 Github: https://github.com/gbdk-2020/gbdk-2020
GBDK-2020 Examples: https://github.com/gbdk-2020/gbdk-2020/tree/develop/gbdk-lib...
GBDK Showcase (Homebrew Software): https://gbdk-2020.github.io/gbdk-2020-gallery/
Homebrew Hub: https://hh.gbdev.io/
Neil Young Album (Silver & Gold) with Cover Image produced using the Gameboy Camera: https://en.wikipedia.org/wiki/Silver_%26_Gold_(Neil_Young_al...
GaggiX
Fun fact the emulator works fine on Ladybird too, even thought it's very slow now.
noeatnosleep
Avid millennial gamer here. Wasn't raised with games. Can someone recommend a good classic game to try?
s369610
Kirby's Dream Land is pretty fun too (esp after watching https://www.youtube.com/watch?v=PBRt2D2YN44 which is where the creator talks about the concepts of the game)
bityard
I always played games growing up but didn't play Kirby until much later in life. Kirby is easily my favorite platformer, even ahead of Mario and Sonic. I wish there were more like it.
frosting1337
Pokemon - Red/Blue or Gold/Silver, and Legend of Zelda: Links Awakening.
matcha-video
seconded! I also enjoyed Zelda: Oracle of Ages / Seasons
aussieguy1234
The game boy Tetris was the first version I played, it was pretty good.
Nowdays for a mobile Tetris option i'm using a SNES emulator on my phone (Snes9x EX) and Super Tetris.
Meanwhile, there are companies creating on the web and mobile app versions of Tetris, inserting ads and charging money for what should be free.
coldpie
Super Mario Land is a good place to start. The music is great, and it is very short and pretty easy.
Link's Awakening is my favorite Zelda game.
The original Pokemon games (Red/Blue, Gold/Silver) that others are recommending are pretty rough these days, but it's fun to see where it all started if you have the patience for them.
If you want something a little less well-known, Bubble Ghost is a fun little puzzler.
Regardless of what you try, remember that this is the era when game manuals were required reading since they rarely were able to fit tutorials & instructions in-game. It's good to scan through the manual first before you play something or you might be missing some critical information.
gwbas1c
Super Mario Land, 1 and 2. Dr. Mario.
Game Boy games tended to be limited due to space constraints.
lxgr
There are definitely limitations, but later games have a lot more depth than these.
Link's Awakening feels like it shouldn't be possible in a single megabyte of mask ROM, for example. The fact that it was makes it almost more impressive by today's standards.
djtango
Games back then were a bit of a dark art...
I feel like I don't really encounter stories of heroics in making games work on their hardware anymore. Even at the end of PS1 with Final Fantasy their hand drawn backgrounds were too big to fit into VRAM iirc
Or in the PS2 era Jak and Daxter using the principle of hot reloading from lisp to figure out open worlds without loading screens
RetroSpark
> Link's Awakening feels like it shouldn't be possible in a single megabyte of mask ROM
Half a megabyte, even! (For the original monochrome game - the later color version is a full megabyte.)
xtracto
I has SML 1 and OperationC in the original game boy. Such great games. Also links awakening!!
999900000999
Tetris or Pokemon Red.
Pokemon is actually a really difficult game before modern QOL. No DLC!
Xenoamorphous
For the original GameBoy, without a doubt: Zelda Link's Awakening.
kibwen
But get the DX edition for the GBC.
patrickcorrigan
Really love seeing more Game Boy emulators written in Rust, especially with browser support — awesome project!
If you're into this space, I’ve been building https://afterplay.io — a browser-based retro gaming platform with support for a bunch of systems (GB,GBC, GBA, SNES, NDS, PS1, etc). It runs entirely in the browser with save states, cloud sync, and native mobile support via Capacitor.
Also has some fun stuff like netplay (multiplayer over the web), Link Cable Support and RTC manipulation, and customisable touch controls.
Always exciting to see more emulators pushing what’s possible on the web.
ericzawo
I remember being 7 years old figuring out how to unzip the no$gbemulator to play Kirby and Final Fantasy Adventure on my dad's Windows 95 laptop. Good times.
pests
Same, first emulator I ever used, maybe a little after you (Windows 98)
The ability to speed up time made leveling up pokemon so much easier back in the day. Walking back and forth in the grass.
Also my first introduction to save states outside the game itself / quick loading.
shaoner
It's been a while since I touched it but I have a very similar GB emulator in rust:
- The library: https://github.com/shaoner/padme-core
- The web/wasm backend: https://github.com/shaoner/padme-browser
catapart
It plays really slow in Firefox, and there are also audio issues (they may be related?)
But in Chrome, this plays really well! Great work!
shakna
WebRender recently got much slower in Firefox [0].
I haven't looked at the source yet, but if the bitmaps aren't all preallocated, then it'll run into this repeatedly.
[0] https://treeherder.mozilla.org/perfherder/graphs?highlightAl...
adrian17
For me it runs at full speed in both stable and developer versions of Firefox (but even then, audio is bad at times). But still, I looked at performance out of curiosity.
After running it under FF's profiler for a moment, it looks like a sync executed after every opcode recalculates the framebuffer (`step_until_next_audio_buffer -> cpu::microops::read_byte_from_memory -> emulator::sync -> gpu::scanline::write_scanlines`) and uploads it to the canvas with `putImageData`, which takes ~35% of execution time. Sounds like that could be redundant work, since I'm pretty sure the canvas isn't actually redrawn until the wasm execution yields back to the browser.
EDIT: also, the emulator can't really be ran in debug mode, since 1. it blows the wasm stack (presumably when creating the huge `Emulator` struct, a not uncommon issue in Rust; I had to hack in bigger stack size with linker args), and 2. is panics on int overflows `apu::step`.
catapart
Yeah, still being on Windows 10, I almost didn't put the complaint in the comment. Lots of reasons it might just be an environment issue for me.
But, in my development experience with firefox, the issues it seems to have always seem performance related (or compliance with web standards related), and I figured that even if others weren't seeing the issue, there was still probably something underlying that could be figured out. So thanks for going through the debug! It's nice to know that there may be an optimization available for the project, and it feels like it might even be an additional performance gain for chromium, if I'm understanding you right? Might be some reason they need to do that sync after every opcode, but I agree with your suspicion that the canvas is probably being over-rendered to.
adrian17
FWIW, the thing I've found as the slowest single factor on my machine, might not be the slowest on yours; I might have not noticed the real cause of slowdowns on your machine at all, and you may be the only one able to diagnose it.
(and for the record, I'm on W10 too.)
Also, my personal experience from optimizing https://ruffle.rs/ is that in many cases Firefox's wasm runtime can behave slightly faster than on Chrome for some reason; and performance issues are often instead caused by other APIs like the canvas.
tonyhart7
ofc it is firefox
ShinTakuya
Can I inquire as to why you feel so negatively about Firefox?
tonyhart7
burn a lot of fcking goodwill for measly 4% web user, turn out eating google money literally make you the next "google"
chromium edge literally surpass firefox and with new policy it would eat more to the marketshare
d3k
Nice! it reminds me of a very similar project a friend of mine did like 10 years ago https://github.com/simias/gb-rs
This is awesome! Very nicely done. I hear a few problems with the audio emulation, (mostly clicks that shouldn't be there) but it's been a long while since I had my head wrapped around Gameboy emulation. I'm not sure I know what's going wrong exactly.
I love how Rust+WASM is an enabler for showing off applications like this which would traditionally be restricted to a desktop environment. Here's my own, an NES emulator, using wasm-bindgen for the translation but otherwise a similar setup:
https://rustico.reploid.cafe/?cartridge=patreon/tactus-v0.7-...
It's so cool to work on a bit of homebrew, then be able to share a link with someone and have it "just work" in their browser. No weird tools, no shady sites, just my game and their feedback.