Repository navigation
Modding Basics
For: someone new to programming. Read this alongside Your First Change; you do not need to memorize it first. You will learn what the two mod files mean and how to edit them.
A folder contains files and other folders. A path tells you how to
find one. In mods/my_first_mod/main.lua, enter mods, then my_first_mod,
then open main.lua.
Engine source checkout App's save directory
├── main.lua runs the game ├── mods/
├── src/ engine code │ └── my_first_mod/
├── tools/ authoring commands │ ├── manifest.json
└── mods/ │ └── main.lua
└── my_first_mod/ └── saved progress and settings
├── manifest.json
└── main.lua
Wiki checkout
├── Home.md documentation
└── Tutorial-00-Your-First-Change.md
The two mod locations are alternatives. Choose one for your mod.
The main.lua inside your mod is different from the main.lua that runs
the engine. The wiki contains instructions, not the installed game.
Getting Started gives the real folder paths.
The game also keeps generated files made from your imported ROM. These are working game data, not the place to edit your mod. Never distribute them as mod assets.
Use an editor that saves plain text, not a Word document or rich text. On
macOS TextEdit, choose Format → Make Plain Text before saving. Keep smart
quotes off for code: " is a code quote; curly quotation marks are different
characters. Windows Notepad can save plain text; use All files when
necessary to keep the exact extension.
Save files as manifest.json and main.lua. Show file extensions in your
file manager and check that .txt was not added. Save after each change;
the game cannot see text that exists only in an unsaved editor tab.
| File | Format | Job |
|---|---|---|
manifest.json |
JSON: structured information | Identify the mod, choose its code file and supported games |
main.lua |
Lua: programming instructions | Tell the game what to change |
Complete manifest:
{
"id": "my_first_mod",
"name": "My First Mod",
"version": "1.0.0",
"entry": "main.lua",
"api": 2,
"games": ["red"]
}A JSON field is a named value, such as "name": "My First Mod".
Double quotes surround names and text; commas separate fields. There is no
comma after the last field. The outer braces { } hold the group together.
JSON does not allow the Lua comments shown below.
id is a stable internal name; name is what the player sees. Avoid changing
the ID after you have saved progress owned by the mod: a different ID means
a different private save area. api chooses the mod API rules; games
limits the example to Red. The Manifest reference
explains additional choices.
Complete main.lua:
return function(mod)
-- Replace the words on the Pallet Town sign.
mod.content.text:override("_PalletTownSignText", "HELLO FROM MY MOD!")
end-
function(mod)creates a set of instructions the game will call when it loads your mod. The namemodreceives the tools for this particular mod. -
returngives that function to the loader. Keep this outer structure. - A line beginning with
--is a comment for people; Lua ignores it. -
mod.content.textchooses the text registry, a named collection of text. -
:override(...)calls an operation on that collection. The values in parentheses are its arguments: the internal text ID, then your new text. -
endcloses the function. New mod instructions belong above this line, inside the function, unless a lesson explicitly says otherwise.
Only edit the second quoted string at first. _PalletTownSignText is an
internal name, not a phrase you invent. Code names are case-sensitive.
The same name with different capital letters can mean something else.
These are example shapes to read, not an additional mod file:
local greeting = "Hello" -- string: text
local speed = 90 -- number
local enabled = true -- boolean: true or false
local missing = nil -- no value
local stats = { hp = 60, speed = 90 } -- table with named fields
local moves = { "TACKLE", "GROWL" } -- table used as an ordered listlocal creates a name used by the surrounding code. = assigns a value.
A Lua table can group named fields or hold a list. A record is a
table describing one thing, such as a creature. A registry holds many
records, found by their IDs.
baseStats is a field name. GROWLITHE is a creature ID. The display name
“Growlithe” is text for the player. When you write code, copy the internal
field/ID spelling from the reference; do not guess it from the display name.
After the first exercise, try Tutorial 02. For example, this is an insertion inside your existing entry function:
mod.content.pokemon:patch("GROWLITHE", {
baseStats = { speed = 90 },
})patch changes the fields you name. Here the other base stats stay as they
were. override replaces an entire record. To change one stat, choose a
patch so you do not accidentally omit the other fields.
Lists need extra care. In a record registry, a plain replacement list
replaces the whole list; __append adds to its end. Some deep registries
append plain lists instead. Follow the registry's
merge rules before editing a list.
A callback is a function the game calls later, for example when the player enters a map. This is an insertion inside an entry function:
mod.events:on("map.entered", function(event)
mod.log:info("Entered %s", event.mapId)
end)event is a table containing information about that map entry. event.mapId
reads one field. %s is a placeholder in the log message; the next argument
fills it in. The message appears in log output,
not in a dialogue box.
An event lets you respond to something that happened. A hook lets you participate in a calculation or decision. Hooks have return-value rules and can affect other code; learn Events and Hooks before using one. A return value is the result a function gives its caller.
- Make one small edit and save the file.
- Validate it with Modkit if you use a source checkout.
- Restart, confirm the correct game/mod is enabled, and perform the lesson's in-game check.
- If it fails, read the first error and compare with the complete example.
- Turn the mod off and restart to compare the active changes.
Validation catches many file/data problems. It cannot prove that a screen draws correctly or that a quest is reachable. You need the in-game check too.
Next: Your First Change, Glossary, or Tutorials.
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.
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