Skip to content

The city spec ​

A city is a level drawn freely, the way the flagship Riverbend is: streets that curve, meet at any angle, ring the town and cross a river, quarters turned off the map's axes, roundabouts, crescents and closes, a hill with a road up to its lookout. Its spec ("template": "city") is data: roads drawn through points, and the rest named. The platform's solver (packages/catalogue/src/city/, its README) resolves it at once, without Blender, into a plan, and answers with the problems at their paths in the spec, or with a map of the city in text. The generator (assets/blender/levels/city.py) then builds the plan: the ground, the pavements, the bridges, the buildings of every district in its style, the street furniture, the parks and the life of the streets and the water.

Through the MCP server: level_spec_set with a city spec answers with its issues or its map; draft_build builds it. Locally: npm run level:city -- <spec.json> --check runs the solver alone; without --check it builds the level's kit and recipe into the kits folder, then level:recipe and level:export.

The frame ​

Everything is in metres, in the game's frame, the map's middle at [0, 0]:

  • a point is [x, z]: x grows westward (east is −x) and z northward. The map runs from −size/2 to size/2 both ways.
  • a bearing is a compass's, in degrees: 0 north, 90 east, 180 south, 270 west. Bearings are the map's everywhere, a grid's turn included (a roundabout's arms are not turned with a grid).

So [-100, 50] is 100 m east of the middle and 50 m north of it.

Names ​

  • Roads, grids, rivers, hills, roundabouts: lower-case words of letters and digits joined by dashes (bridge-street), 32 characters at most.
  • Districts and parks: lower-case words joined by underscores or dashes (old_town). They name places, whose ids take them with underscores (old_town.cafe_1, the park east_green).
  • Places: lower-case words joined by underscores, parts by dots (bridge_foot).

The fields ​

FieldWhat it says
template, namecity, and the level's name (test-<words>, main-<words>; the platform names a draft's itself).
seedEvery random choice comes from it.
sizeThe map's side, 240 to 1000 m (600 by default).
climate, clockThe weather's odds and the room clock, as for every template (see Time and weather).
gridsTurned grids of streets.
waterRivers (two at most): a level below the streets, bridges where roads cross them.
hillsHills outside the town.
roundaboutsRoundabouts and their islands.
roadsEvery other road.
districtsAt least one: each a style and a seed or an outline.
parksParks, greens and squares.
spawnThe road the players start on, and where along it.
placesNamed points for missions.

The town ​

The town is where the districts are built: inside the closed road that is its boundary when one is (beyond it is open country: woods, meadows, rocks), else the whole map less 12 m round its edge; never on the water, nor within a hill's reach (and 2 m more). A hill stands outside the town even without a boundary. Only one closed road bounds the town.

Points ​

Wherever a spec wants a point it takes one of these:

FormThe point
[x, z]Those coordinates.
{"grid": "mid", "at": [u, v]}A point of a grid, in its own frame: u metres toward its east, v toward its north.
{"roundabout": "circle", "arm": 90}Where the roundabout's arm at that bearing leaves it (the arm nearest, within 10°).
{"road": "quay", "at": "start"}A road's start, its end, or a distance along it in metres from its start.
{"hill": "knoll"}A hill's top.

A point may name anything, drawn before or after it: the solver draws what each needs first. A road that needs itself (two roads each ending on the other) is an issue.

Roads ​

json
{
  "name": "bridge-street",
  "class": "street",
  "from": { "roundabout": "circle", "arm": 0 },
  "through": [
    [-84, 0],
    [-80, 110]
  ],
  "to": { "onto": "bank-road" }
}
  • class: parkway (16 m, two lanes each way, fast), avenue (16 m), boulevard (14 m), street (11 m, a lane each way), lane (8 m), one-way (7.5 m, one lane, its traffic running from its start to its end).
  • from, through, to: where it starts, what it runs through (optional), where it ends; the road runs through all its points in that order. An end is a point, or {"onto": "<road>"}: the road is cut where it crosses that road, or its end stretch is lengthened (60 m at most, at its start as at its end) until it meets it. A roundabout's name means its whole circle, a closed road's name its whole ring. through takes points and bank stretches: {"bank": "river", "side": "left", "from": point, "to": point, "back": 14} runs along the river's bank from where the river passes nearest from to where it passes nearest to, back metres (4 to 60, 14 by default) from the water's edge to the road's centre line: a quay, an embankment. The side is the bank's looking downstream: a river flowing south has its left bank on its east.
  • line: spline (a smooth curve through the points, the default), straight (straight between them: a corner is a bend as tight as it is sharp, so a street's corner needs rounded), rounded (straight, each corner an arc of radius: one radius, or one per corner; 12 m by default) or eased (straight, each bend eased until no bend is tighter than radius, 12 m by default).
  • leaving, arriving: the bearing a spline leaves its start in, or arrives at its end in (a road leaving a roundabout straight out, say).
  • closed: a ring through its points, back to the first, a spline, straight or rounded (every corner); it takes no from or to. It is drawn as parts (<name>-1, <name>-2…) of about 500 m, three at least. boundary: true makes it the town's edge.
  • turningCircle: a close: its end is a paved turning circle.
  • cycle: a cycle lane painted along it.
  • to: {"hill": "knoll"}: the road climbs the hill to its top at one grade, over its whole length from its start: 12 % at most, so draw it long enough (a rounded serpentine's corners shorten it). A lookout stands at the top. It is the only road that climbs: the town's streets are flat.
  • step: how far apart its points are, 2 to 10 m (6 for a parkway, an avenue and a boulevard, 5 for the rest); 4 suits a tight serpentine.

Roads that cross meet in a junction, with rounded kerbs, crossings and, where an avenue or a parkway meets a street squarely, traffic lights. A road should start and end on something (a junction: onto, a roundabout's arm, a point of another road; a turning circle; a hill's top) or well clear of every other road: an end within a pavement or two of a road it does not join is an issue. A crescent runs from a road onto the same road; its ends may stop short of it (they are lengthened) or run past it (they are cut).

Grids ​

json
{
  "name": "mid",
  "origin": [40, -50],
  "bearing": 15,
  "class": "street",
  "u": [{ "at": -50, "to": { "onto": "quay" } }, { "at": 0, "class": "avenue" }, 50],
  "v": [-45, 5, 55]
}

A grid is a turned frame: its origin and the bearing its own north points to. u lists the streets running toward its north, by how far east of the origin they stand; v the streets running toward its east, by how far north. A line runs from the first to the last line of the other family unless it says otherwise: from is its south end (a u line) or its west end (a v line), in the grid's own frame, and to its other end; each takes a coordinate of the other axis, or {"onto": "<road>"} (the line runs on, however far, until it first meets that road). A line may be of another class than its grid's. Its streets are named <grid>-u<i> and <grid>-v<j>, i and j counting the lists from 0, so another road can end on them.

Rivers, hills, roundabouts ​

  • A river: through (points upstream to downstream, a smooth curve; draw it across the map and beyond), width (8 to 120 m, 30 by default), and widen: {"from": 0.6, "to": 0.8, "width": 90}, the shares of its length (all of it, drawn beyond the map too) between which it widens to that width; it stays that wide downstream, as an estuary or a harbour opening to the sea. Its water is a level below the streets. A road crossing it gets a bridge, if it crosses at 30° or more; roads never meet over the water.
  • A hill: its top at, its height (2 to 40 m) and reach (20 to 200 m: how far its slopes go). Nothing of the town stands on it; woods and rocks do.
  • A roundabout: its middle at, its radius (9 to 40 m, 22 by default: its carriageway's centre line), its arms (bearings, or {"toward": point}: the arm pointing at that point; three to eight), lanes (2 by default, or 1 for a small one) and its island: green (a monument, flower beds, trees; the default), market (a paved square with a fountain and stalls, its rim of bollards), plain. Roads start and end at its arms ({"roundabout": "circle", "arm": 0}); an arm no road takes is only where two arcs meet. A road may also end onto its circle, between two arms.

Districts and their styles ​

Each district is a style and either a seed at (a lot belongs to the nearest seed on the same side of the water) or an outline area, which wins over the seeds and needs no at: a list of points, or any of a park's areas ({"polygon"}, {"ellipse"}, {"circle"}, {"block"}). Seeds share the town by distance alone: for a district in the middle with others round it, give it an outline, or set the others' seeds evenly round it. A district's title is what the minimap shows; its landmarks are buildings it must have, by the catalogue's building archetypes or the tags they carry (town-hall, amenity=pub); without them it has its style's own (an old town's town hall, library and church), and "landmarks": [] gives it none.

StyleWhat it is built and dressed as
old-townTownhouses, shops, cafés, pubs and guest houses round lanes; a town hall, a library, a church.
civicPublic offices, a courthouse, a police and a fire station, colleges, a museum.
financialGlass and stone towers, banks, a hotel, a multi-storey car park.
midtownShops, apartments and offices; a mall, a hospital, a supermarket, a bus station.
townhousesApartments and townhouses with gardens; a school, a doctor, a bakery.
suburbHouses and townhouses on lawns, a chapel, a pub.
docksDepots, warehouses, factories and car trades, container yards, cranes on the quay nearest the water.
waterfrontHotels, glass towers, restaurants and bars by the water, boathouses, pools on the roofs.
high-streetShops and flats over them, pubs; a hospital and a sports centre.
garden-suburbHouses in gardens, fruit trees, a school.
worksWarehouses, factories, a brewery, storage, yards of scrap and skips.
parklandParkland with a few cafés and chalets; a stadium.
hillsideVillas, chalets and guest houses on lawns, a chapel.

They are Riverbend's thirteen quarters (packages/catalogue/src/city/styles.json): each style carries its mix of buildings, its density, its trees, the furniture of its pavements, its yards and its roofs.

Parks, the spawn, places ​

  • A park (kind: park or green, lawn and trees, the default park; square, paved) is an area: {"polygon": [points]}, {"ellipse": {"at", "size": [a, b], "bearing"}} (a and b its half-axes toward its own east and north, turned to bearing), {"circle": {"at", "radius"}}, or {"block": {"grid", "from": [u, v], "to": [u, v]}} (a block of a grid between its streets, inside their pavements). Its place is its name.
  • spawn: {"road", "near"}: four spawn points on that road (a town street, 30 m long at least) near that point (its middle by default), two each way.
  • places: [{"name": "bridge_foot", "at": point}].

The level also names every roundabout (its name, dashes as underscores), every hill's top, every bridge's middle (bridge.<road>, by the piece of road it carries) and every district's buildings and their anchors (<district>.<building>_<n>).

What the solver refuses ​

The solver checks in stages: the spec's fields first; then every name and every road drawn (a road that cannot be drawn is said once, at its own path, not again for the roads that need it); then the network and the districts. A stage with problems keeps the next from running, so fixing them may bring others. Each problem comes back at its path in the spec (roads[3].to, grids[0].u[1]), saying where on the map it is:

  • a name used twice, a name that names nothing, a road that needs itself;
  • an end onto a road it neither crosses nor reaches within 60 m;
  • a road shorter than it is wide, or bending tighter than its width allows (half its width and 2 m: 10 m for a parkway, 7.5 m for a street, 6 m for a lane);
  • two junctions under 16 m apart, roads meeting at under 35°;
  • a road leaving the map (its centre line keeps 2 m inside the edge);
  • an end that stops short of a road without joining it (say onto, or keep it clear);
  • two roads so near that no pavement fits between their kerbs, where they do not meet;
  • a river crossed at under 30°, a road ending or running in the water, roads meeting over it;
  • a street of the town climbing a hill (only a road ending at its top climbs), a climb over 12 %;
  • a district's seed in the water, outside the town or on a hill, a district left with no lot;
  • a spawn on a roundabout, on a climbing road or on a road under 30 m;
  • a city drawn as more pieces of road than a level holds (256: every road, grid line, roundabout's arc and closed road's part is one), said at roads before Blender runs.

A build passes with a warning, not an error, when a district's landmark found no lot along its streets: it stands nowhere, and the warning names it (give the district more street, or name fewer landmarks).

What version 1 does not build: sloping streets and buildings inside the town, tunnels, water at two heights, lakes, compounds.

The map ​

A spec the solver accepts comes back as text, north up and east to the right, a character every 8 to 20 m: the districts by their letters, # parkway, = avenue or boulevard, + street, - lane or one-way, o roundabout, ~ water, ^ hill, * park or square, S the spawn, . outside the town; under it the legend, then the spec's roads, grid lines and roundabouts, the pieces of road they are drawn as (a roundabout's arcs and a closed road's parts are pieces of their own), the length of road, the junctions and the bridges.

An example ​

test-city (its spec is apps/level-editor/assets/kits/test-city.spec.json, and the catalogue's template.city example): a 320 m town on a river's south bank, a grid of two by two blocks turned 15°, its avenue running east to a roundabout of three arms, a street from it over the river's one bridge, a quay along the south bank and a road along the north one, a crescent, a close, a knoll with a lane climbing to its lookout, three districts (an old town, the docks, the north bank) and a paved square.