This document describes the optional map.json file used by BeamNG levels to add manual navigation graph segments.
The navigation map is used by AI, traffic, navigation, route generation, and related gameplay systems. Most navigation data is generated automatically from DecalRoad objects and BeamNGWaypoint objects, but map.json allows level creators to manually define additional road/path segments.
map.json is placed in the level folder:
levels/<levelName>/map.json
Example:
levels/west_coast_usa/map.json
If map.json is missing, the navigation graph can still be generated from DecalRoad and BeamNGWaypoint objects.
Use map.json when automatic road graph generation is not enough.
Common use cases:
DecalRoadmap.json does not define visual road geometry. It only defines navigation graph connections between existing nodes.
The navigation graph is built from multiple sources:
BeamNGWaypoint objectsDecalRoad objects with drivability > 0map.jsonmap.json segments reference existing node names. These can be:
BeamNGWaypoint object namesDecalRoad objectsIf a node referenced in map.json does not exist, that segment cannot be fully created and an error may be logged.
map.json contains a top-level segments object.
{
"segments": {
"bridge1": {
"nodes": ["Bridge1_A", "Bridge1_B"],
"drivability": 1
},
"tunnel_A": {
"nodes": ["tunnel_A_1", "tunnel_A_2", "tunnel_A_3"],
"oneWay": true,
"flipDirection": false,
"lanesLeft": 1,
"drivability": 1
}
}
}
Each key inside segments is a segment name. The name is mainly for organization and debugging.
| Field | Type | Default | Description |
|---|---|---|---|
nodes |
array/string | required | Ordered list of node names that form the segment. |
drivability |
number | 1 |
Pathing preference/cost multiplier. Lower values are less preferred. |
oneWay |
bool | false |
Whether the segment is one-way. |
flipDirection |
bool | false |
Reverses the logical direction of the segment. |
speedLimit |
number | auto | Optional speed value in meters per second used by AI/navigation. Values <= 0 are treated as unset. |
type |
string | nil |
Road type metadata, for example private. |
gatedRoad |
bool | false |
Treats the segment as private/gated road data. |
hiddenInNavi |
bool | false |
Hides or de-emphasizes the segment in navigation display where supported. |
autoLanes |
bool | true |
If set to false, lane count is read from lanesLeft and lanesRight. |
lanesLeft |
integer | 0 |
Manual lane count for one side when autoLanes is false. |
lanesRight |
integer | 0 |
Manual lane count for one side when autoLanes is false. |
autoJunction |
bool | true |
If set to false, prevents automatic merging at this segment’s nodes. |
The nodes field defines the ordered path of the segment.
Example:
"nodes": ["Bridge1_A", "Bridge1_B", "Bridge1_C"]
This creates links:
Bridge1_A → Bridge1_B
Bridge1_B → Bridge1_C
For two-way segments, pathing can travel both directions. For one-way segments, travel direction depends on oneWay and flipDirection.
The nodes field can also be written as a string.
Example:
"nodes": "tunnel_A_1-tunnel_A_10"
This expands to:
tunnel_A_1
tunnel_A_2
tunnel_A_3
...
tunnel_A_10
Multiple ranges or individual nodes can be separated with commas:
"nodes": "Bridge1_A, tunnel_A_1-tunnel_A_10, Bridge1_B"
oneWay marks a segment as one-way.
"oneWay": true
The default travel direction follows the order of the nodes list.
Example:
"nodes": ["A", "B", "C"],
"oneWay": true
This creates a one-way path from:
A → B → C
flipDirection reverses the logical direction of the segment.
"flipDirection": true
Example:
"nodes": ["A", "B", "C"],
"oneWay": true,
"flipDirection": true
This creates a one-way path from:
C → B → A
Use this when the node order is convenient for editing, but the legal driving direction is the opposite.
drivability controls how desirable a segment is for pathfinding.
"drivability": 1
Typical values:
| Value | Meaning |
|---|---|
1 |
Normal road/path. |
0.5 |
Less preferred path. |
< 0.5 |
Strongly discouraged path. |
0 |
Extremely undesirable, but still internally guarded against invalid zero cost. |
Navigation cost increases as drivability decreases, so AI and routing systems prefer higher-drivability roads when possible.
speedLimit can be set per segment:
"speedLimit": 13.89
If speedLimit is missing or <= 0, the engine automatically estimates speed limits based on road width/radius, drivability, and road direction.
"speedLimit": 0
means “auto-calculate”.
speedLimit and let the engine calculate it automatically. Speed limit is set in meters per second.A segment can define a road type:
"type": "private"
You can also use:
"gatedRoad": true
When gatedRoad is true, the segment is treated as private-type road data.
Private roads affect routing and traffic behavior. When private roads connect to public roads, the navigation graph may mark connecting edges as gated so pathfinding treats them differently.
Use private/gated roads for:
Example:
"dirttrack": {
"nodes": ["dirttrack_1", "dirttrack_2", "dirttrack_3"],
"oneWay": true,
"drivability": 1,
"gatedRoad": true
}
hiddenInNavi can hide a segment from navigation display where supported:
"hiddenInNavi": true
This can be useful for:
The segment may still exist in the graph and be used by systems depending on context.
Lane information can be generated automatically or specified manually.
By default, lanes are generated from road width/radius and road rules.
"autoLanes": true
or omitted.
The engine uses level road rules from info.json:
"roadRules": {
"rightHandDrive": false
}
to decide lane-side assumptions.
Set autoLanes to false to use lane counts:
"autoLanes": false,
"lanesLeft": 1,
"lanesRight": 1
For one-way roads, lane data can result in a one-way lane string internally.
The internal lane string uses:
+ = direction from inNode to outNode
- = direction from outNode to inNode
The lane order depends on the level’s rightHandDrive road rule.
lanesLeft and lanesRight are interpreted together with roadRules.rightHandDrive from info.json.map.json uses road rules from info.json.
Example:
"roadRules": {
"rightHandDrive": false,
"turnOnRed": true
}
Relevant field:
| Field | Used by map graph? | Description |
|---|---|---|
rightHandDrive |
Yes | Affects automatic/manual lane direction interpretation. |
turnOnRed |
Indirectly | Used by traffic/navigation systems where applicable. |
rightHandDrive does not visually change the road. It affects how navigation lane data is interpreted/generated.
By default, the navigation graph performs automatic merging and junction processing.
Set:
"autoJunction": false
to prevent automatic merging at the segment’s nodes.
Internally, this marks the segment/node data as noMerge.
Use this for:
Example:
"junction_helper": {
"nodes": ["j1", "j2", "j3"],
"autoJunction": false,
"drivability": 1
}
After loading DecalRoad, BeamNGWaypoint, and map.json data, the engine processes the navigation graph.
The process includes:
map.json segmentsBecause of this, the final runtime graph may not exactly match the raw input file.
{
"segments": {
"bridge1": {
"nodes": ["Bridge1_A", "Bridge1_B"],
"drivability": 1
}
}
}
This creates a normal two-way segment between Bridge1_A and Bridge1_B.
{
"segments": {
"bridge2": {
"nodes": ["Bridge2_A", "Bridge2_B"],
"oneWay": true,
"flipDirection": true,
"drivability": 1
}
}
}
This creates a one-way segment using the reverse of the listed node order.
{
"segments": {
"tunnel_A": {
"nodes": [
"tunnel_A_1",
"tunnel_A_2",
"tunnel_A_3",
"tunnel_A_4"
],
"oneWay": true,
"autoLanes": false,
"lanesLeft": 1,
"lanesRight": 0,
"drivability": 1
}
}
}
{
"segments": {
"dirttrack": {
"nodes": ["dirttrack_1", "dirttrack_2", "dirttrack_3"],
"oneWay": true,
"flipDirection": false,
"drivability": 1,
"gatedRoad": true
}
}
}
This segment is treated as private/gated road data.
{
"segments": {
"tunnel_city_A": {
"nodes": "tunnel_city_A_1-tunnel_city_A_63",
"oneWay": true,
"lanesLeft": 1,
"drivability": 1
}
}
}
This is equivalent to listing every node manually from tunnel_city_A_1 to tunnel_city_A_63.
Manual segments often rely on BeamNGWaypoint objects placed in the level.
Example waypoint object:
{
"class": "BeamNGWaypoint",
"name": "tunnel_A_1",
"position": [100, 200, 5],
"scale": [1, 1, 1]
}
The map.json segment can then reference it:
"nodes": ["tunnel_A_1", "tunnel_A_2"]
If a waypoint has excludeFromMap, it is not added automatically to the navigation graph.
Useful debugging tools/functions include:
The map system can export a simplified SVG view of the graph for inspection.
Common debug visualization shows:
DecalRoad for normal roads when possible.map.json only for manual corrections and special connections.map.json exists.oneWay and flipDirection carefully.autoJunction: false around complex overpasses, tunnels, or close parallel roads.gatedRoad or type: "private" for non-public routes.drivability close to 1 for normal roads.drivability for rough or less preferred routes.speedLimit unless a specific value is required.Possible causes:
map.json is missing or invalidsegments object is missingCheck:
"oneWay": true,
"flipDirection": true
If the direction is reversed, toggle flipDirection.
Check:
autoLaneslanesLeftlanesRightroadRules.rightHandDrive in info.jsonSet:
"autoJunction": false
on affected manual segments.
Check gatedRoad, type, and how private roads connect to public roads.
Remove speedLimit to allow automatic calculation, or verify that the value is correct for the intended road.
map.json is an optional manual navigation graph file.
It defines additional path segments between existing navigation nodes and is mainly used for special cases such as tunnels, bridges, overpasses, private roads, and complex intersections.
The main structure is:
{
"segments": {
"segment_name": {
"nodes": ["node_a", "node_b"],
"drivability": 1
}
}
}
Most roads should be generated from DecalRoad objects. Use map.json when you need precise manual control over AI/navigation connectivity or you cannot use decal roads on your level.
Was this article helpful?