mod.json
Every mod has a mod.json at its root. The game reads it before anything else, and a mistake in it is reported with the line number in Mods, in the script editor's Problems and by theonaris-mod validate. Misspelled keys are reported with a suggestion ("did you mean permissions?").
{
"format": 1,
"id": "yourname.thruster-pack",
"name": "Thruster Pack",
"version": "1.2.0",
"description": "Three new thrusters and a tuning window.",
"authors": ["Your Name"],
"license": "MIT",
"homepage": "https://example.com/thruster-pack",
"icon": "icon.png",
"tags": ["blocks", "building"],
"game": ">=0.1.0",
"api": 1,
"side": "both",
"network": "required",
"entry": { "server": "scripts/server.lua", "client": "scripts/client.lua" },
"dependencies": { "someone.shared-lib": "^2.0.0" },
"permissions": ["building", "building.edit", "ui", "net"],
"settings": [
{ "key": "strength", "type": "number", "label": "Strength", "default": 1, "min": 0.1, "max": 5, "step": 0.1 }
],
"content": { "blocks": ["content/blocks/*.json"] }
}Identity
| Field | Required | Description |
|---|---|---|
format | yes | Always 1. |
id | yes | Unique forever. Lower-case yourname.modname: letters, digits, - and _, at least one dot, 3–64 characters. Changing it makes a different mod. Do not start yours with theonaris., which the game uses for its own modules and examples. |
name | yes | Shown to players. Up to 64 characters. |
version | yes | Semantic version: 1.4.2, 2.0.0-beta.1. |
description | no | Up to 4000 characters. |
authors | no | Up to 16 names. |
license | no | For example MIT or CC-BY-4.0. |
homepage | no | An https:// address shown in Mods. |
icon | no | A .png inside the mod, up to 1 MB, shown beside the mod in Mods. Square pictures look best. |
tags | no | Up to 16 lower-case words, such as blocks, ui or map. |
Compatibility
| Field | Default | Description |
|---|---|---|
game | any | The game versions the mod works with, as a version range. A mod outside its range does not start and says why. |
api | (required) | The API version the mod was written for. Currently 1. |
side | both | Where the mod has code: both, client or server. A client-only mod never runs on a dedicated server. |
network | required | How it behaves in multiplayer. See below. |
network values:
required: every player on a server running this mod must run the identical package. Joining players are offered the download. Use this for anything that changes the world, blocks, rules or shared content.optional: the server runs it and players may join with or without it. Use this for server-side tools that have an optional client interface.local: personal. It is never sent to anyone, never required, and works on any server. Use this for your own interface tweaks, sound packs and effects. A local mod's server script never runs on other people's servers, and the validator warns about it.
Version ranges
Ranges use the npm style:
| Range | Means |
|---|---|
* | any version |
1.2.3 | exactly 1.2.3 |
^1.2.3 | 1.2.3 up to, not including, 2.0.0 (for 0.x, the minor number is the breaking one) |
~1.2.3 | 1.2.3 up to, not including, 1.3.0 |
>=1.0.0 <2.0.0 | all conditions must hold |
1.x, 1.2.x | wildcards |
^1.0.0 || ^2.0.0 | either range |
Pre-release versions only match a range that itself names a pre-release, so ^1.0.0 never picks up 2.0.0-beta.
Code
"entry": { "shared": "scripts/common.lua", "client": "scripts/client.lua", "server": "scripts/server.lua" }shared runs on both sides first, then client or server. All three are optional: a mod made only of content needs no scripts. Scripts load other scripts with require; see Scripting.
Relationships
| Field | Example | Description |
|---|---|---|
dependencies | { "a.lib": "^1.0.0" } | Must be installed, enabled and in range. Starts first. If it fails, this mod does not start. |
optionalDependencies | { "b.extras": "*" } | Used if present and in range. Starts first when present. |
conflicts | { "c.old": "<2.0.0" } | This mod refuses to start alongside these. |
loadAfter | ["d.mod"] | Start after these if they are running, without requiring them. |
loadBefore | ["e.mod"] | Start before these if they are running. |
Another mod's exports are only reachable through mods.get when it is listed in dependencies or optionalDependencies.
Permissions
"permissions": ["ui", "world", "http:api.example.com"]Up to 64 entries. Each is a permission name from the permissions reference, some with an argument after a colon. Unknown permissions are reported, and calls that need them are refused. Medium and high risk permissions are shown to the player before the mod runs. See Security and permissions.
Settings
Settings are values the game keeps for your mod, always within what you declare here. Scripts read them with mod.settings.get(key) and change them with mod.settings.set(key, value).
"settings": [
{ "key": "enabled", "type": "bool", "label": "Enabled", "default": true },
{ "key": "speed", "type": "number", "label": "Speed", "default": 2.5, "min": 0, "max": 10, "step": 0.5 },
{ "key": "count", "type": "integer", "label": "Count", "default": 3, "min": 1, "max": 20 },
{ "key": "greeting", "type": "string", "label": "Greeting", "default": "Hello" },
{ "key": "mode", "type": "choice", "label": "Mode", "default": "calm",
"options": [ { "value": "calm", "label": "Calm" }, { "value": "wild", "label": "Wild" } ] },
{ "key": "hotkey", "type": "key", "label": "Open window", "default": "F7" },
{ "key": "tint", "type": "color", "label": "Tint", "default": "#40c0ff" },
{ "key": "rounds", "type": "integer", "label": "Rounds", "default": 5, "scope": "server" }
]| Field | Description |
|---|---|
key | An identifier (letters, digits, _), up to 48 characters, unique in the mod. |
type | bool, number, integer, string, choice, key (a key name) or color ("#rrggbb", or "#rrggbbaa" with alpha). |
label, description | A name and an explanation for the setting, in words players understand. |
default | Must suit the type and range. |
min, max, step | For number and integer. |
options | For choice: { "value", "label" } entries. |
scope | user (default) is each player's own preference. server is chosen by the host and sent to every player. |
Up to 64 settings. See Settings and storage.
Content
"content": { "blocks": ["content/blocks/*.json"], "maps": ["content/maps/*.json"] }Keys are content types (see Content types). Values are lists of file patterns: * matches within a folder and ** across folders. Each matched .json file holds one definition, or an array of them. Paths inside a definition are relative to that JSON file. Start a path with / to begin at the mod root.
Files a mod may contain
The game only reads file types it understands. Anything executable is refused outright, and a package containing one is rejected.
| Kind | Extensions | Limit (installed) | Limit (downloaded from a server) |
|---|---|---|---|
| Scripts | .lua | 2 MB each | 2 MB each |
| Data | .json | 16 MB | 16 MB |
| Text | .txt .md .csv | 2 MB | 2 MB |
| Pictures | .png .jpg .jpeg | 32 MB, 8192 px per side | same |
| Audio | .wav .ogg .mp3 | 256 MB | 64 MB |
| Video | .mp4 .webm | 512 MB | 128 MB |
| Models | .glb .gltf .obj .fbx (+ .bin .mtl) | 256 MB | 64 MB |
| Interfaces | .uxml (layout) / .uss (style) | 1 MB | 1 MB |
| Refused | .dll .exe .so .dylib .bat .cmd .ps1 .sh .vbs .js .jar .msi .scr .com .cs | — | — |
A whole mod may have up to 4096 files and 1 GB (2048 files and 256 MB when downloaded). README, LICENSE, CHANGELOG, AUTHORS and NOTICE without an extension are allowed. Files and folders whose names start with . (like .luarc.json) are ignored and never packed. File names must be portable: no .., no drive letters, no reserved Windows names, and no two paths that differ only in letter case.