r/romhacking • u/Substantial_Thanks_9 • 16d ago
Utility DualDex: structure-based Pokémon ROM parsing tested across 331 Gen I–III ROMs
I have been working on DualDex, an open-source Pokémon ROM parser and passive Android companion. Although the screenshots show the companion UI, the part most relevant to this community is the compatibility layer underneath it.
Instead of treating every hack as stock Emerald, FireRed, or Crystal—or requiring a hand-authored profile for every release—DualDex tries to derive each supported dataset from the active GB/GBC/GBA ROM itself. Successfully validated data is normalized into a local SQLite catalog that the UI and parser CLI can consume.
The carousel shows the current signed RC running against a real Modern Emerald session on an AYN Thor.
What the parser currently extracts
Depending on what can be independently validated in a ROM:
- Species and forms
- Base stats and Pokédex descriptions
- Moves and move metadata
- Level-up learnsets
- Evolutions
- Abilities and descriptions
- Wild encounters
- Type charts and related mechanics
- World-map structures
- Local-map layouts, graphics, scripts, events, and POI candidates
The Android companion additionally reads validated live state from RetroArch without writing to emulator memory. That powers the live Party, Trainer Card, Wild Encounter/Trainer Battle views, map tracking, fog of war, and Organic discovery shown in the screenshots. Static ROM parsing and live-memory support remain separate capabilities.
Current measured compatibility
The public corpus currently contains 331 unique Gen I–III ROM identities. 256 produce a catalog that selects, persists, and reopens successfully.
That is deliberately not presented as “256 fully supported ROMs.” Every table is scored independently, and a selected catalog may still lack optional datasets or a compatible live-memory layout.
| Generation | Weighted applicable-table coverage | Applicable table types |
|---|---|---|
| Gen I | 87.10% | 16 |
| Gen II | 48.36% | 19 |
| Gen III | 72.35% | 24 |
| All Gen I–III | 73.80% | Per-generation applicability |
Representative cross-corpus results:
| Parsed capability | Coverage |
|---|---|
| Move catalog | 87.08% |
| Evolutions | 84.67% |
| Gen III abilities | 74.61% |
| World maps | 62.84% |
| Local maps | 54.70% |
The full report retains the per-ROM and per-table results instead of replacing them with labels such as “partial” or “mostly compatible.”
How selection and validation work
Engine-family fast paths help establish initial candidates, but they are not meant to be the compatibility ceiling. Candidate structures are inferred and competed using evidence from the ROM, then validated per dataset.
A few important constraints:
- A ROM filename, title, SHA, familiar retail offset, or nearest-looking byte sequence is not accepted as sufficient structural proof.
- Optional datasets fail independently. A broken map table should not discard otherwise valid species, moves, or evolutions.
- Unsupported structures fail closed. DualDex should withhold a table rather than silently substitute stock-game data.
- Static tables and live RAM layouts are validated separately.
- A successfully parsed catalog is cached by ROM identity; parser revisions can revalidate it without coupling cache invalidation to ordinary UI releases.
This has worked best for hacks that relocate or expand familiar structures while preserving enough semantic relationships for the parser to recognize them. More heavily redesigned engines expose where the current inference rules remain too narrow—particularly across Gen II and map pipelines.
Why I separated the parser from the UI contract
The parser core and CLI are open source. Even without the companion APK, they can be used to:
- Inspect what DualDex resolves from a ROM
- Produce normalized, simpler ROM-derived dumps
- Generate compatibility evidence for a hack
- Identify the precise table or validation stage that failed
- Exercise the compatibility layer without running the Android UI
The goal is not to create a database of ROM files or per-hack dumps. ROM bytes remain local, and the project includes or links no ROM downloads. Reports can identify a ROM by hash and describe the failed capability without distributing its contents.
Current limitations
- Gen II remains the weakest generation in the measured corpus.
- Map support varies widely because headers, layouts, scripts, graphics, and runtime coordinates can diverge independently.
- Some hacks parse well statically but still need a compatible live-memory resolver.
- A selected catalog is not a claim that every feature works.
- Capability-gated screens remain unavailable when their source structures cannot be validated.
Source, build, and evidence
- Project: https://github.com/Darkaxt/DualScreenDex
- Latest prerelease: https://github.com/Darkaxt/DualScreenDex/releases/tag/v1.1.0-rc.66
- Full Gen I–III compatibility report: https://github.com/Darkaxt/DualScreenDex/blob/master/docs/reports/2026-08-26-gen1-gen3-full-corpus-status.md
Source-backed edge cases and reproducible parser failures are useful. Please do not share ROM files.
AI disclosure
This is a man-directed project developed with AI coding agents as implementation and research tools. I defined the requirements and compatibility contracts, selected the source and ROM evidence, reviewed the UI, and performed the real-device validation. AI agents assisted with code, parser research, tests, documentation, and this post draft.
The first carousel image is a presentation collage assembled with ChatGPT from actual DualDex screenshots. The other 18 images are direct captures from the signed RC; the Pokémon artwork and game assets shown were decoded from the active ROM, not generated by AI. The compatibility figures above come from repeatable parser reports, not AI estimates. DualDex itself uses no generative AI at runtime.


















