Rooms
room.json holds a room's settings, its rules, and every thing standing in it.
Each room is a folder under rooms/, named like the room, with a room.json and its script files.
room.json
{
"id": "room:tpi_room_…",
"name": "Skybound",
"root": true,
"width": 48, "height": 48,
"view": "iso", "view_height": 1, "camera": "fit",
"chat": "line", "watch": "off", "capacity": 8,
"rules": [
{ "kind": "rounds", "seconds": 90, "min": 2, "countdown": 5, "results": 8 },
{ "kind": "winner", "by": "points" }
],
"things": [
{ "id": "placed_…", "thing": "Guardian", "x": 24, "y": 20 },
{ "thing": "Skybound Sign", "x": 20, "y": 26, "bricks": [{ "kind": "sign", "text": "Strike the guardian." }] },
{ "thing": "Spawn Pad", "x": 24, "y": 30, "rotation": 90, "bricks": [{ "kind": "spawn", "team": "red" }] },
{ "door": "Belt Island", "x": 40, "y": 10 }
]
}
Settings
| field | values | meaning |
|---|---|---|
root | true on one room | the game's own room, where its door leads |
width, height | 12 to 48 | the room in tiles |
view | iso, top | the world's own view, or a board from above |
view_height | 0, 1, 2 | seen from above: a plan, three-quarter, tall fronts |
camera | fit, follow | the whole board, or the player |
chat | line, open, off | Enter opens one line; the bar stays open; no chat |
watch | off, quiet, open | whether a copy can be watched, and whether watchers talk |
click | near, anywhere | where a click on a thing counts from: beside it (a click from further walks there first), or from any tile at once |
capacity | 1 to 1000 | people per copy |
A room folder with no matching room on the server is created on push. A room on the server with no folder is left as it is, and the push says so.
Rules
rules is the list of bricks on the game for this room: rounds, winner, teams, lives, score, welcome. No rounds makes a hangout. Every brick and its fields: Bricks.
Things
Each entry in things is one placed thing:
| field | meaning |
|---|---|
thing | the name of a thing in the game's stock |
door | instead of thing: another room of the game; the door stands here |
x, y | the tile |
id | written by a pull; a thing that keeps its id and its tile stays as it is, everything else is placed anew |
bricks | bricks on this one placed thing, on top of the thing's own |
rotation | 0, 90, 180, 270 |
height | its lift, in voxels |
look | a filter: outline, inked, soft, flat, sticker, flat-ink, color-ink, soft-ink or chunky |
hidden | true for a thing a script shows later |
state | the state it shows before a script sets another, one of the thing's own states; the Studio and renders show it too |
tag | a name for this one placed thing, up to 32 characters; a script finds it with tagged("plot-3") and reads t.tag |
version | which published version of the thing this one shows; without it, it shows the stock's (eggox stock use) |
click | anywhere: this thing can be clicked from any tile, whatever the room's click |
Any other field is refused, and the push names it. Things are placed in the order listed; a tile another thing already covers refuses, and the push names the entry.
Doors
A door is the room itself, standing in one place: {"door": "Hall"} in the root puts Hall's door there. Each room has one door, so it stands in one room only. There is no door back: leaving a room takes players out to where its door stands, and a script can send(p, "Room") to any room of the game. A door to the room it stands in, or to a room that holds this one (the root, from a room inside it), is refused.
A door wears the floor star. To dress the doors into a room as a thing from the stock: eggox entrance set "Moss Portal" --room Hall.
Size
A push that shrinks a room picks up the things it drops first, so shrinking and clearing the far side is one push. A thing that stays but would stand outside the new edge is named.
Script files
rooms/<Room>/<file>.lua are the room's files, each compiled as its own block, in name order (name them 1-main.lua, 2-shop.lua if it matters). Globals are shared between files and with the scripts on things. Up to 8 files of 16 KB each. A room with no .lua file has no script.
Shared code
Any other .lua file in the folder, outside rooms/ and things/, is a module every room can load with require:
-- shared/ui.lua
local M = {}
function M.coins(p, n) hud(p, "COINS", n) end
return M
-- rooms/Hub/main.lua
local ui = require("shared/ui")
on("enter", function(p) ui.coins(p, 0) end)
The name is the file's path without .lua, written as text in the call (require("shared/" .. x) is not followed). A module runs once per copy, the first time it is required, and what it returns is what every require of it gets. A room carries only the modules its code requires, and they count toward its script size. Rooms share the code, not the values: each copy runs its own. Up to 64 shared files.
This page as markdown, for you or your agent: /project/rooms.md