Example mod · theonaris.examples.crater-canyon 1.0.0
Crater Canyon
A custom map: a winding red-rock gorge ending in a steaming crater. It shows terrain and props from model files, lighting and fog, spawn points, looping ambient sounds, music with a radio switch, and scripted geysers with particles, sound and camera shake.
A custom map: a winding red-rock gorge that ends in a steaming crater. The static world is one JSON file. A client script adds music, wandering dust devils and geysers that the server triggers for everyone at once, with particles, a positioned sound and a camera shake that fades with distance.
| You will learn | Where |
|---|---|
| Declaring a map: base scene, preview, spawn points | content/maps/crater-canyon.json |
| Terrain from a glTF file, props from OBJ + MTL | "objects" with "model" and "collider": "mesh" |
| Sky colour, fog and sun | "environment" |
| Lights, particle effects and looping sounds placed in the world | "light", "effect", "sound" objects |
| Music with a fade, and an on/off switch that is remembered | audio.music, Sound:fadeOut, a Toggle that calls mod.settings.set |
| Starting and stopping things with the map | maps.onEnter, maps.onLeave |
| Moving particle effects | effects.start, Effect.position |
| Server-timed events every player sees together | task.spawn + task.wait on the server, net.broadcast |
| Camera shake | camera.shake |
| Console commands for testing | /crater-canyon.erupt, /crater-canyon.go (maps.tryLoad) |
Try it
- Install the mod, start the game and allow its permissions in Mods. Crater Canyon appears on the map selection screen with its preview picture.
- Pick it and play. (
/crater-canyon.goin the console selects it for your next session.) - Walk down the gorge to the campfire and the red totem. Dust devils drift along the canyon floor.
- Wait for an eruption, or type
/crater-canyon.erupt. Stand closer to the crater for a stronger shake.
How a mod map works
A map in this game is a scene that also carries the player spawner, water, networking and so on. A mod cannot ship a scene of its own without shipping code, so a mod map is built on top of one of the game's scenes:
{
"id": "crater-canyon",
"name": "Crater Canyon",
"base": "Empty",
"preview": "/preview.png",
"environment": { "fog": { "color": "#d7a07a", "density": 0.0045 }, "sun": { "pitch": 22, "yaw": -40 } },
"spawns": [ { "position": [8.7, 4.8, 0], "heading": 146 } ],
"objects": [
{ "model": "/models/canyon.glb", "collider": "mesh" },
{ "effect": "fire", "position": [24.7, 3.7, -10], "effectOptions": { "rate": 45 } },
{ "sound": "/sounds/campfire.wav", "position": [24.7, 4, -10], "range": 20 }
]
}Every game system keeps working, and the whole map is data the game has already checked. That is also what lets a server send the map to joining players safely.
Object kinds: model, shape (cube, sphere, cylinder, capsule, plane), light, sound (loops), effect. Each object has position, rotation (degrees) and scale (a number or three numbers). Colliders: none (default), box or mesh.
Coordinates
Map positions are world positions in metres, Y up. Model files use the usual right-handed convention (Blender, glTF, OBJ, FBX). The game is left-handed, so a model's Z is mirrored when loaded. A point that is at z = 10 in your modelling tool is at z = -10 in the map. The script's gorgeX accounts for this.
Why music is in the script
A map definition can play music by itself ("music": { "file": "/music/theme.wav", "volume": 0.4 }). This example plays it from the script instead to show audio.music, fading, and a player-controlled switch: a small radio panel whose toggle saves the choice with mod.settings.set("music", on), so it is remembered next time.
Arriving and leaving
maps.onEnter("crater-canyon", enter) runs enter every time the players arrive on the map, and at once when the mod starts while the map is already loaded (after a reload, or on a client that joins late). maps.onLeave runs leave, which removes the radio, the music and the dust devils. "crater-canyon" is the mod's own map, so its short id is enough.
Assets
Everything in models/, textures/, music/, sounds/ and preview.png was generated for this example: a 400 × 400 m heightfield with a baked texture, boulder clusters, a totem, a fire ring, a looping theme in D minor, wind, fire crackle and a geyser roar. Replace any of them with your own files of the same name.
Files
mod.json
content/maps/crater-canyon.json the map
scripts/server.lua eruption timing, console commands
scripts/client.lua music, radio panel, dust devils, eruptions
models/canyon.glb terrain with an embedded texture (glTF)
models/boulders.obj + .mtl rock clusters (OBJ + MTL + textures/rock.png)
models/totem.obj, fire-ring.obj landmarks (colour-only materials from landmarks.mtl)
music/canyon-theme.wav
sounds/wind.wav, campfire.wav, geyser.wav
preview.png map card pictureAll files
| File | Size |
|---|---|
content/maps/crater-canyon.json | 3 KB |
mod.json | 1 KB |
models/boulders.mtl | 99 B |
models/boulders.obj | 366 KB |
models/canyon.glb | 3.8 MB |
models/fire-ring.obj | 179 KB |
models/landmarks.mtl | 119 B |
models/totem.obj | 6 KB |
music/canyon-theme.wav | 3.8 MB |
preview.png | 51 KB |
README.md | 5 KB |
scripts/client.lua | 5 KB |
scripts/server.lua | 1 KB |
sounds/campfire.wav | 534 KB |
sounds/geyser.wav | 689 KB |
sounds/wind.wav | 689 KB |
textures/rock.png | 143 KB |