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). A new city is 1000 m (see Every capability).
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.
reliefThe town's own ground rising and falling: rises and slopes its streets climb.
lakesLakes in the town, their water just under the ground round them.
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); and the roads of the open country: country (7 m, a lane each way, 72 km/h) and track (5 m, a lane each way, 36 km/h). See Country roads and tracks.
  • 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.
  • tunnel: it runs under the hills in its way at its own level (the town's, on its relief) instead of being refused for climbing them: where a hill stands 6.5 m and more over it across its cutting (9 m either side of its edges), for 16 m and more, it is in a tunnel (the hill's surface rebuilt as a roof over the cutting that fades over a player under it, a stone portal at each end with its lamps, lamps along its walls), at the hill's feet in a cutting; nothing grows over the roof. A road that tunnels under no hill, a climbing road that tunnels, and a junction inside a tunnel are refused.
  • to: {"hill": "knoll"}: the road climbs the hill to its top at one grade, over its whole length from its start: 12 % at most (a track 12.5 %, the region template's), 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 a hill: the town's streets climb only its relief.
  • 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).

Country roads and tracks ​

A country road and a track are roads of the open country, the region template's classes in a city: no pavement, no kerb, no building fronting them (the walks of the buildings, the street furniture, the crossings and the traffic lights keep to the town's streets), a strip of grass 4 m wide each side graded to their edges, trees on it every 14 to 24 m and runs of post-and-rail fence behind them along about half their length. A country road is asphalt with an edge line and a dashed centre line, lit by a lamp near each junction it meets and nowhere between; a track is dirt, drawn brown with no paint, unlit, and climbs a hill at 12.5 % (to: {"hill": …}). Both carry their class to the level (RoadDef.kind), so the ambient traffic on them is the country's: pickups, tractors, the odd car. They belong out past a boundary road (a farm road off the ring, a track up a hill), but run anywhere: through a block of the town they cut it without a pavement, and a lake may come within 1.5 m of their edge. Two roads running close beside each other are never refused for the pavement between them when one is a country road or a track.

json
{
  "name": "farm-road",
  "class": "country",
  "from": { "onto": "ring" },
  "through": [
    [370, -10],
    [420, -40],
    [470, -160]
  ]
}

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. Timber jetties stand out from its banks, boats moored at each: one about every 250 m inside the map, on alternate banks, unless it lists its own jetties ([{"side": "left", "at": 0.8}]: its bank looking downstream, and how far along it as a share of its length; [] for none). A jetty that would stand by a bridge, or out over no water, is left out.
  • 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. A green island's six trees are a palm, a poplar and a cypress by turns from one roundabout to the next, or its own trees (one tree of the shared kits: nature/tree-palm, nature/tree-cypress, city/pine…). 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.

The relief ​

The town's ground need not be flat: relief lists rises and slopes, added together, and the whole city (its streets, its lots, its parks, its pieces and places) stands on their sum.

json
"relief": [
  { "kind": "rise", "at": [-75, 105], "height": 5, "reach": 110 },
  { "kind": "slope", "from": [0, -95], "to": [0, -150], "height": 4 }
]
  • A rise (kind: "rise"): a bell, its top at, height metres (1 to 30) over the town, its slopes reaching reach metres (30 to 400) from its top. Unlike a hill it is the town's: its streets run over it, its districts are built on it.
  • A slope (kind: "slope"): the ground rising height metres (1 to 30) between the line through from and the line through to, both square to the way from one to the other, eased in and out, level either side: the town stays that much higher beyond to, a terrace or a valley's side.

The city is built flat, then lifted by the relief: every road, piece and place by its height there, every building and what stands on it (its parts, its roof's things, its anchors) by its pad, a level plinth at the height of the pavement at its entrance, the ground built round it (a plinth's wall where it falls away, a cut where it rises); a building is not built where the ground under it falls more than 3 m below its entrance or rises more than 3.5 m over it. A road over the relief leans with it across its width. The solver refuses a rise or a slope steeper than 25 % anywhere, a street climbing more than 12 % over it (a climb up a hill counts it too), a road leaning across it so much that its edges stand more than 0.4 m over or under its middle (8 % for a street, 5 % for an avenue: run streets up the slope rather than across it), any of it within 24 m of a river (the quays and the bridges stand at the streets' level), a roundabout where it rises more than 1 m across, and a lake or a compound where it rises more than 0.3 m.

Lakes ​

json
"lakes": [{ "name": "pond", "area": { "circle": { "at": [0, -82], "radius": 11 } }, "depth": 2.5 }]

A lake is an area (any of a park's areas) whose ground shelves down from its shore to its depth (1 to 5 m, 2.5 by default) under its water, which lies half a metre under the ground round it: wherever that ground stands, so a lake on a rise is water at another height than the river's (or another lake's). A lake may lie in a park (it wins over the park's lawn). Nothing stands on it; its place is its name (on its water). It keeps clear of every road's pavement and a metre more, of the hills and of the rivers (30 m: their water stands at two heights), and of the other lakes; it lies where the relief is level.

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), the big ones one walks into and climbs among them (castle, mega-mall, general-hospital, mensa, ski-lodge: a castle needs a lot 44 m square along the district's streets, else the build says it is missing); 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.

A district may say more than its style, field by field, as a grid town's district does:

  • mix: the buildings it is built of, with their weights, over its style's ({"cafe": 2, "shop=*": 1, "family:industrial": 1}: archetypes, tags or wildcards, as in Levels);
  • landuse (retail, commercial, residential, industrial, …): without a mix of its own, it is built of that landuse's buildings made from OpenStreetMap's tags;
  • theme (a satire theme: high-street, tech-campus, wellness-quarter…): its buildings' invented names, its title and its colours; its style's buildings stay unless it names a mix or a landuse;
  • density: {"built": 0.7, "setback": 3, "height": "low"}, each field over its style's;
  • cranes: how many cranes stand on its quay (0 to 8; three in a docks district, none elsewhere), along its street with the most of its length by the water. A district that asks for cranes and has no street along the water is refused.
  • compound: a walled compound (a corporate campus, as a grid town's compounds, Levels) on the district's largest lot free of its streets' pavements, the water, the parks and the lakes, 78 m a side at least (its walls 66 m, a strip of lawn of 6 m inside the lot) and cut to 112 m a side from its main gate's wall: {"gate": "south", "delivery": "east", "gap": "west", "roof": true, "security": "medium", "title": "Zenful Campus"}. gate is the side of its main gate (a barrier and a door locked by keycards, a guardhouse), which must face a street; delivery and gap walls beside the gate's (a delivery gate locked by a keycard; a gap where the wall fell in); roof an annex across the back wall with fire stairs over it; security low, medium (the default) or high (its cameras and its guards on schedules by the room clock); its title and theme (its district's by default) name its company; its name (its district's by default) prefixes its places (<name>.gate, <name>.lab, <name>.hq…). The district's buildings stand round it on the rest of its lots; give it "landmarks": [] when the compound takes its whole block.

The style still dresses it (its trees, its pavements' furniture, its yards and 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. Trees stand wherever there is room, its kind's or its own trees (one to six of the shared kits' trees, picked at random). What stands in it is its things, set before its trees: [{"piece": "urban/carousel", "at": [14.5, -3.5], "face": 0}], a prop of the shared kits (a court, bleachers, a memorial, a statue, a carousel, a food truck, café tables, a swing set, benches: the catalogue's kit-piece entries of kind prop), at metres toward the park's own east and north from its middle (its frame turned by an ellipse's or a grid block's bearing, as a grid's), face the bearing its front faces from the park's own north (0 by default); a thing that would not fit on the green clear of the streets is left out. A court, an outdoor gym, a toilet block, a kiosk, a swing set or a memorial is a place too (<park>.<piece>). Riverbend's spec (packages/catalogue/src/city/fixtures/main-riverbend.spec.json) dresses its four parks this way.
  • 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, and a road with tunnel runs under it), a climb over 12 % (a track's over 12.5 %);
  • a relief too steep, a street climbing or leaning too much over it, a relief by the water, a roundabout, a lake or a compound on its slope (see The relief);
  • a road with tunnel under no hill high enough, a climbing road that tunnels, a junction in a tunnel;
  • a lake on a road, a hill or another lake, by a river or out of the town;
  • a compound with no lot 78 m a side, its gate on a wall facing no street, its delivery gate or gap on a wall not beside the gate's;
  • 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).

A city with none of relief, tunnel, lakes, a compound, a country road or a track is built byte for byte as one was before they existed.

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, : country road or track, 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.

Every capability ​

A new city is 1000 m a side: the studio's New starts from the catalogue's large city (LARGE_CITY in packages/catalogue/src/entries.ts, the template.city entry's example, and the creator card's worked example), which uses all of it and solves as it is: a parkway ringing the town (closed, boundary: true); a downtown grid turned 12° whose avenue runs across the town from the ring to the ring and over the river on a bridge; a river across the north, the ring bridging it twice; a street under a knoll in a tunnel (and over the river on its own bridge); a rise in the West End its streets climb (relief); a lake in a park (lakes); six districts; and beyond the ring a country road out to a farm gate and a dirt track up to the beacon's top, a hill 24 m high. Grow it, cut it, move it: every field it uses is described above.

An example ​

test-city (its spec is apps/level-editor/assets/kits/test-city.spec.json, and the studio's and the API's tests' small example, EXAMPLE_CITY): 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. test-city-terrain (apps/level-editor/assets/kits/test-city-terrain.spec.json) is the terrain's: a grid of three by three blocks on a rise and a slope, a street under a knoll in a tunnel, a pond and a tarn up on the rise, Zenful Campus, a district's compound, a country road across a block in the east (farm-road) and a dirt track from the east's last street up to the tarn (tarn-track).