Flexbodies

Flexbodies are the models that get mapped to your nodes, and have deformation applied to them.

The game will calculate deformation by mapping every vertex to the nearby nodes, and moving them accordingly with the movement of those nodes.

Flexbodies are assigned to a set of nodes using groups, with the flexbodies only getting deformed by the movement of those specific nodes. See the nodes page for more information.

All the meshes should be in one or multiple dae files either in your car’s folder or the common folder. See the vehicle modelling page for more information.

Deform groups

An additional feature that can be used are deform groups. Those allow you to trigger a material change on a model when a defined set of beams get deformed. They are commonly used for lights and windows.

When one of the beams with the same deformGroup property as this flexbody deforms enough to meet its deformationTriggerRatio treshold, or the beam breaks, then the model’s material will be changed to the material named in the deformMaterialDamaged property.

Mesh to node mapping

Each mesh vertex gets mapped to 3 or 4 nodes - a center node, VX and VY nodes positioned in a way that imaginary lines (or beams) drawn from them to the center node form a roughly 90 degree angle, and if possible, a VZ node positioned in a way that a line drawn from it to the center node forms a roughly 90 degree angle with the other lines. The flexbody mapping system finds the closest possible nodes matching these criteria for each vertex, with some maximum distance constraints which can make some vertices map to nodes that form less than straight angles but are closer to them.

When VX or VY nodes cannot be found anywhere in the assigned group(s), the mesh will not be generated, and the console will shown an error:

  • VX node error means that only a center node can be found for all the vertices. This can only happen when the group consists of only 1 node.
  • VY node error means that the flexbody system cannot find any node to form a 90 degree angle for some or all of the vertices. This can have multiple causes, which can be determined by the flexbody behavior in game:
    • If the flexbody is fully invisible in game, that means none of the vertices can find any nodes forming a right angle. Debugging this situation:
      • It can happen when the group consists of only 2 nodes, or when it consists of nodes that all form a straight line. To fix this, a third node in the group is needed somewhwere, with a beam that forms a roughly 90 degree angle with the other beam(s) in the group. It doesn’t need any collision, it can exist purely to help the flexbody system - that is called a flexbody help node. They are usually present on long, thin structures like antennas.
      • Make sure that the flexbody isn’t too far away from all of the nodes - there might be a typo in the node positions in Jbeam.
    • If the flexbody is partially visible, but a part of it is missing or weirdly stretched, it means that some of the vertices could find nodes forming a right angle, but not all of them. In that case:
      • You should first check if the group doesn’t have any nodes that share exactly the same position (easy to see in the node names debug visualization mode) - remove one of such nodes if it’s not intended, otherwise remove the group property from one of these nodes (you might want to remove selfCollision from this node as well).
      • If none of the nodes share the exact same position, there is an issue with the flexbody help node (if it exists in the first place), check the points below:
        • If the flexbody help node is not present, it should be added on the side that has a missing or stretched flexbody part.
        • If the node is already present, it means some of the vertices can’t use it to form a wide enough angle. In that case it should be moved further away from the other nodes, so that the sharpest angle formed by the imaginary lines on this group is larger.

Sometimes, the flexbody system can map some vertices to less than ideal nodes, causing them to move into unexpected positions upon deformation, creating so called spikes in the mesh. To prevent this from happening, the nodes should be aligned in a grid of sorts, with no outliers that could cause unintentional vertex mapping. If extra nodes outside of the grid are needed for some other purpose, you can exclude them from the group. For a good example of good grid-like node positioning, you can take a look at vanilla vehicles with the Nodes and Triangles debug visualization modes on.

Notice the area around the rear wheel arch. The overall grid is aligned with the windows, but some nodes on the first and second row had to be repositioned to map to the rear fender flare instead. That on its own could have caused spikes, but it was fixed by moving the nodes right above them by half of this distance, so that they form straight, angled lines with the nodes above and below. Figuring out solutions like this takes some trial and error, prior experience helps speed up the process.

Required arguments

"flexbodies" :[
    ["mesh", "[group]:","nonFlexMaterials"],
    ["my_mesh", ["my_group"]],
],
string
type
Defines the name of the mesh
This is the same name as in blender.
table
type
Defines the list of the node groups this mesh is linked to
A mesh can be linked to one or multiple node groups. For more information about groups, see the nodes page.

“nonFlexMaterials” is a deprecated legacy feature that is not used or usable anymore. It was used with the old tire model to prevent the rigid wheel mesh from compressing with the tire.

Optional arguments

dictionary
type
{“x”:0, “y”:0, “z”:0}
default
Position offset of the flexbody (m)
"pos":{"x":0.0, "y":0.0, "z":0.0}
dictionary
type
{“x”:0, “y”:0, “z”:0}
default
Rotation offset of the flexbody (degrees)

Uses the intrinsic Euler +Z +X +Y rotation system.

"rot":{"x":0.0, "y":0.0, "z":0.0}
dictionary
type
{“x”:1, “y”:1, “z”:1}
default
Scale factor of the flexbody
"scale":{"x":1.0, "y":1.0, "z":1.0}
string
type
Defines the deform group that will be used for this mesh
This name should match the deform group defined in the beams section.
string
type
The name of the initial material that will get changed
Any mesh that has a deform group applied should have only a single material to avoid issues. This can require separating parts into multiple components, like separating the lens and reflector on a headlight.
string
type
The name of the material to use when the deform group is triggered
string
type
The sound clip that will be played when the deform group is triggered
number
type
The volume of the sound clip that is played when the deform group is triggered
dictionary
type
{“x”:0, “y”:0, “z”:0}
default
Offsets the mesh on the YZ axis, and offsets it in a mirrored fashion on the X axis if the position is not centered on it (m)
This is never set explicitly in Flexbodies section but rather passed from the Slots section.
dictionary
type
{“x”:0, “y”:0, “z”:0}
default
Offsets the mesh on the XYZ axis (m)
This is never set explicitly in Flexbodies section but rather passed from the Slots section.
dictionary
type
{“x”:0, “y”:0, “z”:0, “px”:0, “py”:0, “pz”:0}
default
Rotates the mesh by x, y, z degrees on XYZ axis, around the center point px, py, pz
This is never set explicitly in Flexbodies section but rather passed from the Slots section.
boolean
type
false
default
Whether the position of the mesh should ignore the nodeOffset modifier
table
type
Replaces a defined set of materials used by the flexbody by a different set of materials

Example usage:

["part", ["group"], [],{"materialOverride":[
    ["originalMaterial1","replacementMaterial1"],
    ["originalMaterial2","replacementMaterial2"]
]}],

Simple Example

A mesh called “my_mesh” is assigned to nodes in group “my_group”.

"flexbodies" :[
    ["mesh", "[group]:","nonFlexMaterials"],
    ["my_mesh", ["my_group"]],
],

Advanced Example

An example of headlights with deform groups.

   "flexbodies": [
         ["mesh", "[group]:", "nonFlexMaterials"],
         ["pickup_headlightframe_R", ["pickup_fascia"]],
         ////lights
         {"deformGroup":"headlightglass_R_break", "deformMaterialBase":"gavril_lights", "deformMaterialDamaged":"gavril_lights_dmg"},
         ["pickup_headlight_R", ["pickup_fascia"]],
         //glass
         {"deformGroup":"headlightglass_R_break", "deformMaterialBase":"pickup_glass", "deformMaterialDamaged":"pickup_glass_dmg"},
         ["pickup_headlightglass_R", ["pickup_fascia"],[]{"deformSound":"event:>Destruction>Vehicle>Glass>glassbreaksound4", "deformVolume":0.6}],
         {"deformGroup":""},
    ],

An example of a flexbody using modifiers and multiple node groups.

    "flexbodies": [
        ["mesh", "[group]:", "nonFlexMaterials"],
        //wheels
        ["steelwheel_10a_13x5_5", ["wheel_FR","wheelhub_FR"], [], {"pos":{"x": -0.50, "y":-0.0, "z":0.0}, "rot":{"x":0, "y":0, "z":180}, "scale":{"x":1, "y":1, "z":1}}],
        ["steelwheel_10a_13x5_5", ["wheel_FL","wheelhub_FL"], [], {"pos":{"x": 0.50, "y":-0.0, "z":0.0}, "rot":{"x":0, "y":0, "z":0},    "scale":{"x":1, "y":1, "z":1}}],
    ],

Using materialOverride to define multiple parts with different color variants.

"us_semi_conventional_bullbar_type_bare": {
    "information":{
        "authors":"BeamNG",
        "name":"Bare Metal",
        "value":450,
    },
    "slotType" : "us_semi_conventional_bullbar_type",
   "flexbodies": [
       ["mesh", "[group]:", "nonFlexMaterials"],
       ["longnose_bullbar", ["us_semi_bullbar"], [],{"materialOverride":[["us_semi_common","us_semi_common"]]}],
   ],
},
"us_semi_conventional_bullbar_type_chrome": {
    "information":{
        "authors":"BeamNG",
        "name":"Polished",
        "value":450,
    },
    "slotType" : "us_semi_conventional_bullbar_type",
   "flexbodies": [
       ["mesh", "[group]:", "nonFlexMaterials"],
       ["longnose_bullbar", ["us_semi_bullbar"], [],{"materialOverride":[["us_semi_common","us_semi_common_chrome"]]}],
   ],
},
"us_semi_conventional_bullbar_type_painted": {
    "information":{
        "authors":"BeamNG",
        "name":"Painted",
        "value":450,
    },
    "slotType" : "us_semi_conventional_bullbar_type",
   "flexbodies": [
       ["mesh", "[group]:", "nonFlexMaterials"],
       ["longnose_bullbar", ["us_semi_bullbar"], [],{"materialOverride":[["us_semi_common","us_semi_common_painted"]]}],
   ],
},
"us_semi_conventional_bullbar_type_black": {
    "information":{
        "authors":"BeamNG",
        "name":"Black",
        "value":450,
    },
    "slotType" : "us_semi_conventional_bullbar_type",
   "flexbodies": [
       ["mesh", "[group]:", "nonFlexMaterials"],
       ["longnose_bullbar", ["us_semi_bullbar"], [],{"materialOverride":[["us_semi_common","us_semi_common_black"]]}],
   ],
},

Using materialOverride on multiple flexbodies at once.

"flexbodies": [
    ["mesh", "[group]:", "nonFlexMaterials"],

    {"materialOverride":[
      ["us_trucklight_signal_R", "us_trucklight_amber_R"],
      ["us_trucklight_signal_L", "us_trucklight_amber_L"],
      ["us_trucklight_taillight_R", "us_trucklight_red_R2"],
      ["us_trucklight_taillight_L", "us_trucklight_red_L2"],
      ["us_trucklightglass_signal_R", "us_trucklightglass_amber_R"],
      ["us_trucklightglass_signal_L", "us_trucklightglass_amber_L"],
      ["us_trucklightglass_taillight_R", "us_trucklightglass_red_R2"],
      ["us_trucklightglass_taillight_L", "us_trucklightglass_red_L2"],
    ]},

    ["us_trucklight_taillight_R",     ["schoolbus_body"],[],{"pos":{"x":-0.880,"y":-0.855,"z":2.661}}],
    ["us_trucklight_signal_R",        ["schoolbus_body"],[],{"pos":{"x":-0.685,"y":-0.855,"z":2.661}}],
    ["us_trucklight_taillight_L",     ["schoolbus_body"],[],{"pos":{"x": 0.880,"y":-0.855,"z":2.661}}],
    ["us_trucklight_signal_L",        ["schoolbus_body"],[],{"pos":{"x": 0.685,"y":-0.855,"z":2.661}}],
    ["us_trucklightglass_taillight_R",["schoolbus_body"],[],{"pos":{"x":-0.880,"y":-0.855,"z":2.661}}],
    ["us_trucklightglass_signal_R",   ["schoolbus_body"],[],{"pos":{"x":-0.685,"y":-0.855,"z":2.661}}],
    ["us_trucklightglass_taillight_L",["schoolbus_body"],[],{"pos":{"x": 0.880,"y":-0.855,"z":2.661}}],
    ["us_trucklightglass_signal_L",   ["schoolbus_body"],[],{"pos":{"x": 0.685,"y":-0.855,"z":2.661}}],

    {"materialOverride":[]},
],
Last modified: April 1, 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.