Locations
locationsLocations are the named places on the map - cities, ruins, dungeons, waypoints - the specific points of interest players visit inside a region.
"Specific places within regions (cities, dungeons, etc.)"
- Editor location
- Files → World → Locations
- Editor type
- Edit in Studio + View JSON
- API endpoint
/sections/locations.json/sections/locations.md- Size limits
locations.*.basicInfo— 4,000locations.*.hiddenInfo— 4,000locations.*.areas.*.description— 4,000locations(entire section) — 2,000,000
Schema
{
"locations": {
"<key>": {
"name": "string",
"basicInfo": "string",
"x": "number",
"y": "number",
"region": "string",
"radius": "number",
"complexityType": "simple | complex | wilderness",
"detailType": "basic | detailed",
"areas": {
"<key>": {
"description": "string",
"paths": [
"string"
],
"images": {
"establishingShot": {}
},
"visualTags": [
"string"
]
}
},
"factions": [
"string"
],
"visualTags": [
"string"
],
"hiddenInfo": "string",
"known": "boolean",
"npcLevelRange": {
"min": "number",
"max": "number"
},
"images": {
"establishingShot": {
"crop": {
"focus": "...",
"zoom": "..."
},
"imageUrl": "string"
}
}
}
}
}Example
{
"locations": {
"The Capital": {
"name": "The Capital",
"basicInfo": "The largest city in the realm. A walled city of towers, markets, and bureaucracy. The ruling council's seat dominates the skyline. Gatekeepers at every entrance, petitioners in every corridor, and information that costs money to obtain.",
"x": -27,
"y": 5,
"radius": 6,
"region": "The Heartland",
"complexityType": "complex",
"detailType": "detailed",
"hiddenInfo": "A criminal syndicate has an active cell operating in the lower district. The mage guild's restricted archive holds three documents officially declared destroyed.",
"areas": {
"Council Hall": {
"description": "The formal chamber of the ruling council. Stone galleries and tiered seating for petitioners, every surface worn smooth from centuries of use. The air carries the smell of old paper and lamp oil. Guards at every door watch the visitors more than the council members.",
"paths": ["Market Quarter", "Academy Gate"]
},
"Market Quarter": {
"description": "The city's commercial heart — a permanent noise of competing vendors, loaded carts, and shouted prices. Dense enough that a conversation can happen three feet from a city watchman without being overheard. Merchants here know where information is bought and sold as well as goods.",
"paths": ["Council Hall", "Lower District", "Academy Gate"]
}
},
"factions": ["The Merchant Council", "The Mage Guild", "The City Watch"],
"known": true
}
}
}Simple location (no areas):
{
"Border Watchtower": {
"name": "Border Watchtower",
"basicInfo": "One of the frontier's forward observation posts. Manned by a rotating garrison detachment. Sparse, functional, and chronically under-supplied.",
"x": 12,
"y": -8,
"radius": 2,
"region": "The Frontier",
"complexityType": "simple",
"detailType": "basic",
"areas": {},
"factions": ["The Border Watch"],
"hiddenInfo": "The garrison rotation is on a fortnight cycle and the next swap is two days late. The current crew know it; the Border Watch command does not.",
"known": true
}
}Each location must be a plain object with all fields merged (not an array or split objects).
Note: Validator errors show
locations.key.0.fieldName— the.0/.1are io-ts union/intersection branch indices. Value must be a plain object.
Note:
hiddenInfois available to the AI during play but players never see it directly. The AI uses it to stay consistent with the world's secrets - dropping hints in atmosphere and description rather than stating secrets outright. This pattern applies consistently across locations, NPCs, and factions:basicInfois the surface,hiddenInfois what drives the AI's behavior beneath it. On regionshiddenInfois unused — put region secrets in a location or NPC instead.
Fields
name
Display name of the location, and must be byte-identical to the outer map key — the engine matches entries by key, so the key and name have to be exactly equal (same case, same spaces). A mismatch is a validation error. Build the map as { location["name"]: location }. (Area keys inside areas follow the same display-name rule — see areas below.)
complexityType
"simple" | "complex" | "wilderness". The correct field name is complexityType, not complexity. Using the shortened form complexity is not a valid schema field and is ignored by the codec. "linear" is NOT a valid value. Use "complex" for any location with multiple areas.
detailType
"basic" or "detailed" — required field (codec-enforced). Determines whether quests use spatialRelationship or questLocation. Omitting it causes a validation error.
areas
areas use description not basicInfo. Production area descriptions run 200–400 chars — significantly longer than a single sentence. A strong area description covers three things: (1) physical character of the space, (2) what function or activity happens here, (3) one atmospheric or sensory detail that makes the area distinct. The third element — a smell, a sound, a social rule, a visual anomaly — is what makes areas feel inhabited rather than labelled.
Area keys must be display names, not snake_case. The area key is what the game displays to the player — "Council Hall" not "council_hall". Using snake_case produces ugly output like "The Capital - Council_hall" in the location bar. The key is also referenced directly in paths, npcs.currentArea, and storyStarts.locationAreas — a rename requires updating all three, so get the names right from the start.
Warning: Location area objects use
"description", not"basicInfo". UsingbasicInfoin an area object causes silent failure — the area appears but with no description. The correct field is"description".
An area's own artwork takes the same images.establishingShot object, with the same crop framing, as the location's.
factions
Optional Array<string>. Array of faction display-name strings associated with this location. Names must exactly match faction keys. Tells the narrator which factions have a presence here, influencing NPC affiliations and political framing in the scene.
npcLevelRange
Optional { min, max } integer band constraining the levels of AI-generated NPCs in this specific location. Takes priority over the parent region's npcLevelRange for NPCs generated here. Use it for outliers -- a high-tier dungeon inside a low-tier region, or a starter-friendly hub inside a high-tier region. NPCs with an explicit authored level ignore the band; only level-less generated NPCs are rolled near party level and then clamped into it. Omit to inherit the region's band (or the engine default when the region has none).
images.establishingShot.imageUrl
Optional string. URL of a banner or map image for this location, shown in the location view. A location image is shown two ways in play: a tall full-screen card on arrival, and a wide banner under Map → Location. Both are crops of the same file, so no single size avoids cropping — keep the subject centred and clear of the edges. Minimum 600×600. In the editor you can upload your own image or generate one from a prompt — both set this URL.
images.establishingShot.crop.focus.x
Positions the visible window over the source image along the horizontal axis, as a percentage: 0 holds the left edge, 50 centres it, 100 holds the right edge. Saved by the crop control rather than typed by hand, and applied wherever Voyage shows the image.
images.establishingShot.crop.focus.y
Positions the visible window over the source image along the vertical axis, as a percentage: 0 holds the top edge, 50 centres it, 100 holds the bottom edge. Saved by the crop control rather than typed by hand, and applied wherever Voyage shows the image.
images.establishingShot.crop.zoom
Scales the image inside its frame, as a percentage of the unzoomed fit: 100 fills the frame with no magnification, 150 shows it at one and a half times, cropping to the area picked by the focus fields. Saved by the crop control rather than typed by hand, and applied wherever Voyage shows the image.
basicInfo
The public-facing description of a location. It should answer: what is this place, who is here, and what is the dominant feeling of being in it? Keep it to 2–3 sentences.
x
Horizontal coordinate within the parent region's cell, ranging from -regionSize/2 to +regionSize/2 (regionSize lives in Location Settings, default 100 so -50 to +50). The unit is local kilometres, and the two coordinate systems compose: a location's global position is region.x * regionSize + x, and the same for y. The Builder's Map view sets it by dragging.
y
Vertical coordinate within the parent region's cell, same range as x; positive y is north. The Builder's Map view sets it by dragging.
radius
The location's size on the map, as a positive number in local kilometres. Worlds commonly author 1, 2, or 3, which is a convention rather than a limit — any positive value is accepted, and the map marker is drawn from the value itself rather than from a fixed set of size classes.
The radius is also the travel catchment. A coordinate belongs to a location when it lies within that radius of the centre, and where two locations both contain a point, the one with the smaller radius takes it. Keep circles from overlapping so arrivals resolve where you expect, and give a location that should win a contested area the tighter radius rather than the wider one.
region
Key of the parent region in regions; the location renders inside that region's map cell.
visualTags
Visual metadata tags for the location.
known
Whether the location starts revealed to players; defaults to true, set false to hide it at game start.
paths
Required key in every area object. Every area must include "paths": [] even if it has no connections. Paths must reference sibling area keys that exist within the same location. Do not reference keys from other locations — paths are intra-location only. For cross-location travel, use triggers (party-location effect) instead and leave the source area's paths empty if it has no intra-location connections. Deleted areas must have their paths references removed from all other areas. Paths must be symmetric: if area A lists area B, area B must list area A back.
Movement and engine behavior
Movement types
Four distinct movement modes the engine recognizes:
| Type | Scope | Behavior |
|---|---|---|
| MOVE | Within a location | Moves between areas using paths. Respects the path graph. |
| TRAVEL | Between locations | Moves between locations via map coordinates. Distance and travel time apply. |
| TELEPORT | Anywhere | Bypasses all distance, path, and travel constraints. Instant. |
| FAST TRAVEL | Anywhere | Like teleport with explicit targeting — bypasses constraints but player must name a destination. |
MOVE is the default within a complex location. TRAVEL is the default between locations. TELEPORT and FAST TRAVEL are instant modes the engine resolves when a skill, ability, item, or area description names the destination location (see Realm travel); triggers can also invoke them directly.
generateLocationDetails trigger
generateLocationDetails generates areas (with descriptions and paths) and hiddenInfo for locations that don't yet have that detail. It reads the existing basicInfo as its creative foundation. Only applies to complexityType: "complex" locations — simple and wilderness locations are not processed. Locations with detailType: "detailed" and fully authored content skip this task.
Wilderness fallback
When the party ends a scene in untracked space and no permanent settlement is established, the engine falls back to a synthetic location named Wilderness with area Wilderness. Parsing is case-insensitive on the AI side, so wilderness, Wilderness, and WILDERNESS all canonicalize to the same Wilderness location.
Authoring tips
Simple vs complex
complexityType: "simple"— a single point of interest with no internal navigation. Good for taverns, shrines, waypoints.complexityType: "complex"— multiple areas connected bypaths. Use for dungeons, cities, estates, major landmarks.
Complex location design
- Give 4–6 areas minimum for a dungeon or major landmark.
- Make sure
pathsare bidirectional where logical (if you can walk from A to B, usually you can walk back). - Put different encounters, NPCs, or items in each area — don't duplicate.
- Use
hiddenInfoat the location level for secrets that only reveal after exploration or specific quest progress.
Areas inside a complex location
areas within a complex location define the navigable sub-zones. A city needs at minimum a public space and a private one — the distinction creates social texture. paths should be symmetric: if Market Quarter lists Council Hall as a path, then Council Hall should list Market Quarter back.
Settlements need a social area
Settlements (locations with NPCs, quest hooks, or hospitality) should include at least one social gathering area — a tavern, market, plaza, parlor, or equivalent — where the player can seek information and quests.
Endgame locations
- Be
known: falseinitially — they're discovered, not given. - Have 3–5 areas forming a linear or branching progression.
- Have their own
hiddenInfothat recontextualises something the player thought they knew. - Be tied to at least 2–3 quests (discovery quest, objective quest, resolution/ending quest).
Region coverage
Every region should have 3+ locations. A region with 1 location has no internal exploration. Minimum: one settlement/hub, one wilderness/danger site, one ruin/secret site.
Map and radius
radius is measured from the centre outward, so a radius of 3 spans 6 across and reaches roughly 2 steps on the diagonal. Overlapping circles are resolved rather than rejected — a point inside two locations goes to the one with the smaller radius — but keeping them apart is still the way to be sure arrivals land where you intended.
There is no street view in the game — players cannot navigate inside a location visually. Use areas within a complex location to represent navigable sub-zones. Multiple separate location circles in a region can make a dense area (like a city) feel more navigable on the map.
Packing tip: You can fit more locations together by offsetting their y-coordinates. Two locations with radius 3 can sit adjacent without overlapping if one is shifted vertically, since the diagonal distance between circles is ~1.5× the horizontal distance.
City design choice: A city can be one large complex location (single circle, many areas) or multiple smaller complex locations filling a region. Multiple circles are more map-readable; a single circle with many areas gives deeper internal navigation.