# LevelSpec: the AI-facing representation

`LevelSpec` is intentionally much smaller and less ambiguous than a triangle mesh, a STEP file, or a complete engine scene. It is an **authoring intermediate representation** for tactical FPS greyboxes.

The current schema is rectangular-grid based because orthogonal tactical layouts are a particularly useful first target. A later version can add polygons, splines, sloped volumes, and modular-kit references without changing the central rule: the model edits semantic intent; a deterministic compiler owns final geometry.

## Coordinate convention

The canonical source coordinate system is:

- right-handed;
- Z-up;
- meters;
- integer XY planning grid; and
- explicit storey elevations.

Engine adapters perform the axis and unit conversion exactly once.

## Root fields

```json
{
  "schema_version": "1.0",
  "id": "original_three_lane_map",
  "name": "Original three-lane tactical map",
  "units": "meters",
  "coordinate_system": "right-handed Z-up",
  "grid": 1.0,
  "wall_thickness": 0.22,
  "floor_thickness": 0.20,
  "voxel_pitch": 0.25,
  "layers": [],
  "vertical_connections": [],
  "covers": [],
  "gameplay": {}
}
```

## Layers and spaces

A layer is a storey or traversable elevation band. Every space is authored as an integer rectangle:

```json
{
  "id": "ground",
  "z": 0.0,
  "height": 3.1,
  "internal_walls": true,
  "spaces": [
    { "id": "lobby", "label": "Lobby", "rect": [10, 8, 7, 9] },
    { "id": "bar", "label": "Bar", "rect": [17, 8, 8, 9] }
  ],
  "portals": [],
  "wall_overrides": [],
  "floor_holes": []
}
```

`rect` is `[x, y, width, depth]` in grid cells.

The compiler rasterizes room occupancy and derives every boundary edge. A shared room boundary is represented once internally, which eliminates the common LLM error where two rooms independently emit almost—but not exactly—the same wall.

Use `allow_space_overlap` only for deliberate unions such as broad outdoor route bands in the approximate Dust-style benchmark. For ordinary buildings, overlapping rooms are a validation error.

## Portals

A portal opens a compiler-owned boundary between spaces or between a space and the outside:

```json
{
  "id": "lobby_bar_door",
  "between": ["lobby", "bar"],
  "kind": "door",
  "width_cells": 1,
  "hint": [17, 12]
}
```

Supported kinds:

- `door`
- `open`
- `arch`
- `breach`
- `window`
- `rappel_window`
- `rappel_door`

For an outside portal, use `"__outside__"` and optionally specify `side` as `N`, `S`, `E`, or `W`.

The model does not supply the door vertices. It states which spaces are connected, the kind and width, and an optional preferred location. The compiler finds a contiguous shared boundary run and owns the exact cut.

## Wall semantics

A wall override marks the shared boundary between two spaces:

```json
{
  "between": ["church", "arsenal"],
  "type": "reinforced"
}
```

Supported types are `hard`, `soft`, and `reinforced`.

The current compiler groups resulting boxes into a runtime manifest. A production version should assign a stable semantic wall ID to each maximal boundary run and generate:

- a static structural frame;
- replaceable panel geometry;
- reinforcement attachment sockets;
- damage cells or fracture tiles;
- visibility and bullet-penetration masks; and
- nav/cover invalidation hooks.

## Vertical connections

Every stair, ladder, hatch, or rappel transition is explicit:

```json
{
  "id": "main_stairs",
  "from_layer": "basement",
  "to_layer": "ground",
  "from_cell": [27, 25],
  "to_cell": [27, 25],
  "kind": "stairs",
  "width": 1.8
}
```

This is essential for stacked tactical spaces. A 2D room plan alone cannot express that Catwalk is above another route, that a hatch aligns with the room below, or that an exterior rappel line reaches a particular window.

The compiler opens floor holes and adds the vertical graph connection. Validators ensure endpoints lie in occupied, traversable cells.

## Cover

Cover is separate from the structural room topology:

```json
{
  "id": "site_crates",
  "layer": "ground",
  "rect": [42, 46, 3, 2],
  "height": 1.25,
  "material": "cover"
}
```

Keeping cover independent makes it possible to optimize layout topology before adding tactical microgeometry.

## Gameplay contract

The `gameplay` object stores markers and required routes. The benchmark compiler turns occupied cells and portals into a navigation graph, then tests connectivity and shortest-path distances.

A production contract should add:

- team spawns and objective sites;
- minimum and maximum route times at a canonical movement speed;
- number of vertex-disjoint or edge-disjoint routes;
- defender rotation constraints;
- chokepoint width intervals;
- sightline exposure and sniper-lane limits;
- cover intervals along routes;
- grenade/utility trajectories;
- bomb-plant and retake reachability;
- drone routes and destructible shortcuts;
- rappel clearance; and
- spawn-to-contact safety windows.

## Compiler invariants

The deterministic compiler, not the model, must enforce these invariants:

1. A shared wall has one owner and one exact coordinate plane.
2. Door/window cuts are selected from an actual shared boundary.
3. Every box has positive dimensions.
4. Engine-specific axes, units, and winding are generated by adapters.
5. Static touching solids are either deliberately retained as editable modules or unioned with a robust geometry kernel.
6. Dynamic panels are not accidentally fused into the immutable shell.
7. Every gameplay marker snaps to a traversable cell.
8. Every required route exists.
9. Every vertical link has a matching opening and valid endpoints.
10. Geometry and gameplay validation reports are machine-readable and become the next AI input.

## Why rectangles first

Rectangles are not proposed as the final expressive ceiling. They are a low-entropy starting point that makes failures legible. Extensions should be added in this order:

1. unions of rectangles;
2. arbitrary grid polygons;
3. 2D constrained polygons with exact shared edges;
4. ramps and extruded profiles;
5. splines for roads, tunnels, and organic boundaries;
6. modular-kit sockets and parametric façades; and
7. local detail generation after the tactical shell passes tests.

Do not jump directly from natural language to arbitrary 3D vertices merely to gain expressiveness. Add a compiler-owned primitive to the DSL each time a real design need appears.
