Level Object Files (items.level.json)

This document describes the items.level.json file format used by BeamNG levels to store scene objects.

items.level.json files are used inside level object folders such as:

levels/<levelName>/main/items.level.json

They store serialized scene objects as line-delimited JSON, meaning each line is one complete JSON object.


Overview

BeamNG levels store many scene objects as JSON objects. Instead of writing one large JSON array, the engine writes one object per line.

Example:

{"class":"SimGroup","name":"Environment"}
{"class":"TSStatic","name":"garage","shapeName":"/levels/example/art/shapes/garage.dae","position":[0,0,0],"rotationMatrix":[1,0,0,0,1,0,0,0,1],"scale":[1,1,1]}
{"class":"PointLight","name":"garage_light","position":[2,4,3],"rotationMatrix":[1,0,0,0,1,0,0,0,1],"scale":[1,1,1],"intensity":800}

This format is used because it is easy to stream, edit, diff, merge, and serialize incrementally.


File location

The main level object file is usually:

levels/<levelName>/main/items.level.json

Additional object groups may be stored in subfolders:

levels/<levelName>/main/
├── items.level.json
├── Environment/
│   └── items.level.json
├── Buildings/
│   └── items.level.json
└── Gameplay/
    └── items.level.json

Each folder can contain its own items.level.json.


Line-delimited JSON

items.level.json is not a normal JSON array.

Correct:

{"class":"SimGroup","name":"Buildings"}
{"class":"TSStatic","name":"building_01","shapeName":"/levels/example/art/shapes/building_01.dae"}
{"class":"TSStatic","name":"building_02","shapeName":"/levels/example/art/shapes/building_02.dae"}

Incorrect:

[
  {"class":"SimGroup","name":"Buildings"},
  {"class":"TSStatic","name":"building_01"},
  {"class":"TSStatic","name":"building_02"}
]
Do not wrap items.level.json contents in [ ]. Each line must be a standalone JSON object.

Recursive loading

The engine loads items.level.json recursively.

When it finds a SimGroup object, it checks whether a folder with the same name exists. If it does, the engine loads that folder’s items.level.json as well.

Example root file:

{"class":"SimGroup","name":"Buildings"}
{"class":"SimGroup","name":"Gameplay"}

This causes the loader to look for:

main/Buildings/items.level.json
main/Gameplay/items.level.json

This allows large levels to organize objects into folders and groups.


Object structure

Each line is a JSON object representing one serialized scene object.

Most objects contain at least:

Field Type Description
class string Object class name, such as TSStatic, SimGroup, PointLight, TerrainBlock, etc.
name string Object name in the Scene Tree.
position array[3] Object position [x, y, z], when applicable.
rotationMatrix array[9] Object rotation as a 3×3 matrix, when applicable.
scale array[3] Object scale [x, y, z], when applicable.

Different object classes can include many additional fields.


Common object examples

SimGroup

A group object used for organization.

{"class":"SimGroup","name":"Buildings"}

If a folder named Buildings exists next to the current items.level.json, it can contain its own nested object file:

Buildings/items.level.json

TSStatic

A static mesh object.

{
  "class": "TSStatic",
  "name": "garage",
  "shapeName": "/levels/example/art/shapes/garage.dae",
  "position": [0, 0, 0],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [1,1,1]
}

Important fields:

Field Description
shapeName Path to the shape file.
position Object position.
rotationMatrix Object rotation.
scale Object scale.

TerrainBlock

A terrain object.

{
  "class": "TerrainBlock",
  "name": "theTerrain",
  "terrainFile": "/levels/example/terrain/main.ter",
  "position": [0,0,0],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [1,1,1],
  "maxHeight": 2048,
  "squareSize": 1
}

Important fields:

Field Description
terrainFile Path to the terrain data file.
maxHeight Maximum terrain height. Defaults to 2048 if missing.
squareSize Size of one terrain square. Defaults to 1 if missing.

SpawnSphere

A spawn point.

{
  "class": "SpawnSphere",
  "name": "default_spawn",
  "position": [10, 20, 1],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1]
}

Spawn points are collected by name and position. The engine also adds a fallback spawn point named Zero at the origin.

WaterPlane

A water plane object.

{
  "class": "WaterPlane",
  "name": "lake",
  "position": [0,0,0],
  "rotationMatrix": [1,0,0,0,1,0,0,0,1],
  "scale": [100,100,1]
}

Transform fields

Many scene objects use these transform fields:

position

"position": [0, 0, 0]

A 3-value array:

[x, y, z]

rotationMatrix

"rotationMatrix": [
  1,0,0,
  0,1,0,
  0,0,1
]

A 9-value 3×3 rotation matrix.

scale

"scale": [1, 1, 1]

A 3-value scale vector:

[x, y, z]

If invalid transform values are found, the loader may default them to safe values such as:

position = [0, 0, 0]
rotation = identity matrix
scale = [1, 1, 1]

Serialization order

When writing line-object files, the engine can sort objects before saving.

There are two sorting modes:

Sort by serializeOrder

If enabled, objects with a string serializeOrder field are sorted numerically.

{"class":"TSStatic","name":"a","serializeOrder":"10"}
{"class":"TSStatic","name":"b","serializeOrder":"20"}

The serializeOrder field is removed before writing the final object line.

Sort by class and name

If serializeOrder sorting is not used, objects are sorted by:

  1. class
  2. name

This gives stable output and makes files easier to diff.


Namespaced saving

The engine can save objects into namespace folders.

For example, an object namespace list may be saved as:

main/
├── Environment/
│   └── items.level.json
├── Gameplay/
│   └── items.level.json
└── Buildings/
    └── items.level.json

Each namespace becomes a folder, and the entries inside it are written to that folder’s items.level.json.


Relationship to level loading

During level loading, the engine starts from:

levels/<levelName>/main/

It then recursively loads:

items.level.json

from the main folder and any discovered SimGroup subfolders.

The resulting object list is then used to create scene objects.


Valid JSON object requirements

Each line should:

  • Contain exactly one JSON object
  • Include a valid class field
  • Use valid JSON syntax
  • Use arrays for transform data
  • Avoid trailing commas
  • Avoid wrapping the whole file in an array

Invalid lines are skipped and logged.


Editing recommendations

Manual editing is possible, but use care.

Recommended workflow:

  1. Edit the level in the World Editor.
  2. Save the level.
  3. Use manual edits only for batch cleanup or advanced tooling.
  4. Validate JSON syntax line by line.
  5. Keep object names unique where possible.
  6. Avoid changing class names unless you know the target object type.
A single invalid line can prevent that object from loading. Check the console or log if objects disappear after manual edits.

Minimal level object file

Example levels/example/main/items.level.json:

{"class":"SimGroup","name":"Environment"}
{"class":"SpawnSphere","name":"default_spawn","position":[0,0,1],"rotationMatrix":[1,0,0,0,1,0,0,0,1]}
{"class":"TSStatic","name":"test_cube","shapeName":"/levels/example/art/shapes/test_cube.dae","position":[5,0,0],"rotationMatrix":[1,0,0,0,1,0,0,0,1],"scale":[1,1,1]}

Optional nested file:

levels/example/main/Environment/items.level.json
{"class":"PointLight","name":"env_light","position":[0,0,5],"rotationMatrix":[1,0,0,0,1,0,0,0,1],"scale":[1,1,1],"intensity":1000}

Common issues

Objects do not load

Possible causes:

  • File is missing
  • Invalid JSON line
  • Object is wrapped in an array
  • Missing or invalid class
  • Wrong folder structure
  • Subfolder name does not match SimGroup name

Nested group does not load

Check that the parent items.level.json contains:

{"class":"SimGroup","name":"GroupName"}

and that the folder exists:

GroupName/items.level.json

Object appears at origin

Possible causes:

  • Invalid position array
  • Non-numeric position values
  • Missing transform data

Object has wrong rotation

Check that rotationMatrix has exactly 9 numeric values.

Object has wrong scale

Check that scale has exactly 3 numeric values.


Summary

items.level.json files store level objects as line-delimited JSON.

Key points:

  • Each line is one JSON object.
  • Files are loaded recursively through SimGroup folders.
  • Do not wrap contents in an array.
  • Transform data commonly uses position, rotationMatrix, and scale.
  • Objects may be sorted by serializeOrder, or by class and name.
  • Invalid lines are logged and skipped.

This format is compact, tool-friendly, and suitable for large levels with many scene objects.

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.