Navigation Map (map.json)

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.


File location

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.


Purpose

Use map.json when automatic road graph generation is not enough.

Common use cases:

  • Tunnels
  • Bridges
  • Overpasses
  • Complex intersections
  • Roads not represented well by DecalRoad
  • Manually controlled one-way paths
  • Private/gated roads
  • Special AI/navigation connectors
  • Hidden navigation links

map.json does not define visual road geometry. It only defines navigation graph connections between existing nodes.


Relationship with DecalRoad and BeamNGWaypoint

The navigation graph is built from multiple sources:

  1. BeamNGWaypoint objects
  2. DecalRoad objects with drivability > 0
  3. Manual segments from map.json

map.json segments reference existing node names. These can be:

  • BeamNGWaypoint object names
  • Nodes generated from DecalRoad objects
  • Other existing navigation nodes

If a node referenced in map.json does not exist, that segment cannot be fully created and an error may be logged.


Basic structure

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.


Segment fields

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.

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.


Node string shorthand

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"
For range expansion, both ends must use the same text prefix and numeric suffix pattern.

Direction

oneWay

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

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

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.


Speed limit

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”.

If you are unsure, omit speedLimit and let the engine calculate it automatically. Speed limit is set in meters per second.

Road type and private roads

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:

  • Restricted areas
  • Dirt tracks
  • Service roads
  • Parking lots
  • Race tracks
  • Non-public roads

Example:

"dirttrack": {
  "nodes": ["dirttrack_1", "dirttrack_2", "dirttrack_3"],
  "oneWay": true,
  "drivability": 1,
  "gatedRoad": true
}

Hidden navigation segments

hiddenInNavi can hide a segment from navigation display where supported:

"hiddenInNavi": true

This can be useful for:

  • Internal connectors
  • Service links
  • AI-only helper paths
  • Hidden tunnel links
  • Non-user-facing navigation routes

The segment may still exist in the graph and be used by systems depending on context.


Lane data

Lane information can be generated automatically or specified manually.

Automatic lanes

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.

Manual lanes

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.

Road rules interaction

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.


Auto junction merging

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:

  • Complex intersections
  • Parallel roads close together
  • Tunnel ramps
  • Bridges/overpasses
  • Places where automatic merging creates incorrect connections

Example:

"junction_helper": {
  "nodes": ["j1", "j2", "j3"],
  "autoJunction": false,
  "drivability": 1
}

Generated graph processing

After loading DecalRoad, BeamNGWaypoint, and map.json data, the engine processes the navigation graph.

The process includes:

  1. Loading road and waypoint data
  2. Adding manual map.json segments
  3. Creating/estimating speed limits
  4. Merging overlapping nodes
  5. Resolving T-junctions
  6. Resolving X-junctions
  7. Merging nodes to nearby lines
  8. Processing private/gated roads
  9. Optimizing/simplifying nodes
  10. Converting the graph to single-sided edge storage
  11. Building spatial acceleration structures for pathfinding

Because of this, the final runtime graph may not exactly match the raw input file.


Example: simple two-way bridge

{
  "segments": {
    "bridge1": {
      "nodes": ["Bridge1_A", "Bridge1_B"],
      "drivability": 1
    }
  }
}

This creates a normal two-way segment between Bridge1_A and Bridge1_B.


Example: one-way bridge

{
  "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.


Example: tunnel with manual lanes

{
  "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
    }
  }
}

Example: private dirt track

{
  "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.


Example: range shorthand

{
  "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.


Relationship with BeamNGWaypoint

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.


Debugging

Useful debugging tools/functions include:

  • Navigation graph debug drawing
  • Graph hash logging
  • Closest road queries
  • Path queries
  • SVG export of the map graph

The map system can export a simplified SVG view of the graph for inspection.

Common debug visualization shows:

  • Junction nodes
  • Road widths
  • Lane directions
  • Drivability colors
  • Gated/private roads

Best practices

  • Use DecalRoad for normal roads when possible.
  • Use map.json only for manual corrections and special connections.
  • Make sure every node referenced by map.json exists.
  • Avoid duplicate consecutive nodes in a segment.
  • Use oneWay and flipDirection carefully.
  • Use autoJunction: false around complex overpasses, tunnels, or close parallel roads.
  • Use gatedRoad or type: "private" for non-public routes.
  • Keep drivability close to 1 for normal roads.
  • Use lower drivability for rough or less preferred routes.
  • Omit speedLimit unless a specific value is required.
  • Keep segment names descriptive.

Common issues

Segment does not appear in navigation

Possible causes:

  • map.json is missing or invalid
  • segments object is missing
  • First node in the segment does not exist
  • A later node does not exist, causing the segment to stop
  • Referenced waypoints are excluded from the map

AI drives the wrong direction

Check:

"oneWay": true,
"flipDirection": true

If the direction is reversed, toggle flipDirection.

Lanes behave incorrectly

Check:

  • autoLanes
  • lanesLeft
  • lanesRight
  • roadRules.rightHandDrive in info.json

Roads merge incorrectly

Set:

"autoJunction": false

on affected manual segments.

Route uses private roads unexpectedly

Check gatedRoad, type, and how private roads connect to public roads.

Speed feels wrong

Remove speedLimit to allow automatic calculation, or verify that the value is correct for the intended road.


Summary

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.

Last modified: May 28, 2026

Any further questions?

Join our discord
Our documentation is currently incomplete and undergoing active development. If you have any questions or feedback, please visit this forum thread.