Introduction

Most of a vehicle’s data is defined in JBEAM, a human-readable text format with syntax similar to JSON. JBEAM files use the *.jbeam extension, and can be edited with any text editor.

A vehicle .jbeam file can contain data on:

  • Physics structure (nodes, beams, triangles)
  • How the vehicle is assembled from individual parts
  • Wheel and tire configuration
  • Powertrain configuration
  • Controller configuration
  • Flexbody (deformable mesh) assignment
  • Prop (static/animated mesh) assignment
  • Material switching triggers
  • Light sources
  • Sound sources
  • Driver cameras

Most vehicles split this data to multiple .jbeam files. The vehicle is assembled using the part names and slot system determined within thesese files, however the .jbeam filenames themselves are not important. When loading a vehicle, the engine will look for .jbeam files in the following directories:

  • vehicles\myVehicle
  • vehicles\common
  • matching folders inside of Documents\BeamNG.Drive\, Documents\BeamNG.Drive\mods, Documents\BeamNG.Drive\mods\repo

Data Types

String types:
A sequence of unicode characters
Float types:
A real number with float precision
Bool types:
Either true or false

Syntax

JBEAM follows JSON syntax with some exceptions:

  • Commas are not required at ends of lines, and not required between data as long as a space is present

Parts

Inside of a jbeam file, data is broken up into objects. Usually these objects represent an entire part of a car, say, an engine, or wheel. For this reason we tend to call the objects parts. Parts can be loaded in an order determined by slots.

Example of a Part

"myPart": {

  "slotType" : "main",

  "information":{
    "name":"My Part",
  },
  "nodes" :[
    ["id", "posX", "posY", "posZ"],
  ],
  "beams": [
    ["id1:", "id2:"],
  ],
  "triangles": [
    ["id1:","id2:","id3:"],
  ],
},

Slots

JBEAM uses a tree heirarchy system to assemble the vehicle from parts. It does this using a system of slots, where each part has some information to describe how it can connect to others as a child, and how others can connect to it as children.

Each part must first contain a “slotType” string. This identifies its compatibility as a child of some other part. Then, each part may also contain a “slot” section identifying what slotTypes can become its children. When a parts’ slotType string matches a slot in another, it can be added to that slot, making it a child. A slot can only recieve one part, but there can be many possible parts to choose from, allowing customization of the vehicle.

The purpose of this system is to replicate the assembly of real vehicle components. A tire should not be loaded without loading a wheel first, for example, because the tire structure needs a wheel to attach to. And the wheel needs attach to the hub, and the hub needs to attach to the chassis, and so on.

The first (or only) part in the tree is always given the slotType “main”. See the example below for usage.

If it is essential that a slot be filled, {“coreSlot”:true} can be added to the slot entry. This prevents choosing the slot to be empty (unless the needed part can not be found). See the example below for usage.

Caution: Make sure you do not create a tree which self-references. If say, you created a tire part, which loads a wheel part, which then loads the tire, it will create a recursive loop and the vehicle will not load.

Example of Slots

"wheel_A": {

  "slotType" : "main",  //"main" means this is the first or only part in the tree

  "slots": [
      ["type", "default", "description"]
        //"type" identifies the relevant slotType,
        //"default" is the default part name to load
        //"description" is used in the user interface for the part selector
      ["tire","tire_X", "Tire", {"coreSlot":true}], //"coreSlot":true means it is not possible to choose this slot to be empty
  ],
},
"tire_X": {

  "slotType" : "tire", //tire_X is a possible child of wheel_A
},
"tire_Y": {

  "slotType" : "tire", //tire_Y is a possible child of wheel_A
},

The above example shows a .jbeam file containing three parts named Wheel, Tire_X, and Tire_Y. Tire_X and Tire_Y both contain the slotType “tire”. Wheel contains a slot section naming “tire” as a compatible slotType. The resulting behavior is as follows:

  • If Wheel is loaded, Tire_X or Tire_Y can be loaded as a child of Wheel.
  • If Wheel is not loaded, there will be no slots available for Tire_X or Tire_Y, and they cannot be loaded.
  • Because Tire_X and Tire_Y share a slotType, only one can be loaded at a given time.
  • Because the “tire” slot is a coreSlot, an empty choice is not possible, it will default to loading Tire_X.

Sections

Inside of each part, sections are created for different types of information. For example, there are nodes, beams, and triangles sections, among others.

Inside these sections, entries are added using []. Each entry represents something like a node, beam, or other entity. The values inside the entry must match the form of the section header.

Extra values can be added using {}. If a value is defined above an entry, it applies to entries underneath. If the value is added “inline” with an entry like so: [{}], then it applies only to the entry itself.

For very commonly shared values, it is better to add them above a group of entries. But for special values it is better to put the value inside the entry.

Example of a Section

"nodes" :[                                //section
  ["id", "posX", "posY", "posZ"],         //header
  ["node_1", 1, 2, 3],                    //entry
  {"nodeWeight":10},                      //value added above applies to all below
  ["node_2", 2, 1, 3],
  ["node_3", 2, 1, 3{"collision":false}], //value added inline applies only to this entry
  ["node_4", 3, 1, 2{"nodeWeight":5}],   //value changed inline changes only this entry
],

Inheritence

Values entered within sections are passed down to the same sections in child parts. For example, if one defines a nodeWeight of 10 for the nodes in a part, any nodes in a child part will also have a nodeWeight of 10, unless the value is redefined. Care has to be taken to avoid unintentional inheritence of values, by redefining the common values at the start of each section, and by setting any uncommon values to “” (empty quotes) at the end of a section. Adding uncommmon values inline with entries also helps mitigate this problem.