* Use spare CPU cores to remove in-game hitches on low-power devices Per-frame game logic and drawing are cheap; the remaining stalls on low-power handhelds are one-off main-thread hitches from chip SFX/cry synthesis, RED++ atlas recolouring, image decodes and the require shim. Move those onto background threads, each with a synchronous fallback so behaviour is identical when threads are unavailable (POKEPORT_NO_THREAD=1, no love.thread, worker failure). Also adds an F3 frame-time overlay and POKEPORT_GAME_PROF headless profiling to measure these costs. * Address code review: shared WorkerLane, F3 gating, decode/epoch fixes - Extract src/core/WorkerLane.lua (worker lifecycle, prioritised lanes, per-lane epochs, bounded LRU) and rebuild the SFX and atlas/decode prefetchers on it - Keep decoded sprite sheets in every colour mode (the OBJ palette bake re-reads them), skip oversized decodes, and let palette changes drop only atlas bakes - Only bump the SFX render epoch when the channel mix actually changes - F3 overlay toggle no longer steals the key from rebinding screens or player bindings; profilers stop only when a quit really proceeds - Require fast path: test hook instead of a hot-path counter - Shared tests/drivers/perf_util.lua; drivers restore their patches * WorkerLane: no budget leak on duplicate sends, keep priority on requeue - Lane:pump only counts a job against the in-flight budget once per key - requeueInflight puts entries back at the head of their own queue, so background hints no longer overtake front requests after a bump - shutdown() keeps a fatally failed worker off - Hiding the F3 overlay logs one summary line instead of a full block * F3 overlay: last-120-frame stats, font-sized box, scale on large screens * Prefetch: skip useless hints, no main-thread fallback, mix check vs worker config - Don't queue decodes for sprite sheets whose Image and OBJ bake are cached - Atlas hint is dropped (sync bake at build time) when the worker can't decode the tileset itself, instead of decoding on the main thread - SFX epoch bump compares the live mix with what the worker was last configured with, replacing the load-time snapshot * Sprite decode skip: raw-path cache check, never under RED++ * Gen 2 battles prefetch both parties' cries; sprite skip keyed by raw path * Prefetch: skip cached tilesets outside RED++, log hint failures once * Profiler: bench survives F3 hide, frame total excludes vsync; safer SFX pump, ordered requeue, tileset skip respects pending variants * Profiler counts GPU stalls in present; water void-fill keeps tileset hint; README + test coverage * Profiler vsync cap: measured cadence via RefreshRate, no per-frame allocation * Use upstream's chip-worker prewarm for SFX/cries; drop our separate SFX worker Our extra coverage (Gen 1 common SFX + party cries, both parties' battle cries, lead move sounds, hit and battle SFX, Gen 2 bench cries) now goes through ChipAudio.prewarmSfx/prewarmCry and a new Sound.prewarmMove. * Skip decode hints for composed assets; share move cache key; drop dead demoteAll * Drop dev-only profiling extras: POKEPORT_JITP hook and perf drivers * README: name the worker threads POKEPORT_JIT leaves alone * Profiler: count the pre-present vblank wait as present, log on NX quit - time PresentSync.waitBeforePresent as "present" (the X11 GLX vblank wait lands there), so it is excluded like the wait inside present - NX quit now emits the PROF summary / overlay line too - love.quit's scripted check reads FrameProfiler.benchRequested, so POKEPORT_GAME_PROF=0 no longer counts as a bench run - prefetchAtlas skips composed tileset sheets (Assets.isComposed) - hit sounds defined once in EffectRegistry.HIT_SOUNDS, shared with the battle prewarm (each hit still gets its own copy) - drop redundant obpPaths, dead FrameProfiler.visible and the unused Lane:bump requeue mode; restore applyOptions' doc comment
G1R Deluxe aka Gen1Recomp
A native LÖVE2D recreation of Poke Red, Blue, Yellow, Gold, Silver, Crystal, FireRed, LeafGreen, Ruby, Sapphire, and Emerald. The engine and map behavior are hand-written Lua; game data and graphics are decoded from a ROM supplied by the player.
And before you say, "that's not a recomp", you're wrong. Recomp is an acronym. Reverse Engineering Causes Obsessive Mental Problems
Click Here for the AI Use Disclosure!
Caution
We are NOT affiliated with the website
gen1recomp[.]comThat website is not run by this project, was not authorized by us, and we have no idea who operates it. It is impersonating this project; do not download anything from it, and treat anything it hosts or claims as untrustworthy. Even if the site currently links back to this repository, the people behind it can change its content at any time, so nothing on it should ever be trusted. This GitHub repository, the Discord, and https://gen1re.com are the only official sources for this project. Also, as I assumed would eventually happen, the idiot that made that website now pumped it full of adware. Please stay away from that website.
SUPPORT / ANNOUNCEMENTS / MODS ALL FOUND ON THE DISCORD
Watch the latest update video
What this is
G1R Deluxe aka Gen1Recomp is a native LÖVE2D recreation of Pokemon Red, Blue, Yellow, Gold, Silver, Crystal, FireRed, LeafGreen, Ruby, Sapphire, and Emerald. The engine and map behavior are hand-written Lua, ported from the pret disassemblies & C. Game data, graphics, and audio programs are decoded on first launch from a ROM you supply.
The project does not include a ROM, emulate the Game Boy, transpile assembly, or download a disassembly. Your ROM is verified, used during import, and released from memory. It is never copied into the cache, and later launches load the private generated cache without asking for it again. Music, sound effects, and cries are synthesized while the game runs. All eleven games can be imported side by side. Gen 2 support is still under construction.
Quick Start
- Download the build for your platform from the latest release.
- Launch it. The packaged app contains no ROM and no game data, so the launcher will ask for one.
- Choose your legally obtained
.gb/.gbc/.gbafile, a.zip/.7zthat holds one (offered only where your platform's build supports archives), or drop it onto the window. Import takes a few seconds and the game starts automatically. - Repeat for any other game you own. Each one gets its own tab in the launcher.
Only the canonical US English ROMs below are accepted. The importer checks the SHA-1 before creating any game data. FireRed, LeafGreen, Ruby, Sapphire, and Emerald support is in beta.
| Game | Revision | ROM size | SHA-1 |
|---|---|---|---|
| Red | - | 1 MiB | ea9bcae617fdf159b045185467ae58b2e4a48b9a |
| Blue | - | 1 MiB | d7037c83e1ae5b39bde3c30787637ba1d4c48ce2 |
| Yellow | - | 1 MiB | cc7d03262ebfaf2f06772c1a480c7d9d5f4a38e1 |
| Gold | - | 2 MiB | d8b8a3600a465308c9953dfa04f0081c05bdcb94 |
| Silver | - | 2 MiB | 49b163f7e57702bc939d642a18f591de55d92dae |
| Crystal | 1.0 | 2 MiB | f4cd194bdee0d04ca4eac29e09b8e4e9d818c133 |
| Crystal | 1.1 | 2 MiB | f2f52230b536214ef7c9924f483392993e226cfb |
| FireRed | 1.0 | 16 MiB | 41cb23d8dccc8ebd7c649cd8fbb58eeace6e2fdc |
| FireRed | 1.1 | 16 MiB | dd5945db9b930750cb39d00c84da8571feebf417 |
| LeafGreen | 1.0 | 16 MiB | 574fa542ffebb14be69902d1d36f1ec0a4afd71e |
| LeafGreen | 1.1 | 16 MiB | 7862c67bdecbe21d1d69ce082ce34327e1c6ed5e |
| Emerald | 1.0 | 16 MiB | f3ae088181bf583e55daf962a92bb46f4f1d07b7 |
| Ruby | 1.0 | 16 MiB | f28b6ffc97847e94a6c21a63cacf633ee5c8df1e |
| Ruby | 1.1 | 16 MiB | 610b96a9c9a7d03d2bafb655e7560ccff1a6d894 |
| Ruby | 1.2 | 16 MiB | 5b64eacf892920518db4ec664e62a086dd5f5bc8 |
| Sapphire | 1.0 | 16 MiB | 3ccbbd45f8553c36463f13b938e833f652b793e4 |
| Sapphire | 1.1 | 16 MiB | 4722efb8cd45772ca32555b98fd3b9719f8e60a9 |
| Sapphire | 1.2 | 16 MiB | 89b45fb172e6b55d51fc0e61989775187f6fe63c |
Platform notes: Linux, iOS, Xbox Dev Mode, handhelds, Nintendo Switch, and PlayStation 4 each have their own install steps.
Windows Defender: it sometimes flags the Windows build with a generic
detection such as Trojan:Win32/Wacatac!ml (#621). This is a known false
positive: the exe is the official LÖVE runtime with the game archive appended,
and Defender distrusts unsigned executables with appended data. Every release
publishes sha256sums.txt so you can verify your download, and you can check
a flagged file on VirusTotal.
Controls
| Action | Keyboard | Controller |
|---|---|---|
| Move | Arrow keys / WASD | D-pad / left stick |
| A | Z / Enter / Space | A |
| B | X / Backspace | B |
| Start | Escape | Start |
| Select | Tab / Shift | Back / Select |
Rebind any of these in-game under OPTIONS > CONTROLS.
| Key | What it does |
|---|---|
- / = |
Zoom out / in (overworld; also mouse wheel) |
1 / 0 |
GAME SPEED up / down (controller: R2 faster, L2 slower) |
2 |
Cycle COLORS |
3 |
Cycle TILT (free-roam overworld) |
4 |
Cycle ZOOM through every level (free-roam overworld) |
F1 |
Save |
F2 |
Load |
F10 |
Open / close the mod manager |
COLORS, TILT, ZOOM, SHADER FX, GAME SPEED, and VOID FILL are also in the
Options menu and persist in options.lua.
Low-end devices: OPTIONS > PERFORMANCE scales the optional extras for weaker hardware (HIGH, BALANCED, LOW, or AUTO, the default). It only changes presentation; game logic is identical on every tier. Details in docs/new-features.md.
Documentation
Everything else lives in the docs folder or on the project wiki, which has the modding book, link play, save editor, and developer setup guides:
- Rulesets: faithful Gen 1 quirks or modern cleanups
- Online play: lobby, battles, tournaments, trading
- Launch options: one-click shortcuts and URLs
- Portable mode: run from a USB drive
- Running from source
- Modding: mod platform, example mods, Tiled map editing
- Architecture
Measuring frame time
Press F3 in a running game to toggle a small frame-time overlay (FPS,
per-section update/draw/present timings, Lua heap, draw calls, texture
memory). It is off by default and costs nothing when hidden. Set
POKEPORT_GAME_PROF_OVERLAY=1 to start with it shown. For a headless
measurement set POKEPORT_GAME_PROF=<frames>: after a 60-frame warmup and
<frames> recorded frames it prints a PROF ... summary to stderr and quits.
POKEPORT_GAME_PROF=all records until the game quits and then prints the
summary, which also lists the worst spikes (over 16.7 ms) with the
per-section cost and the screen/map they happened on. The frame figure and
the spike threshold are work time: the vsync wait in or just before present
(up to one display refresh) is excluded, so an idle frame reads well under a millisecond
while a GPU stall in present still counts. The launcher is never profiled.
POKEPORT_JIT=0 turns the LuaJIT compiler off (prints [info] jit off), to
approximate low-power devices that run Lua without it. It affects only the
main Lua state; worker threads (music/SFX and the atlas/decode worker) keep
their JIT.
Bugs
Found a bug? A warp dropping you somewhere it shouldn't, a battle doing math that looks wrong, text in the wrong box, anything that does not match the original game. Open a bug report. Attach a screenshot if you can. It saves a lot of back and forth, and if you can't get one, the form asks you to describe what you saw instead.
License
See LICENSE.MD.
Special Thanks
This project would not be possible without pret > the pret band of decompiling maniacs > and their pokered disassembly.

