This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Total conversions
Building a new game on the engine (new region, new dex, new story, new branding) without touching engine source. The capstone tutorial (Tutorial 12) walks a small one end-to-end; this page is the map of the territory.
Start with a small playable result
This is an advanced authoring path. Start with a scaffolded mod, an imported
game, and the Modding Basics and first change
pages if you are new to Lua. Run the scaffold command from the engine
repository root, the directory containing tools/modkit.py.
Build in milestones and boot the game after each one:
- Scaffold the conversion and confirm it loads as a mod.
- Replace one map and tileset, then walk through it.
- Add one encounter, character, and text change.
- Add the story, roster, rules, art, and audio in separate steps.
- Add save state, package the result, and test from a clean install.
Keep a short DIFFERENCES.md as you go. At each milestone, record the
visible result and the file or registry that produced it. If the game does
not boot after a change, disable the last change, read the manager error feed,
and use Troubleshooting before adding more
surfaces.
The profile
This is a complete minimal manifest for the scaffolded conversion; add only fields your project actually uses.
{
"id": "my_conversion",
"version": "1.0.0",
"api": 2,
"profile": "total_conversion",
"games": ["red"],
"description": "A small replacement game"
}
profile = "total_conversion" labels the mod in the manager and marks it as
content that needs deliberate link review. Link play uses the launcher’s
approved vanilla or sealed custom-cart flow; the manifest field below is not
a player permission for loose-mod linking. The scaffold wires the profile:
python3 tools/modkit.py scaffold my_conversion --profile total_conversion
What a conversion replaces (all data)
| Surface | Mechanism |
|---|---|
| The world | maps / tilesets / encounters registries; field (ledges, hidden items, fly network, town map, badge gates) |
| The boot flow | field.boot: spawn, names, money, naming presets, screens = { splash, title, newGame } resolved through the screens registry. To keep OakSpeech but add questions / sprite beats / answers, wrap intro.oak_speech.build instead of replacing newGame |
| The roster | pokemon / moves / type_chart / statuses / move_effects / growth_rates / evolution_methods |
| The people | trainers / ai_classes; NPCs as map objects + map_scripts |
| The story | map_scripts (compose; an override chain excludes the vanilla contribution per map), commands, tokens, text, text_pointers |
| The rules | constants: dex size, badges (override for a whole new set), bag/party/box caps, level cap, HM list |
| The sound | music / sfx / cries / map_songs; ChipAsm for authentic tracks |
| The look | palettes / font / sprites / transitions; asset transforms and overrides/ (Art Pipeline) |
| The screens | screens registry + the ui.* menu hooks |
| The saves | save.new_game hook when field.boot is not enough; mod.save + mod.migrations for your own state |
The deep registries take override as the total-conversion verb: it
replaces a whole key where patch folds into it.
One generation at a time
A total conversion is a Gen 1 project today. profile is a label (the
manager shows it and the mod index flags anything but content); it
unlocks nothing per generation,
and the scaffold writes "games": ["gen1"]. The surfaces the table above
leans on hardest are Gen 1 surfaces:
| Surface | Gen 2 (Gold, Silver, Crystal) | Gen 3 (FRLG, RSE) |
|---|---|---|
field |
boot only: startMap/startX/startY/startFacing, startMoney, rivalName, namePresets. No boot.screens, title, starterScript |
no target |
maps, tilesets, encounters, trainers, text |
Gen 2 tables, Gen 2 record shapes | maps by native map id; encounters, trainers, text own tables; tilesets no target |
map_scripts |
Gold's bytecode VM scripts (data.gen2Scripts) |
native script ops (data.gen3Scripts) |
constants |
Gold's ordered ROM name lists | no target |
rulesets, text_pointers |
no target | no target |
transitions |
Gen 1 target | no target |
A write with no target is taken, dropped and reported, so there is no
sanctioned way to replace a Gen 2 or Gen 3 boot flow or title, and Gen 2 and
Gen 3 story work means native-shape map_scripts, not the Gen 1 row lists
(Data Model). Keep the
conversion on "games": ["gen1"] (or omit games, which means Gen 1 only)
rather than half-loading on later games. Smaller cross-game pieces (a
species, a move, an item) can ship as a separate api 3 mod; see
Portable Mods across Gen 1, 2 and 3 and
Preparing Your Mod for Gen 2.
What a conversion must not replace
- The ROM import. It stays mandatory: it supplies fonts, UI plumbing and audio infrastructure, and it is the legal foundation: the player's own verified ROM is the only game-content input. Conversions overlay the imported world; they never substitute for it.
- Engine source. Everything you need is a registry, hook, or event;
a conversion that requires private modules is unsupported and must
declare
permissions = ["engine_internals"]. - Someone else's content. Porting an existing ROM hack means rebuilding it natively: data re-expressed as registry records, mechanics rewritten against the mod API, art regenerated via transforms. The loader never executes IPS/BPS/UPS patches.
Coverage discipline
A conversion is done when every surface the player meets is deliberate.
Iterate the merged registries (mod.content.<name>:each()) in a dev
build to hunt vanilla leftovers: a Kanto map song on your route, an
unreplaced trainer party, a dex entry you forgot. Keep a DIFFERENCES.md
in the mod enumerating what diverges from vanilla; the base game's own
ledgers stay clean because your changes vanish with the mod
(Compatibility).
Shipping
modkit pack gates distribution on the no-ROM-content lint. To link two
players, include the conversion in a sealed custom cart and test that cart
through the launcher; an ordinary conversion package is not a link cart
(Link Compatibility, Publishing).
Check and recover
At each milestone, the expected result is a bootable game with the one visible change just added. If the boot fails, disable the last surface, read the manager error feed, and return to the last working milestone before adding another registry or hook.
Start here
Playing
Tutorials
- Choose a tutorial
- 01 Sprite and Text Tweak
- 02 Balance Patch
- 03 New Species
- 04 New Item and Ball
- 05 New Move
- 06 NPC and Dialogue
- 07 New Map
- 08 Quest
- 09 Custom Music
- 10 New Mechanic
- 11 Custom UI Screen
- 12 Mini Total Conversion
Creative guides
Concepts
Recipes and reference
Author and developer tools
Home · Start Playing · Glossary · Troubleshooting · Repository · Community
Game data is imported locally from a supported ROM supplied by the player. Shared mods contain original work or transform recipes, never extracted game content. Check each guide's target game before using its examples.