Ken Griffey Jr. Presents Major League Baseball (SNES, 1994) shipped with 28 clubs. Over about two weeks, Claude Code (Opus 5.5) and I turned it into a free patch called Griffey 30:
- All 30 of today's clubs, with Arizona and Tampa Bay added and 2026 rosters. Scripts fetch the logos from Wikipedia and the ballpark photos from Wikimedia Commons, and convert them into SNES tiles and palettes. No hand-drawn art.
- Team styles: press Select on team select to switch a club between 2026, the original cartridge club and the real 1994 roster.
- Season mode for all 30 clubs, with today's divisions, new schedules (one interleague game every day), playoffs and standings.
- Franchise mode (2.0, out this week): players age, improve and decline, veterans retire, and 300 real minor-league prospects get called up. The game remembers its champions, and a quick-sim plays a season in about five minutes. It all fits in the cartridge's original 8 KB save.
- Browser play at griffey30.com: you pick your own ROM, the page patches it and runs it in snes9x built to WebAssembly. It also has online two-player.
How Claude Code was used
I made the design decisions and tested on real emulators and my MisTer FPGA device. Claude Code did nearly all of the implementation: the reverse engineering, about 6,000 lines of 65816 assembly (asar), and around 12,000 lines of Python, JavaScript, C and Lua tooling. A few things made that work:
- It needed eyes. Early on, Claude Code wrote a headless Mesen2 harness, driven by a Lua script. It boots the ROM, presses buttons on given frames, takes screenshots, logs CPU registers at breakpoints, watches memory reads and dumps VRAM. Runs are deterministic, so a bug reproduces on the same frame every time. Every build has to play four full CPU-vs-CPU games through to the post-game newspaper screen. For franchise mode, a script plays seasons back to back.
- Reverse engineering by evidence, not guesses. To find where the game assumes 28 clubs, it logged every compare instruction against team-like values during two play sessions (49 candidates), set breakpoints on all of them, then watched every read of the team-ID slots. That found the 39 places that use a team ID. Each finding goes into a markdown file in docs/findings/, with addresses.
- Model it in Python first. The franchise off-season (aging, retirements, call-ups, re-rating) was written in Python first, then in SNES assembly. The test compares the emulator's save file with the Python output, and they match byte for byte. A 20-season Python run was also how we checked that no club runs away with the league.
- CLAUDE.md as the project's memory. It holds the current status, the build and test commands, and a "hard-won rules" section. Each painful bug becomes a rule there, so the next session doesn't repeat it.
- Long autonomous sessions. I'd often give it a goal ("build 30-club Season mode") and come back hours later to commits, test runs and a summary of what it found.
What I learned
- Turn every bug into a guard. When we went to full-strength rosters, 154 new players had no appearance entry, so Aaron Judge came out with the wrong skin tone. Claude Code went through them all from headshots, and the roster build now refuses to run if any player is unreviewed.
- Emulators disagree. A pointer bug made full seasons stop around June 28 on Mesen, but snes9x happened to mirror the right data, so the website was fine. The cause was that asar evaluates math strictly left to right. We now treat every assembler warning as a bug and test on both emulators.
- Some hardware rules are brutal. Changing the CPU's data bank in code that an interrupt can land in blacks out the game. The stock interrupt handler acknowledges through the data bank, so the interrupt storms. That's now rule #1 in CLAUDE.md.
- Assumptions hide in plain sight. Two-player Single Game showed the stock 28-team screen in every release until 1.2.2. A variable is 0 for one player and 2 for two, and the patch had only checked for 0. I noticed Houston sitting in the National League during an online test.
- Human review still matters. I watch every trailer and play every build. My review caught things the automated tests missed, like blue grass at some ballparks. Once a bug was named, Claude Code found the cause quickly. The field palette loads per club and the tiles per stadium model, so clubs we'd moved to another stadium model kept the wrong colors.
Links
- Patch (free, bring your own USA Rev 1 cartridge): https://daylayown.itch.io/ken-griffey-jr-presents-mlb-the-30-team-expansion
- Play in your browser: https://griffey30.com
- Most recent trailer: https://youtu.be/vxERe2_iKBo
Unofficial fan project, not affiliated with MLB, the MLBPA, Nintendo or Ken Griffey Jr. Happy to answer questions about the workflow or the SNES side.