Repository navigation
Packaged Lua Mods
Home / Packaged Lua mods
Use a packaged mod when one mod needs several private Lua modules, assets, or a distributable ZIP. Single-file mods remain supported for small additions.
A packaged mod is a directory directly inside .minecraft/betamoon/scripts with betamoon.mod.json at its root:
betamoon/
scripts/
clockwork/
betamoon.mod.json
clockwork.lua
content/
items.lua
machines.lua
assets/
clockwork/
textures/
models/
The entrypoint may have any filename or nested path. It does not need to be main.lua.
{
"entrypoint": "clockwork.lua",
"name": "Clockwork",
"version": "1.0.0",
"description": "Clockwork machines and tools.",
"dependencies": ["Shared Materials"],
"image": "icon.png"
}entrypoint is required and must select a .lua file inside the package. The other fields are optional. They have the
same meaning as entrypoint metadata. Metadata may be declared in the manifest, the
entrypoint, or both. When both declare a field, the values must match exactly; a conflict rejects the package instead
of silently choosing one source.
For packaged mods, prefer keeping all metadata in betamoon.mod.json and leave the entrypoint focused on lifecycle
functions and registration. This gives each field one source of truth and avoids exact-match conflicts during edits.
Unknown manifest fields, absolute paths, .., backslashes, duplicate dependencies, and missing entrypoints are
rejected.
Use ordinary Lua require inside a packaged mod:
local items = require("content.items")
local machines = require("content.machines")
function modInit()
items.register()
machines.register()
endrequire("content.items") checks content/items.lua and then content/items/init.lua inside the same package. Modules
are cached for that mod generation, so repeated calls return the same value without evaluating the file again.
Private module names cannot escape the package and cannot resolve files from another mod. BetaMoon checks the syntax of
every .lua file in a package before loading it, including modules that the entrypoint does not currently require.
Use betamoon.modules for deliberate sharing between different mods. Ordinary require is for files
that belong to the same packaged mod and does not establish dependency order.
The distributed examples include a minimal beginner package and eight complete
advanced packages. The beginner lesson shows only the manifest, entrypoint, and a no-op private
module. Basic Storage keeps
plain data and layout declarations in private modules. The recipe-machine packages return registration functions from
their type and recipe modules, then call those functions from modInit so every registration remains inside the normal
package lifecycle. The world-generation packages keep JSON structure gameplay data beside their entrypoints; the
capstone also separates features, structures, and biome composition into private modules.
A packaged mod may be distributed as one ZIP directly inside betamoon/scripts:
betamoon/
scripts/
clockwork.zip
clockwork.zip contents:
betamoon.mod.json
clockwork.lua
content/items.lua
assets/clockwork/textures/...
The manifest must be at the ZIP root. Do not wrap the package in an extra top-level directory. ZIP entry names are case-sensitive and packages containing unsafe, duplicate, or case-colliding paths are rejected.
The directory and ZIP forms have the same Lua module and asset behavior. Changing anything inside a ZIP replaces the archive as one package on the next manual or automatic reload.
Game asset paths are relative to the package's assets/ directory. A packaged mod can keep its code and assets
together while separating them from Lua modules and manifest metadata:
betamoon.assets.textures:add {
key = "clockwork:block/gearbox",
path = "clockwork/textures/gearbox.png"
}For the directory example, the default is clockwork/assets/clockwork/textures/gearbox.png; inside the ZIP it is the
entry assets/clockwork/textures/gearbox.png. The texture-pack override remains
bm_assets/clockwork/textures/gearbox.png because explicit asset paths retain their structure beneath bm_assets/.
Assets registered without path use their ordinary key-derived package path. See Assets and
texture-pack overrides.
Each package resolves defaults only from its own assets/ directory. Different packages may use the same relative
path without colliding. Files beside betamoon.mod.json, Lua modules, and manifest images are not implicitly exposed
as game assets.
The top-level directory name or ZIP filename without .zip is the package's storage identity. A loose script,
directory package, and ZIP package cannot use the same identity, including names that differ only by letter case.
The mod's dependency identity remains its name metadata. Storage identity, metadata name, registered content keys,
and exported module names serve different purposes and do not replace one another.
Manual reload checks the manifest and all Lua sources before unloading the active generation. Directory package Lua files and assets participate in optional reload-on-save detection; a ZIP reloads as one package when its file changes. Required structural content still follows the ordinary hot-reload compatibility rules.
- Installation
- Install scripts
- Getting started
- VS Code and LuaLS
- Examples
- Reload and compatibility
- Troubleshooting
- Changelog
Scripts and shared values
- Script lifecycle
- Packaged Lua mods
- Modules
- References and stacks
- Queries
- Overrides
- Minecraft constants
- Chat and positions
- Structured data
- Script configuration
- Particles
Blocks and items
- Multiblocks
- Blocks
- Block state and placement
- Block shapes and rendering
- Block callbacks
- Block ticks and redstone
- Items
- Fluids
- Item callbacks
- Tools and armor
- Materials
- Textures
Entities
- Entities
- Entity access and movement
- Entity lifecycle and data
- Entity health and loot
- Entity inventories and relationships
- Projectiles and pickups
- Entity presentation and sounds
- Living entities and AI
- Entity parts and sensors
Assets and audio
- Assets
- Models and animations
- Built-in Minecraft models
- Model appearances
- Blockbench workflow
- Audio
- Texture-pack overrides
Events and world actions
World generation
World systems
Inventories and screens
Recipes