Side Projects
Genesis ROM Workshop: Pulling Palettes, Tiles and Text Out of Sega Genesis ROMs

Part 6 of the thread The retro workbench
- What it is
- Open-source tool
- My role
- Creator
- Year
- 2025
- Built with
- Python
- Pillow
- NumPy
- Capstone
- A Python toolkit for pulling palettes, text and tile graphics out of Sega Genesis / Mega Drive ROMs.
- It decodes Genesis 4-bit planar tiles and renders them as PNG tile sheets and palette previews.
- There's a hex viewer, ROM header and checksum analysis, and a text extraction and translation workflow too.
- It's command-line only and a learning project: no compressed-data support yet, and results need checking by eye.
A Genesis cartridge is a few megabytes of bytes with no labels on them. Somewhere in there are the palettes, the tile graphics and the dialogue, but you can't just open it and look. You need something that knows how the hardware stores things and can turn raw bytes back into pictures and words.
genesis-rom-workshop, or GRW, is my Python toolkit for that. It's aimed at ROM hacking, translation projects, preservation research and plain curiosity about how 16-bit games were put together. Bring your own legally owned ROMs; none are included.
What's in the box
GRW is a set of small tools with one CLI, grw_pipeline.py, on top.
| Tool | What it does |
|---|---|
palette_editor |
Extracts, edits and swaps color palettes; exports JSON or PNG previews |
graphics_renderer |
Decodes 4-bit planar tiles and renders them to PNG |
asset_extractor |
Pulls out graphics tiles, tilemaps and sprites, with rendering built in |
text_extractor |
Finds text strings and handles a translation export and patch workflow |
hex_editor |
Hex view with address, hex and ASCII columns; edit, search and compare ROMs |
rom_analyzer |
Header parsing, checksum validation and entropy stats |
asset_manager |
Organizes everything you extract into projects |
How the graphics work
This is the interesting part. Genesis graphics are built from 8x8 tiles, 32 bytes each, at 4 bits per pixel, so every tile can use 16 colors from one palette. The pixel data is stored in planar bitplanes, which is why a raw dump looks like static until something decodes it.
GRW's renderer does that decoding and writes out PNGs at 1x up to 16x scale, with optional grid overlays for pixel-level work. Pair a palette with a stretch of tile data and you get a tile sheet you can open in any image viewer, instead of a .bin file and a JSON list of hex colors.
Note
Palette extraction assumes the standard VDP format, and GRW doesn't find palettes automatically yet. If a sheet comes out in strange colors, it's usually the wrong palette, not broken tiles.
Using it
Clone it and install the requirements. Pillow is the one that matters, since every image export depends on it.
git clone https://github.com/wesellis/genesis-rom-workshop.git
cd genesis-rom-workshop
pip install -r requirements.txt
Then point the pipeline at a ROM:
python grw_pipeline.py analyze game.bin --output-dir ./analysis
python grw_pipeline.py extract-palettes game.bin --format png
python grw_pipeline.py extract-text game.bin --output text.json
There's also a graphics demo in examples/ that renders palette previews, a tile sheet and individual tiles from one ROM in a single run. Every tool can be imported from Python as well if you'd rather script it.
Tip
Start with
analyze. It checks the header and checksum and gives you a feel for the ROM before you go digging for graphics.
Rough edges
I'll be straight about where this stands, because the README is. It's a learning project, and some of what's described there is only partly built or still planned.
- No compressed data. Graphics stored with Nemesis or Kosinski compression can't be unpacked yet, so they won't render.
- Command line only. There's no GUI.
- Genesis first. Master System, Game Gear and 32X files are recognized, but support is thin.
- Text is ASCII. Japanese ROMs need Shift-JIS and other encodings that aren't there yet, and text detection can throw false positives.
- Sprites stay as tiles. Assembling multi-tile sprites automatically isn't implemented.
- Check your results. ROM layouts vary a lot between games, so treat the output as a starting point.
The roadmap puts compression support first, then sprite assembly, full tilemap rendering, a GUI, broader tests, and eventually YM2612 and PSG audio playback.
If retro hardware is your thing, the arcade cabinet build is the other end of the same hobby: playing these games rather than taking them apart.
Try it
It's on GitHub. Contributions are welcome, especially anyone who's written a Nemesis decompressor before.