On a window too short for the stacked single-column layout -- a phone, or a narrow desktop window -- the ROM / SAVE FILES / Play / SAVE SLOT stack ran past the bottom of the window while the footer stayed pinned there and drew over it. Nothing clipped the panel and nothing scrolled it, so the overflow was unreachable. Everything under the tab bar (panel, updater banner, footer) is now one scrolling column, used only when it is taller than the room below the tab bar. The strip, logo and tab bar stay pinned, so navigation is always on screen, and the footer is laid out downward from footerTop right after the content instead of upward from the window bottom. - RomImporter.pageScrollFor is the whole decision, pure and covered by tests/engine/launcher_page_scroll.lua. A window that grows back drags the offset down with it, so the page never stays parked past its own end. - The panels return their natural height as they draw, so the measurement is the previous frame's: the same one-frame settle the slot and mod lists already rely on. - One scroll axis at a time. While the page scrolls, the panels draw paged: the slot and mod lists take their natural height, keep no inner scroll region and report a max of 0, so wheel, right stick and drag all move the page. Two-column layouts do not overflow, paged stays false, and every one of these behaves exactly as before. - inside() and _ptIn() reject a rect that scrolled out of the viewport, so a control that slid under the tab bar cannot be clicked through it. Tab chips are pinned and exempt. pageScroll resets on a tab change. Android had no scroll gesture at all: the launcher is handed no move events (main.lua forwards neither touchmoved nor mousemoved while it is up) and its mouse emulation was never trusted, which is what "no reliable pointer polling" referred to. That was survivable while every scroll region was an inner list, and useless once the page itself scrolls, since a phone is exactly where it overflows. love.touch is pollable, so _pointerHold reads the first active touch there and hands _updateSlotDrag the same (held, y) pair the mouse gives on desktop. Slot rows and mod toggles consequently arm on press and commit on release on Android too, matching desktop, so a swipe that starts on a card scrolls instead of selecting it. All of it is gated on touchPollable: without love.touch every Android path is exactly what it was. conf.lua also grows minwidth/minheight (480x360) for the desktop window, under which the cards stop being readable. Mobile is fullscreen and ignores it. Verified on the Android emulator (1080x2400) against a build of the parent commit: before, the footer painted over the SAVE SLOT card with no way to reach it; after, the page pans by touch and the footer is reachable and intact.
Gen1Recomp
A native LÖVE2D recreation of Poke Red and Blue. The engine and map behavior are hand-written Lua; game data and graphics are decoded from a ROM supplied by the player.
SUPPORT AND ANNOUNCEMENTS: Discord
This project does not include a ROM, emulate the Game Boy, transpile assembly, or download a disassembly. A canonical US Poke Red or Blue ROM is the only game content input.
The ROM is verified, used during import, and then released from memory. It is not copied into the cache. Later launches load the private generated cache and do not ask for the ROM again. Red and Blue can both be imported and played side by side.
Quick Start
Open the desktop app. On first boot, choose your legally obtained .gb file
or drop it onto the window. Import takes a few seconds and the game starts
automatically.
Only the canonical 1 MiB US Red and Blue ROMs are accepted. The importer verifies SHA-1 before creating any game data:
- Red:
ea9bcae617fdf159b045185467ae58b2e4a48b9a - Blue:
d7037c83e1ae5b39bde3c30787637ba1d4c48ce2
The packaged app contains neither a ROM nor pre-extracted game data. Music, sound effects, and cries are synthesized while the game runs from compact audio channel programs copied out of the verified ROM.
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. Controllers are supported out of the box.
Hotkeys
| Key | What it does |
|---|---|
- / = |
Zoom out / in (overworld; also mouse wheel) |
2 |
Cycle COLORS |
3 |
Cycle TILT (free-roam overworld) |
4 |
Cycle ZOOM through every level (free-roam overworld) |
5 |
Cycle GBC FX |
F1 |
Save |
F2 |
Load |
F10 |
Open / close the mod manager |
COLORS, TILT, ZOOM, GBC FX, and VOID FILL are also in the Options menu
and persist in options.lua.
Rulesets
OPTIONS → RULESET picks which set of Gen 1 battle behaviors to run.
Both rulesets share the same damage formulas; they differ only in whether
the original's quirks are kept. The setting persists in options.lua, and
mods can register their own.
gen1_faithful is the default and reproduces the original cartridge,
famous bugs included:
| Rule | Behavior |
|---|---|
oneIn256Miss |
A 100%-accurate move still misses on a roll of 255 |
critUsesBaseSpeed |
Crit rate reads base speed, not the current stat |
critIgnoresStages |
Crit rate ignores stat stages |
focusEnergyBug |
FOCUS ENERGY quarters the crit rate instead of x4 |
enemyUnlimitedPP |
Enemies never spend PP, so they never Struggle |
hyperBeamSkipRechargeOnKO |
HYPER BEAM skips its recharge when the target faints |
randMin / randMax |
Damage random factor 217-255 |
modern_clean keeps the formulas but removes the notorious quirks:
| Rule | Behavior |
|---|---|
oneIn256Miss |
Off: a 100%-accurate move always hits |
critUsesBaseSpeed |
Unchanged: crit rate still reads base speed |
critIgnoresStages |
Off: stat stages count toward the crit rate |
focusEnergyBug |
Off: FOCUS ENERGY raises the crit rate as intended |
enemyUnlimitedPP |
Off: enemies deplete PP and Struggle when empty |
hyperBeamSkipRechargeOnKO |
Off: HYPER BEAM always recharges, like Gen 2+ |
randMin / randMax |
Damage random factor 217-255, same as faithful |
Running From Source
Requires LÖVE 11.x. Place a Red or Blue ROM in the project folder and
double-click Play-Mac.command or Play-Windows.bat, or run:
scripts/setup.sh --rom "/path/to/Poke Red.gb" # or Poke Blue.gb
scripts/run.sh
then love . for later launches. Windows PowerShell scripts, the optional
developer data build, test suites, and cache management are covered in
Developer Setup.
Portable Mode
By default the game keeps your save, options, and the private ROM-derived
data cache in your OS's normal per-user app data folder. To keep everything
next to the game instead (handy for a USB stick or portable drive you carry
between computers), drop an empty file named portable.txt next to the app
(next to gen1recomp.app/.exe, or next to main.lua/conf.lua when
running from source), then launch the game. Portable mode is desktop-only
(Windows, Linux, macOS); it has no effect on Android or iOS, where the app
runs from a read-only package.
With portable.txt present:
save.lua,save.lua.bak, andoptions.luaare read from and written to that same folder instead of the OS save directory.- A ROM import writes the generated
data/generatedandassets/generatedcache straight into that folder too (nothing is left in the OS save directory), so a later launch reuses it without asking for the ROM again even on a different computer, as long as the same folder comes along. - Deleting
portable.txtswitches back to the normal OS save directory; nothing already written to either location is touched automatically, so copy files over yourself if you want to carry existing progress across the switch.
Handhelds
A PortMaster-style port for the Anbernic RG34XXSP on Stock OS 64-bit MOD
ships with every release as gen1recomp-*-rg34xxsp-stockos64-mod.zip.
Install steps, controls, and troubleshooting live in
docs/anbernic-rg34xxsp.md.
Modding
The game ships a native mod platform: content registries, events and hooks, per-mod saves and options, and an in-game manager. The full modding book — getting started, a twelve-rung tutorial ladder, a cookbook, and the generated reference — lives on the project wiki.
Shipped example mods, one per kind of author, live in [mods/](mods/).
Maps can be edited in our own build of Tiled, bryanthaboi/tiled_gen1recomp, and exported back out as a mod; see docs/tiled-map-editing.md.
Bugs and Ideas
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.
Thought of a feature that could be good, or a way to improve one that already exists? Open a feature request. Say what you want, why it is worth doing, and how you picture it working. A request with real detail is one that can actually get built.
More
- Link play — START > LINK connects two copies directly over UDP.
- Save editor — edit party, boxes, items, events, and Pokédex flags outside the game.
docs/architecture.md— runtime details;docs/behavior-porting-notes.md— formula provenance.
Special Thanks
This project would not be possible without pret > the pret band of decompiling maniacs > and their pokered disassembly.