RLS Studios
ProjectsPatreonCommunityDocsAbout
Join Patreon
BeamNG Modding Docs

Guides

Vehicle Control from GEVE Architecture Quick ReferenceVE Developer Recipes & PatternsVehicle Modding GuideUnderstanding Vehicle Damage SystemsJBeam BasicsCreating Vehicle Extensions

Reference

UI

Resources

BeamNG Game Engine Lua Cheat SheetGE Developer RecipesMCP Server Setup

// RLS.STUDIOS=true

Premium Mods for BeamNG.drive. Career systems, custom vehicles, and immersive gameplay experiences.

Index

HomeProjectsPatreon

Socials

DiscordPatreon (RLS)Patreon (Vehicles)

© 2026 RLS Studios. All rights reserved.

Modding since 2024

GuidesVehicle

VE Developer Recipes & Patterns

The comprehensive vehicle scripting reference — quick one-liners, reusable patterns, and 62+ copy-paste recipes for powertrain, physics, damage, UI, and inter-VM communication.

The comprehensive vehicle scripting reference. Quick one-liners at the top, mid-length patterns in the middle, and full recipes at the bottom.

All snippets run in the VE (Vehicle Engine) context — inside lua/vehicle/extensions/ files. Use Ctrl+F to search by keyword.


Quick Reference

Copy-paste one-liners for the most common vehicle scripting tasks.

Physical State

  • Get Position (World): local pos = obj:getPosition()
  • Get Velocity (m/s): local vel = obj:getVelocity()
  • Get Speed (km/h): local speed = obj:getVelocity():length() * 3.6
  • Get Direction (Forward): local fwd = obj:getDirectionVector()
  • Get Direction (Up): local up = obj:getDirectionVectorUp()
  • Get Rotation (Quat): local rot = obj:getRotation()
  • Get Angular Velocity: local angVel = obj:getAngularVelocity()
  • Teleport Vehicle (via GE): obj:queueGameEngineLua(string.format("be:getObjectByID(%d):setTransform(MatrixF(quat(0,0,0,1), vec3(0,0,0)))", obj:getId()))
  • Apply Force (to Node): obj:applyForceVector(nodeId, vec3(0,1000,0))
  • Get Total Mass: local mass = 0; for _, n in pairs(v.data.nodes) do mass = mass + n.nodeWeight end

Electrics & Data Bus

  • Get Engine RPM: local rpm = electrics.values.rpm or 0
  • Get Throttle Input: local throttle = electrics.values.throttle or 0
  • Get Brake Input: local brake = electrics.values.brake or 0
  • Get Steering Input: local steering = electrics.values.steering or 0
  • Get Airspeed (m/s): local airspeed = electrics.values.airspeed or 0
  • Get Current Gear: local gear = electrics.values.gear or 0
  • Check Ignition State: local ignition = electrics.values.ignitionLevel or 0 -- 0=off, 1=acc, 2=on, 3=start
  • Toggle Hazard Lights: electrics.setIgnitionLevel(2); electrics.toggle_warn_signal()
  • Get Battery Level (EV): local fuel = electrics.values.fuel or 0
  • Custom Signal: electrics.values.mySignal = 1.0

Powertrain & Gearbox

  • Shift to Gear: controller.mainController.shiftToGearIndex(1)
  • Set Gearbox Mode: controller.mainController.setGearboxMode('manual') -- 'arcade', 'realistic', 'manual'
  • Get Engine Load: local engine = powertrain.getDevice("mainEngine"); local load = engine.engineLoad
  • Get Wheel Speed: local speed = wheels.wheels[0].angularVelocity * wheels.wheels[0].radius
  • Check if Engine Running: local isRunning = powertrain.getDevice("mainEngine").state == "running"
  • Kill Engine: powertrain.getDevice("mainEngine"):lockUp()
  • Apply Power Multiplier: powertrain.getDevice("mainEngine").outputTorqueState = 1.2 -- +20% power
  • Check NOS Status: local nos = electrics.values.n2oActive or false
  • Access Differential: local diff = powertrain.getDevice("rearDiff")

Damage & State

  • Get Total Damage: local damage = beamstate.damage
  • Is Tire Popped: local popped = damageTracker.getDamage("wheels", "tireFL")
  • Is Engine Broken: local broken = damageTracker.getDamage("engine", "engineBlock")
  • Check Radiator: local leaking = damageTracker.getDamage("engine", "radiator")
  • Get Body Damage %: local fl = damageTracker.getDamage("body", "FL") or 0
  • Deflate Tire: beamstate.deflateTire(0)
  • Break All Hinges: beamstate.breakHinges()
  • Get Part Condition: local cond = partCondition.getConditions()["engine"]
  • Reset Vehicle: onVehicleReset()
  • Check First Player: local seated = playerInfo.firstPlayerSeated

UI & Audio

  • UI Message (Toast): guihooks.message("Hello World", 5, "category")
  • Send to Console: print("Value: " .. tostring(val))
  • Play Sound (Once on Node): obj:playSFXOnce("event:>Vehicle>Failures>tire_burst", 0, 1, 1) -- event, nodeId, volume, pitch
  • Trigger UI Hook: guihooks.trigger("myEvent", {data = 1})
  • Update UI Stream: guihooks.queueStream("myValue", 100)
  • Draw Line (Debug): obj.debugDrawProxy:drawLine(pos1, pos2, color)
  • Draw Text (Debug): obj.debugDrawProxy:drawText(pos, color, "Hello")
  • Draw Sphere (Debug): obj.debugDrawProxy:drawSphere(pos, 0.5, color)

Inter-VM & Logic

  • Call Game Engine: obj:queueGameEngineLua("print('Hello from VE')")
  • Call Other Vehicle: obj:queueObjectLuaCommand(targetId, "print('Hello from Peer')")
  • Set Timer: local timer = HighPerfTimer()
  • Stop/Reset Timer: local ms = timer:stopAndReset()

Common Patterns

Patterns you'll use repeatedly in vehicle extensions. Each one solves a specific, common problem with production-quality code.

High-G Impact Detection

Detecting when a vehicle has hit something hard, regardless of structural damage.

local impactThreshold = 50 -- G's
local function updateGFX(dt)
    local gX = sensors.gx or 0
    local gY = sensors.gy or 0
    local gZ = sensors.gz or 0
    local totalG = math.sqrt(gX*gX + gY*gY + gZ*gZ) / 9.81
    
    if totalG > impactThreshold then
        guihooks.message("Impact Detected!", 2, "safety")
    end
end

Speed-Based Conditional Logic

Automatically performing an action (like deploying a spoiler) at a specific speed.

local deploySpeed = 80 / 3.6 -- 80 km/h in m/s
local function updateGFX(dt)
    local speed = electrics.values.airspeed or 0
    if speed > deploySpeed then
        electrics.values.spoilerPosition = 1.0
    else
        electrics.values.spoilerPosition = 0.0
    end
end

Monitoring Damage Delta

Detecting a new collision by checking the change in total damage energy.

local lastDamage = 0
local function updateGFX(dt)
    local currentDamage = beamstate.damage or 0
    if currentDamage > lastDamage then
        local delta = currentDamage - lastDamage
        print("Vehicle sustained " .. delta .. " Joules of new damage!")
        lastDamage = currentDamage
    end
end

Cross-Module Communication via electrics

Using the electrics bus to decouple a custom controller from a visual prop.

-- In your custom extension or controller:
local function updateGFX(dt)
    electrics.values.customNeedle = math.sin(os.clock())
end

-- In the JBeam (visual prop section), the prop is defined to watch "customNeedle"
-- ["customNeedle", "needle_mesh_name", "rotation_axis", ...]

Throttled Logic Updates

Running expensive logic at a lower frequency than the frame rate.

local timer = 0
local interval = 0.5 -- 2Hz (runs twice per second)
local function updateGFX(dt)
    timer = timer + dt
    if timer >= interval then
        if obj:inWater(0) then
            print("Underwater!")
        end
        timer = 0
    end
end

Remote Vehicle State Sync

Sending your speed to another vehicle for coordinated behavior (like a convoy).

local function updateGFX(dt)
    local mySpeed = electrics.values.airspeed or 0
    local targetVehId = 1234
    obj:queueObjectLuaCommand(targetVehId, string.format("convoy.updateLeadSpeed(%f)", mySpeed))
end

Full Recipes

Numbered recipes for quick reference. Each one is a self-contained solution you can drop into your vehicle extension.

1. Powertrain & Torque

  1. Add permanent torque boost (In onInit): for rpm, torque in pairs(eng.torqueCurve) do if type(rpm) == "number" then eng.torqueCurve[rpm] = torque * 1.2 end end; eng.torqueData = eng:getTorqueData()
  2. Find the main engine object: local eng = powertrain.getDevice("mainEngine")
  3. Check if clutch is slipping: local isSlipping = math.abs(eng.outputAV1 - gearbox.inputAV) > 1
  4. Force a specific gear: controller.mainController.shiftToGearIndex(2)
  5. Disable/Reset rev limiter: eng:resetTempRevLimiter()
  6. Calculate current Horsepower: local hp = (eng.combustionTorque * eng.outputAV1) / 745.7
  7. Stall/Lock engine: powertrain.getDevice("mainEngine"):lockUp()
  8. Check fuel level percentage: local fuel = electrics.values.fuel * 100
  9. Change idle RPM dynamically: eng.idleAVOverwrite = 800 * 0.104719755
  10. Detect when shifting starts: if electrics.values.isShifting then ... end
  11. Architectural Boost (UI Visible): Override getTorqueData to multiply curve values (see Modding Guide).
  12. Master Power Multiplier: eng.outputTorqueState = 0.5 (50% power)
  13. Get total wheel torque: local totalTorque = wheels.wheelTorque
  14. Check if engine is running: local running = not eng.isStalled and eng.outputAV1 > 0
  15. Apply braking torque to all wheels: wheels.scaleBrakeTorque(1.0)
  16. Get turbo boost pressure: local boost = electrics.values.turboBoost or 0
  17. Check if NOS is active: local nos = electrics.values.n2oActive or false

2. JBeam & Physics

  1. Get JBeam variable value: local myVar = v.data.variables["$myVar"]
  2. Change beam spring/damp at runtime: obj:setBeam(cid, id1, id2, strength, spring, damp)
  3. Find node CID by name: local nodeId = beamstate.nodeNameMap["nodeName"]
  4. Get node world position: local pos = obj:getNodePosition(nodeId)
  5. Add mass to a node: obj:setNodeMass(nodeId, newMass)
  6. Check if a part is broken (via DamageTracker): local isBroken = damageTracker.getDamage("body", "hood")
  7. Break a group of beams: beamstate.breakBreakGroup("groupName")
  8. Get distance between two nodes: local dist = obj:getNodePosition(id1):distance(obj:getNodePosition(id2))
  9. Apply a force vector to a node: obj:applyForceVector(nodeId, vec3(0, 5000, 0))
  10. Get vehicle world rotation (Quat): local rot = obj:getRotation()
  11. Check if vehicle is upright: local up = obj:getDirectionVectorUp(); if up.z > 0.8 then ... end
  12. Deflate a specific tire: beamstate.deflateTire(wheelId)
  13. Get total vehicle mass: local mass = 0; for _, n in pairs(v.data.nodes) do mass = mass + n.nodeWeight end
  14. Apply a global torque impulse: obj:applyTorqueAxisCouple(500, node1, node2, node3)
  15. Check for node collision: Hook into onNodeCollision(p).

3. Input & Control

  1. Override user steering: electrics.values.steeringOverride = 0.5
  2. Disable user throttle: electrics.values.throttleOverride = 0
  3. Read raw user steering: local rawSteer = electrics.values.steering_input
  4. Detect controller button event: Use input.event("name", val, filter)
  5. Create a non-blocking timer: local t = HighPerfTimer(); ... if t:stop() > 1000 then ... end
  6. Throttled update (2Hz): timer = timer + dt; if timer > 0.5 then timer = 0; ... end
  7. Toggle hazard lights: electrics.toggle_warn_signal()
  8. Set ignition to 'On': electrics.setIgnitionLevel(2)
  9. Check if parking brake is on: if (electrics.values.parkingbrake or 0) > 0 then ... end
  10. Smooth a value over time: val = smoother:get(target, dt)

4. UI & Communication

  1. Trigger screen message: guihooks.message("Impact!", 5, "safety")
  2. Send data to UI app: guihooks.queueStream("myKey", myValue)
  3. Call function in Game Engine: obj:queueGameEngineLua("print('Hello')")
  4. Send command to another vehicle: obj:queueObjectLuaCommand(targetId, "electrics.values.horn = 1")
  5. Play a one-time sound effect: obj:playSFXOnce("event:>Vehicle>Failures>tire_burst", nodeId, 1, 1)
  6. Register damage update callback: damageTracker.registerDamageUpdateCallback(myFunc)
  7. Check if first player is seated: if playerInfo.firstPlayerSeated then ... end
  8. Draw debug line in world: obj.debugDrawProxy:drawLine(pos1, pos2, color)
  9. Draw debug text at node: obj.debugDrawProxy:drawNodeText(nodeId, color, "Broken!")
  10. Sync variable to peer vehicle: obj:queueObjectLuaCommand(id, "myModule.syncValue(" .. myVal .. ")")

5. Niche Modding Tasks

  1. Get vehicle's unique object ID: local id = obj:getId()
  2. Check if in walking/unicycle mode: local isWalking = (controller.mainController.typeName == "playerController")
  3. Disable a powertrain device: powertrain.getDevice("rearDiff"):disable()
  4. Check if a node is underwater: if obj:inWater(nodeId) then ... end
  5. Get environmental air density: local density = obj:getRelativeAirDensity()
  6. Check if any player is in vehicle: if playerInfo.anyPlayerSeated then ... end
  7. Change node friction at runtime: obj:setNodeFrictionSlidingCoefs(id, 1.0, 0.8)
  8. Get gravity magnitude: local g = powertrain.currentGravity
  9. Trigger custom UI event: guihooks.trigger("MyEvent", {val = 1})
  10. Lock a differential: powertrain.setDeviceMode("rearDiff", "locked")

See Also

  • Damage Overview - Understanding damage systems
  • TL;DR Architect - Quick architecture reference
  • Lua Patterns - General Lua patterns
  • Getting Started - Extension basics

VE Architecture Quick Reference

10-second refresher on Vehicle Engine core rules — lifecycle hooks, override patterns, and the no-ghost-values rule.

Vehicle Modding Guide

How to add custom logic to vehicles safely — extensions vs controllers, the electrics data bus, powertrain API, safe overrides, and UI visibility.

On this page

Quick ReferencePhysical StateElectrics & Data BusPowertrain & GearboxDamage & StateUI & AudioInter-VM & LogicCommon PatternsHigh-G Impact DetectionSpeed-Based Conditional LogicMonitoring Damage DeltaCross-Module Communication via electricsThrottled Logic UpdatesRemote Vehicle State SyncFull Recipes1. Powertrain & Torque2. JBeam & Physics3. Input & Control4. UI & Communication5. Niche Modding TasksSee Also