This page describes level-local crawl data.
Crawl data defines off-road trail gameplay through companion files for trails, paths, boundaries, and starting positions. Some crawl missions can also carry mission-local crawl files under gameplay/missions/.
Level crawl data is stored under:
levels/<levelName>/crawls/
Common file names:
<crawlName>.trail.json
<crawlName>.path.json
<crawlName>.boundary.json
<crawlName>.startingPosition.json
presets.json
The crawl save/load system recognizes files by suffix. Keep the suffixes exact:
.trail.json
.path.json
.boundary.json
.startingPosition.json
Use the Crawl Data Editor for new crawl content when possible. It writes the companion files in the format expected by the crawl system.
Recommended workflow:
levels/<levelName>/crawls/.If you are converting older race/path data, use the conversion tools first, then manually review the generated files.
Manual authoring works best when you create the companion files in this order:
*.path.json*.boundary.json*.startingPosition.json*.trail.jsonThe trail file should be last because it references the other files.
Minimal folder layout:
levels/<levelName>/crawls/example.path.json
levels/<levelName>/crawls/example.boundary.json
levels/<levelName>/crawls/example.startingPosition.json
levels/<levelName>/crawls/example.trail.json
Use matching base names where possible. Matching names are not strictly required, but they make authoring and debugging much easier.
| File | Purpose |
|---|---|
*.trail.json |
High-level trail descriptor. References path, boundary, starting position, preview, rules, and optional prefabs. |
*.path.json |
Ordered route nodes, checkpoint data, radii, rotations, and node flags. |
*.boundary.json |
Playable area polygon/volume data. |
*.startingPosition.json |
Spawn/recovery transform and icon position. |
presets.json |
Optional editor presets for crawl authoring. |
A trail file links the companion files together with fields such as:
{
"pathId": "/levels/example/crawls/example.path.json",
"boundaryId": "/levels/example/crawls/example.boundary.json",
"startingPositionId": "/levels/example/crawls/example.startingPosition.json"
}
Use level-rooted paths and keep referenced files in sync when renaming a crawl.
Trail files are the highest-level crawl files. They do not usually contain the full path or boundary inline; they point at the companion files. This makes it possible to reuse or swap path, boundary, or starting position data, but it also means broken references can make an otherwise valid crawl invisible or unusable.
When writing a trail manually, start with only the required references and add optional metadata later:
{
"name": "trail.example.title",
"pathId": "/levels/example/crawls/example.path.json",
"boundaryId": "/levels/example/crawls/example.boundary.json",
"startingPositionId": "/levels/example/crawls/example.startingPosition.json",
"pathReversed": false
}
Add preview, thumbnail, rules, and prefabs after the trail loads successfully.
*.trail.json fields
| Field | Required | Notes |
|---|---|---|
name |
Recommended | Display name or translation key. |
description |
Optional | Description or translation key. |
pathId |
Yes | Path to *.path.json. |
boundaryId |
Yes | Path to *.boundary.json. |
startingPositionId |
Yes | Path to *.startingPosition.json. |
startingPositionIdReversed |
Optional | Reverse-direction starting position. |
pathReversed |
Optional | Whether the path should be read in reverse. |
thumbnail |
Optional | UI thumbnail path. |
preview |
Optional | UI preview path. |
rules |
Optional | Crawl rule settings. |
prefabs |
Optional | Supporting prefab references. |
metadata |
Optional | Created/modified/version information. |
isFromMission |
Optional | Marks mission-owned trail data. |
Path files store ordered route nodes. Nodes can include:
The path should follow the intended driving direction. If a trail supports reverse driving, prefer using explicit reverse settings rather than duplicating nearly identical paths unless the reverse route needs different checkpoints.
For hand-written paths:
Minimal *.path.json:
{
"name": "example_path",
"description": "Example crawl path",
"nodes": [
{
"name": "Start",
"position": [0, 0, 0],
"rotation": [0, 0, 0, 1],
"radius": 4,
"flags": {}
},
{
"name": "Checkpoint 1",
"position": [20, 0, 2],
"rotation": [0, 0, 0, 1],
"radius": 5,
"flags": {
"isRecoveryCheckpoint": true,
"recovery": 1
}
}
]
}
*.path.json fields
| Field | Required | Notes |
|---|---|---|
name |
Recommended | Internal/display name. |
description |
Optional | Editor/debug description. |
nodes |
Yes | Ordered array of path nodes. |
nodes[].name |
Recommended | Useful for debugging and conversion. |
nodes[].position |
Yes | World position as [x, y, z]. |
nodes[].rotation |
Optional | Quaternion array. |
nodes[].radius |
Recommended | Checkpoint/route radius. |
nodes[].flags |
Optional | Recovery, padding, normal, or other gameplay flags. |
Boundary files define the playable area for the crawl. Keep the boundary generous enough for normal driving mistakes, but not so large that players can bypass the intended challenge.
If the boundary clips the route, players may fail or reset unexpectedly. If it is too loose, the crawl may lose its challenge definition.
Create boundaries in the editor where possible. Manual boundary editing is error-prone because vertex order and placement matter.
Minimal *.boundary.json shape:
{
"name": "example_boundary",
"vertices": [
[0, -10, 0],
[100, -10, 0],
[100, 10, 0],
[0, 10, 0]
],
"bot": {
"active": false,
"normal": [0, 0, -1],
"pos": [0, 0, -10]
},
"top": {
"active": false,
"normal": [0, 0, 1],
"pos": [0, 0, 10]
},
"customFields": {
"names": {},
"tags": {},
"types": {},
"values": {}
}
}
The boundary format is shared with site zone serialization. If possible, create it through the Sites or Crawl tools.
Starting position files define where the player starts or recovers. They commonly include:
Place starts on stable, flat-enough ground and test them with the vehicle classes expected for the crawl.
When writing manually, remember that iconPosition is for UI/map display and is not necessarily the same as the actual spawn transform.
Minimal *.startingPosition.json:
{
"name": "Example Start",
"description": "Start for the example crawl",
"transform": {
"position": [0, 0, 1],
"rotation": [0, 0, 0, 1],
"radius": 5
},
"iconPosition": [0, 0, 3],
"metadata": {
"created": "2026-06-08",
"modified": "2026-06-08"
}
}
*.startingPosition.json fields
| Field | Required | Notes |
|---|---|---|
name |
Recommended | Display/debug name. |
description |
Optional | Description. |
transform.position |
Yes | Actual spawn/recovery position. |
transform.rotation |
Yes | Quaternion orientation. |
transform.radius |
Recommended | Spawn/recovery radius. |
iconPosition |
Recommended | UI/map icon position. |
metadata |
Optional | Created/modified data. |
Some crawl gameplay lives under modern mission folders:
gameplay/missions/<levelName>/crawl/<missionName>/
Mission-local crawl data can use the same concepts as level-local crawl data. Check the mission folder before assuming all crawl files are in levels/<levelName>/crawls/.
Some crawl files are converted from older race.race.json data. Converted files often keep descriptions such as “Converted from race.race.json”. After conversion, treat the generated path, boundary, trail, and starting-position files as the active crawl data.
When converting, review the result manually. Converted path node names, recovery checkpoints, side padding, and boundaries may be technically valid but still need gameplay tuning.
presets.json is editor/tooling data. It can store reusable crawl authoring presets and should be kept with the level only when those presets are useful for future editing.
Do not rely on presets as gameplay data. The active crawl should be represented by the trail, path, boundary, and starting-position files.
Check:
.trail.json.pathId, boundaryId, and startingPositionId files.Check:
Check:
*.trail.json references valid path, boundary, and starting-position files.*.path.json has ordered nodes with reasonable radii and rotations.*.boundary.json covers the intended route and does not clip normal driving.*.startingPosition.json points to a safe spawn/recovery position.Was this article helpful?