Skip to content

Reference Mod Object

bryanthaboi edited this page Jul 19, 2026 · 1 revision

The mod object

Every member of the mod table the loader hands your entry function, as constructed in src/mods/Loader.lua (_api). Nothing outside this surface, the registries, the cataloged events/hooks, and the documented data schemas is supported.

Identity

Member Value
mod.id the manifest id
mod.version the manifest version string
mod.path the mod's directory ("mods/")
mod.manifest a deep copy of the validated manifest — mutating it changes nothing
mod.DELETE the tombstone sentinel for patch (patch(id, { field = mod.DELETE }))

Content

Member Signature Notes
mod.content.<registry>:register (id, value) add; duplicate id errors
mod.content.<registry>:override (id, value) replace whole record
mod.content.<registry>:patch (id, partial) deep-merge
mod.content.<registry>:remove (id) tombstone
mod.content.<registry>:get (id) -> value merged view, base data included
mod.content.<registry>:each () -> iterator merged view

All 37 registries plus the v1 aliases (scripts, ui) hang off mod.content; see Reference: Registries. Content verbs are entry-chunk-only (Lifecycle).

Events and hooks

Member Signature
mod.events:on (name, callback, priority) -> unsubscribe
mod.events:once (name, callback, priority) -> unsubscribe
mod.events:emit (name, payload) — only "mod.<id>.*" names
mod.hooks:wrap (name, callback, priority) -> unsubscribe

Catalogs: Reference: Events, Reference: Hooks.

Persistence

Member Signature Backed by
mod.save:get (key, default) -> value save.modData[modId]
mod.save:set (key, value) save.modData[modId]
mod.options:define (rows) rows render in the manager
mod.options:get (key) -> value options.modOptions[modId], falling back to the row default
mod.migrations:add (since, fn) runs on load for saves older than since

Row shapes and migration ordering: Save Model.

Assets and files

Member Signature Notes
mod.assets:path (relative) -> "mods/<id>/<relative>" the path helper every sprite field wants
mod.assets:image (relative) -> Image cached love.graphics.newImage; needs a graphics context
mod.assets.<registry> v1 alias of mod.content.<registry>
mod:read (relative) -> contents, err read a file from the mod directory

Scripting sugar

Member Signature Notes
mod.commands:register (verb, fn) sugar over mod.content.commands; replacing an engine verb must say override on the registry

UI toolkit

mod.ui is the shared widget facade (src/ui/ModUI.lua); widgets load on first touch.

Member What it is
mod.ui.Menu, mod.ui.ListMenu, mod.ui.ChoiceBox, mod.ui.QuantityBox, mod.ui.NamingScreen, mod.ui.PicBox, mod.ui.TextBox, mod.ui.Font, mod.ui.Theme the stable widget set for building screens
mod.ui.push(game, screenId, ...) instantiate through the screens registry and push
mod.ui.insertBefore(items, anchorLabel, item) anchored menu insertion (missing anchor appends)
mod.ui.insertAfter(items, anchorLabel, item) same, after the anchor
mod.ui.removeLabel(items, label) remove a row by label

World facade

mod.world materializes on first touch, once the live Game exists (after game.ready); nil before that and in headless runs without a game. Implementation: src/world/WorldAPI.lua.

Member Signature Notes
mod.world:current () -> { mapId, x, y, facing } the player's position
mod.world:warpTo (mapId, x, y, facing, opts) scripted warp; opts.arrive = "fly" | "teleport" picks the arrival FX
mod.world:toggleObject (mapId, objName, visible) persisted; emits world.object_toggled
mod.world:setFlag / getFlag (name, value) / (name) -> bool the shared story-flag namespace
mod.world:replaceBlock (bx, by, block) current map, block grid
mod.world:spawnNpc (mapId, objDef) -> npc runtime NPC, same shape as maps[].objects; not serialized — respawn on map.entered
mod.world:removeNpc (npcId)
mod.world:npc (mapId, indexOrName) -> handle handle:scriptMove(dir, tiles, onDone), marchInPlace, face
mod.world:queueScript (rows, extra) run command rows through the script queue
mod.world:invalidateMap (mapId) drop the built map so edits show

Inter-mod API

Member Signature Notes
mod.exports a table you fill (or assign) what other mods see
mod.find (otherId) -> { id, version, exports } | nil nil when absent, disabled, failed, or not yet loaded

Logging

Member Signature
mod.log:info / warn / error (fmt, ...) — attributed [mod-id] lines

Supported requires

Mod code may require exactly two engine modules without the engine_internals permission: src.mods.Semver (range-check another mod's exports) and src.audio.ChipAsm (author chip music and sfx). Everything else under src. is unsupported-and-may-break; under POKEPORT_DEV=1 an undeclared require logs a warning naming the mod and module.

Clone this wiki locally