# Level format (chat maps and level files)

Levels can be written as a **text map** in chat, pasted into the editor (`editor.html`, **Paste map**), and copied back out (**Copy chat map**). The editor saves the same level as a `.level.json` file that the game plays (**Custom Level**).

Use this format exactly.

## Layout grid

One character per 1 m tile. Row 1 is the **top = north = the back wall**. All rows must be the same width. Sizes: 4 × 4 up to 64 × 64.

| Emoji | Letter | Meaning |
|---|---|---|
| ⬛ | `#` | wall (solid, 3 m tall) |
| ⬜ | `.` | floor (walkable ground) |
| 🟫 | `P` | pillar (round column, 3 m tall) |
| 🟧 | `B` | crate (box, about 1 m, can be jumped onto) |
| 🟤 | `R` | rock (boulder for cover) |
| 🟪 | `G` | gate (glowing gate; line several up for a wide gate) |
| 🟩 | `S` | player start (only one; if there are several, the first is used) |
| 🟥 | `E` | enemy spawn (a practice dummy stands here in the game) |
| 🟦 | `_` | empty (no floor, nothing there; the game treats it as the edge of the map) |

Every piece except 🟦 stands on floor, so a wall tile needs no ⬜ under it. Emoji and letters can be mixed. Extra blank lines, spaces and code fences are ignored.

## Height grid (optional)

After the layout, leave a blank line, then give **one row of whole numbers per layout row**, separated by spaces. Same width and same number of rows as the layout.

- Each number is the tile's height in **levels of 0.5 m**: `0` is ground level, `2` is 1 m up, `-4` is a trench 2 m deep.
- Range is -12 to 30 (-6 m to +15 m).
- Pieces stand on the tile's height. The game and the editor blend neighboring heights into smooth slopes, so a big jump between two tiles becomes a steep slope, not a cliff. Use walls for cliffs.
- Leave the height grid out for a flat level.

## Example (8 × 6, with a small hill)

```
⬛⬛⬛⬛⬛⬛⬛⬛
⬛⬜⬜⬜⬜🟤⬜⬛
⬛⬜⬜🟧⬜⬜⬜⬛
⬛⬜⬜⬜⬜⬜🟥⬛
⬛🟩⬜⬜⬜⬜⬜⬛
⬛⬛⬛⬛⬛⬛⬛⬛

0 0 0 0 0 0 0 0
0 0 0 1 2 2 0 0
0 0 1 3 4 2 0 0
0 0 0 1 2 1 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
```

The same map in letters:

```
########
#....R.#
#..B...#
#.....E#
#S.....#
########
```

## Level file (`.level.json`)

The editor's **Save level** writes this, and **Load level** / the game's **Load level file** read it.

```
{
  "format": "testroom-level",
  "version": 2,
  "name": "My level",
  "tileSize": 1,
  "heightStep": 0.5,
  "size": { "width": 8, "depth": 6 },
  "pieces": [
    {"type":"floor","x":1,"y":0,"z":1},
    {"type":"rock","x":5,"y":0,"z":1}
  ]
}
```

- `x` is the column and `z` is the row, both counted from 0 at the top-left of the layout.
- `y` is the tile's height in levels. A floor piece carries the terrain height, and any piece on that tile uses the same `y`.
- Piece types: `floor`, `wall`, `pillar`, `crate`, `rock`, `gate`, `player_start`, `enemy_spawn`.
- Version 1 files (no `heightStep`, `y` always 0) still load as flat levels.

## Tile size

A level has a `tileSize` (1 to 8 meters per tile, default 1). Pieces scale with the tile: at 4 m a wall is 4 m wide and 12 m tall, a crate is a 3.8 m block, a rock is a boulder. **The player stays human sized** (about 1.8 m tall, 5.5 m/s) and so do the dummies, so a 4 m level feels like a big outdoor map. Terrain heights are always in half-meter levels, whatever the tile size.

A wall can have its own height in meters with an `h` field (`{"type":"wall","x":0,"y":0,"z":0,"h":8}`). Those walls are drawn as rock cliffs. Chat maps do not carry tile size or cliff heights; the editor keeps the current tile size when you paste a map.

## Recipes (shape commands)

Instead of drawing every tile, write a short recipe and press **Run recipe** in the editor. It builds the level, and you can paint over it afterwards. Running a recipe replaces the level and is one undo step.

Rules: one command per line, run **top to bottom, later lines override earlier ones**. `x` goes across and `z` goes down (same as the grid, counted from 0). Lines starting with `#` are notes. Heights are in levels of 0.5 m; add an `m` to use meters (`3m`, `-1.5m`). A mistake stops the run with `line N: ...` and leaves the level unchanged.

An **area** is a zone name, or `x a-b z c-d` (inclusive; leave one axis out for "all of it").

| Command | What it does |
|---|---|
| `level "Name" WxD [tile Nm]` | Start a new flat floor, 4 to 64 tiles each way. Must be the first command. Without it, the commands change the current level. |
| `border wall` | A wall around the edge. |
| `border cliff [height] [N]` | A tall cliff around the edge (default 8 m, e.g. `border cliff height 12`). |
| `zone name = x a-b z c-d` | Name an area for later lines. |
| `raise <area> to H [ramp N]` | Set the area's height to H, with a sloped band N tiles wide around it (it only lifts the band). |
| `dig <area> to H [ramp N]` | Same, but the band is only lowered. |
| `hill at x,z radius R height H` | A smooth round bump added to the terrain (a negative H makes a crater). |
| `trench along z N from a to b width W depth D` | A straight channel along row N (or `along x N` for a column) from a to b. |
| `crate at x,z x,z ...` | Place crates. Also `pillar at`, `rock at`, `gate at`, `enemy at`. |
| `start at x,z` | The player start (only one; a later one replaces it). |
| `rock scatter N in <area> seed S` | N rocks at seeded random spots on empty floor (never on gates, starts or other pieces). The same seed always gives the same spots. |
| `mirror north-to-south` / `mirror west-to-east` | Copy the first half of the map (layout and heights) onto the other half. A mirrored start is dropped. |

Example (a 25 × 25 arena with a raised base at each end and a trench between):

```
level "Medium Arena" 25x25
border wall
zone north_base = x 8-16 z 1-5
zone trench = z 11-13
raise north_base to 4 ramp 1
dig trench to -4 ramp 1
gate at 12,0
start at 12,2
crate at 10,3 14,3
rock scatter 6 in x 1-23 z 6-9 seed 3
mirror north-to-south
enemy at 9,22 12,22 15,22
```

A big outdoor map at 4 m tiles:

```
level "Gulch Style" 50x40 tile 4m
border cliff height 8
zone red_base = x 3-10 z 14-26
zone blue_base = x 39-46 z 14-26
zone valley = x 12-37 z 4-35
raise red_base to 3 ramp 2
raise blue_base to 3 ramp 2
dig valley to -1 ramp 3
trench along z 20 from 14 to 36 width 4 depth -3
hill at 25,10 radius 6 height 3
hill at 25,30 radius 6 height 3
rock scatter 30 in valley seed 7
pillar at 20,20 30,20
start at 6,20
enemy at 43,18 43,22
```

(Heights there are small because levels are half meters: `raise red_base to 3` is 1.5 m. Use `to 6m` for a 6 m base.)

## Samples

`levels/arena.level.json` (16 × 16, with a raised platform) and `levels/canyon.level.json` (25 × 25, raised bases at both ends and a trench). The matching `.map.txt` files are the same levels as chat maps.
