A Game Boy emulator and monster-battling RPG that runs as a Meshtastic module on the LilyGO T-Deck — raise your team, earn badges, and battle other trainers over LoRa radio, no internet required.
Version: pre-alpha · Status: active development — expect bugs and breaking changes.
MonsterMesh turns a LilyGO T-Deck (ESP32-S3 with a QWERTY keyboard, color TFT, SX1262 LoRa radio, and SD card) into a portable Game Boy that also networks with other T-Decks over the Meshtastic mesh — no servers, no internet, just long-range LoRa radio.
It is a fork of the Meshtastic firmware with one extra module (src/modules/monstermesh/). Everything Meshtastic normally does — messaging, GPS, telemetry, the node map — keeps working. Press a key and the same device becomes a Game Boy; the emulator and a full monster-RPG/social layer run alongside the mesh stack.
On top of the raw emulator, MonsterMesh adds a native Generation-1 battle engine, a mesh-wide daycare where your party socializes with monsters on nearby nodes while you're not playing, the "Legend of Charizard" gym-and-badges RPG (eight gyms plus an Elite Four), player-hosted gyms other trainers can discover and challenge over the mesh, and live trainer-vs-trainer battles over the radio.
Fan project / no ROMs included. MonsterMesh ships no copyrighted ROMs or save files. You supply your own legally-obtained Game Boy
.gbROM and.savsave on the SD card. See Legal & trademarks.
MonsterMesh is one game world that runs on three different kinds of hardware. Each lives on its own branch of this repository:
| Platform | Branch | Hardware | What it is | Build |
|---|---|---|---|---|
| T-Deck (this branch) | main |
LilyGO T-Deck (ESP32-S3) | Game Boy emulator + Gen-1 battle RPG + mesh daycare, as a Meshtastic module | pio run -e t-deck-tft |
| Raspberry Pi | mm/monster-mesh-pi |
Raspberry Pi / RetroPie handheld (e.g. GPi Case 2W) | The same RPG/daycare/battle layer as an ncurses terminal (mmd daemon + mmterm), talking to a Meshtastic node over USB |
cmake — see the Pi README |
| Pentest Pikachu | pentest-pikachu |
Heltec V3 / V4 (WiFi) · Heltec T114 (BLE) | Turns the radio into a Pokémon-themed WiFi/BLE security auditor — nearby vulnerabilities trigger monster battles | pio run -e heltec-v3 / -e heltec-v4 / -e heltec-t114-pet |
All three share the same deterministic Gen-1 battle engine and mesh protocol, so T-Deck, Pi, and Heltec players interoperate over the same LoRa mesh. This README covers the T-Deck build.
- Features
- Hardware
- Controls
- Terminal command reference
- Getting started
- Building from source
- Documentation
- Project structure
- Credits & open-source acknowledgements
- Legal & trademarks
- License
- Runs Generation-1 monster games (and other GB/GBC titles) at full speed on the ESP32-S3, powered by Peanut-GB.
- T-Deck QWERTY keyboard mapped to Game Boy controls.
- SD-card file browser to pick a ROM; ROM + battery save (
.sav) load straight from the card. - Sound via on-board I2S audio (minigb_apu).
- Emulator keeps running in the background when you switch back to the Meshtastic UI.
When you're not actively playing, your six party monsters "check in" to a mesh-wide daycare.
- Reads species, levels, nicknames, moves, and XP directly from your Game Boy save (Gen-1 SRAM).
- Broadcasts a compact party beacon over LoRa; nearby nodes become daycare neighbors.
- A dual-layer event generator (hand-written templates + compositional sentence assembly) narrates what your monsters get up to with monsters on other nodes, DM'd to the other trainer's node.
- Friendship and rivalry scores grow between specific pairs across the mesh.
- XP earned in the daycare is written back into your save file (Gen-1 EXP curves + SRAM checksum fix), so progress shows up next time you boot the game.
- 34 achievements, the rare ones broadcast to the whole mesh.
- Optional WiFi-gated weather events and GPS-based day/night events.
See docs/DAYCARE.md.
- A from-scratch C++ Generation-1 battle engine (
Gen1BattleEngine) — type effectiveness, STAB, critical hits, stat stages, and Gen-1's speed-tie and accuracy quirks. - Stats are computed from base stats + level; real movesets are read from your loaded save.
- Deterministic and pure-input so it can run the same battle on two nodes over LoRa by exchanging only the moves, plus periodic state hashes for desync detection.
- Battle data (base stats, moves) is sourced from Pokémon Showdown.
A door-game-style RPG layer built on the battle engine, with state that persists across reboots and resets daily:
- Gyms 1–9 — work through the eight Kanto-style gym gauntlets to earn badges, then take on gym 9: the Indigo Plateau (the Elite Four + Champion).
- Explore — a daily wild-encounter run down a route.
- New Game+ — once you clear the league, the gyms and Elite Four scale up for another loop.
- Persistent badges, a news ring, and per-run stats.
See docs/GAMEPLAY.md.
- MonsterMesh Gyms (
mmg) — host your own party as a gym other trainers can find;mmgdiscovers gyms on the mesh andmmg fight Nchallenges a discovered gym's five-trainer ladder. - MonsterMesh Battle (
mmb) — a live trainer-vs-trainer battle: a DM challenge/accept handshake, then a deterministic networked battle where both sides exchange only moves over the radio. - Local
fight— an instant CPU battle against a nearby trainer's published beacon party (a "mirror match"), no coordination needed.
See docs/MULTIPLAYER.md.
A device-wide theme system: Dark, Light, DMG (classic LCD green), GBC (Color teal), Pocket (high-contrast green), Poke Blue, and Poke Red. Green themes switch the whole UI to crisp Cozette bitmap fonts. Change it from the Meshtastic Settings → Theme dropdown.
See docs/THEMES.md.
- LilyGO T-Deck — ESP32-S3, 16 MB flash, 8 MB PSRAM, 320×240 TFT, QWERTY keyboard, SX1262 LoRa, micro-SD slot, I2S speaker.
- A micro-SD card (FAT32) holding your own
.gbROM and.savsave files. - Two T-Decks (or more) for the multiplayer features.
MonsterMesh only builds for the T-Deck target (-D T_DECK); the module compiles out on every other Meshtastic board.
| Key | Action |
|---|---|
| Ctrl+E (or SYM+E) | Toggle between the emulator and the Meshtastic UI |
| ALT (in Meshtastic UI) | Open the SD-card ROM browser |
| SYM+ALT | Eject the cartridge (pause back to the browser) |
| Mic button | Toggle sound on/off |
| Tools → MonsterMesh Terminal | Open the in-game terminal (RPG / battles / daycare) |
| T-Deck key | Game Boy button |
|---|---|
| W / A / S / D | D-pad (Up / Left / Down / Right) |
| K | A |
| L | B |
| Enter | Start |
| Space | Select |
Open the terminal from Tools → MonsterMesh Terminal in the Meshtastic UI, then type commands. help lists game commands; help sys lists system commands.
| Command | Effect |
|---|---|
party |
Show your party loaded from the save file |
daycare |
Daycare status + neighbor list |
gym |
List the local Kanto gym ladder and your badges |
gym fight <N> |
Challenge gym N (1–9); gym 9 is the Indigo Plateau (Elite Four + Champion) |
explore |
Wild-encounter run on a nearby route |
fight |
Local CPU battle vs a nearby trainer's party |
mmg |
Discover MonsterMesh Gyms hosted by other nodes |
mmg fight <N> |
Challenge a discovered MM gym's five-trainer ladder |
mmb |
List peers currently online for battle |
mmb <peer> |
MonsterMesh Battle — live PvP against a peer |
news |
Legend of Charizard news ring |
achievements |
List achievements you've earned |
| Command | Effect |
|---|---|
version |
Firmware build string |
echo <text> |
Print text |
clear |
Wipe the screen |
beacon |
Broadcast presence (daycare + battle discovery) now |
Pre-built firmware images live in the project's
firmware-builds/archive (namedMonsterMesh-…-app.binfor app-only flashes and…-factory.binfor full images). If you're flashing yourself, see docs/BUILD.md — there are important cautions (never factory-flash a configured node; it wipes WiFi/keys).
- Format a micro-SD card as FAT32 and copy your own Game Boy ROM (
.gb) and its save (.sav) onto it. Insert it into the T-Deck. - Flash a MonsterMesh build (see docs/BUILD.md).
- Boot the T-Deck. It comes up in the normal Meshtastic UI.
- Press ALT to open the ROM browser, pick your ROM — the emulator launches.
- Press Ctrl+E any time to flip between the game and the Meshtastic UI.
- Open Tools → MonsterMesh Terminal and type
helpto start the RPG/daycare/battle layer.
MonsterMesh builds with PlatformIO against the T-Deck environment:
# from the repo root, in a PlatformIO-capable Python venv
pio run -e t-deck-tftFull setup, clean-build, USB and over-the-air (M5/bmorcelli-Launcher) flashing, and the device-UI patch workflow are documented in docs/BUILD.md.
| Doc | Contents |
|---|---|
| docs/ARCHITECTURE.md | How the module is wired into Meshtastic: threads, mode switching, the LoRa channel, SD/SPI hygiene |
| docs/GAMEPLAY.md | Player-facing guide: gyms, Elite Four, explore, NG+, the terminal |
| docs/BATTLE_ENGINE.md | The Gen-1 engine: determinism, desync detection, data pipeline |
| docs/DAYCARE.md | Daycare over the mesh: beacons, events, friendship/rivalry, SAV write-back, achievements |
| docs/MULTIPLAYER.md | mmg player-hosted gyms, mmb live PvP, local fight, the wire protocol |
| docs/THEMES.md | The 7-theme system and Cozette fonts |
| docs/BUILD.md | Build, flashing (USB + OTA), device-UI patches, safety cautions |
| docs/CREDITS.md | Full open-source attributions and licenses |
src/modules/monstermesh/
MonsterMeshModule.{cpp,h} Main Meshtastic module: emulator host, UI/mode switching, LoRa wiring
MonsterMeshEmulator.{cpp,h} Game Boy emulator wrapper around peanut_gb
MonsterMeshFileBrowser.h SD-card ROM browser
MonsterMeshAudio.{cpp,h} I2S audio output
MonsterMeshTerminal.{cpp,h} In-game LVGL terminal + command handler (RPG/battle/daycare)
MonsterMeshTextBattle.{cpp,h} Battle "client": local CPU, gym, explore, and networked battles
Gen1BattleEngine.cpp Deterministic Gen-1 battle resolution engine
Gen1Species.h / PokemonData.h Species name table + party data structures
MeshtasticTransport.h Sends MonsterMesh packets over the Meshtastic mesh
PokemonDaycare.{cpp,h} Daycare orchestrator + beacon broadcast
DaycareEventGen.{cpp,h} Dual-layer event generator
DaycareTypes.h Daycare data structures, beacon format, persistence
DaycareAchievements.h 34 achievement definitions
DaycareSavPatcher.h Gen-1 SRAM read/write, checksum, XP & move patching
DaycareData.h Species profiles (generated from PokeAPI)
LordGyms.{cpp,h} The eight Kanto gym rosters
LordE4.{cpp,h} Indigo Plateau roster (Elite Four + Champion)
LordRoutes.{cpp,h} Wild-encounter route pools for `explore`
LordLogic.{cpp,h} RPG logic: daily reset, run stats, badge/unlock/NG+ rules
LordSave.h RPG persistence (badges, news, stats)
peanut_gb.h Game Boy CPU/PPU/APU emulator core (Peanut-GB)
minigb_apu.{c,h} Game Boy audio processing unit (minigb_apu)
showdown_gen1_basestats.h Gen-1 base stats — generated battle data (gitignored)
showdown_gen1_moves.h Gen-1 move data — generated battle data (gitignored)
patches/device-ui/ Patched into the meshtastic-device-ui library at build time
.../TFT/Themes.{cpp,h} 7-theme color system with cozette-font support
generated/ui_320x240/screens.c themed LVGL screens
generated/ui_320x240/lv_font_cozette_* Cozette bitmap fonts for the green themes
DaycareData.hand theshowdown_*.hbattle-data headers are generated from PokéAPI / Pokémon Showdown rather than hand-edited, and the battle-data headers are gitignored — they're produced as part of setting up a build.
MonsterMesh stands entirely on the work of others. Full license texts and details are in docs/CREDITS.md.
| Project | Used for | License |
|---|---|---|
| Meshtastic firmware | The mesh-networking firmware this is forked from — radio stack, UI, everything non-game | GPL-3.0 |
| Peanut-GB by Mahyar Koshkouei | Game Boy CPU/PPU emulator core (peanut_gb.h) |
MIT |
| SameBoy by Lior Halphon | PPU/timing code incorporated into Peanut-GB | MIT |
| minigb_apu by Mahyar Koshkouei, based on MiniGBS by Alex Baines | Game Boy audio emulation (minigb_apu.c/.h) |
MIT |
| Pokémon Showdown | Gen-1 battle data: base stats and moves (showdown_*.h, generated) |
MIT |
| PokéAPI | Species data used to build the daycare profiles (DaycareData.h, generated) |
data sourced via PokéAPI |
| LVGL | UI toolkit (via Meshtastic device-ui) | MIT |
| LovyanGFX | T-Deck TFT display driver | FreeBSD |
| meshtastic-device-ui | The LVGL UI we theme/patch | GPL-3.0 |
| Cozette by Slavfox | Bitmap font used by the green themes | MIT |
Plus the broader Meshtastic dependency stack (RadioLib, Nanopb, Adafruit drivers, and more) — see each library's own license.
MonsterMesh is an unofficial, non-commercial fan project. It is not affiliated with, endorsed by, or sponsored by Nintendo, Game Freak, Creatures Inc., or The Pokémon Company. "Pokémon", "Game Boy", and related names, characters, and game data are trademarks and copyrights of their respective owners.
- No game ROMs, save files, sprites, or other copyrighted game assets are included or distributed with this project. The emulator runs ROMs you provide yourself, from your own legally-obtained cartridges.
- The Gen-1 battle/species data comes from the open-source Pokémon Showdown and PokéAPI projects and is used for interoperability and gameplay simulation only.
- If you are a rights-holder with a concern about this project, please open an issue.
MonsterMesh is a fork of Meshtastic firmware and is distributed under the GNU General Public License v3.0 (LICENSE), the same license as the upstream firmware. The MonsterMesh module source under src/modules/monstermesh/ follows the same license, except where individual files carry their own SPDX/MIT headers (the Peanut-GB, minigb_apu, Showdown, and font files retain their original upstream licenses — see docs/CREDITS.md).