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

Creating Vehicle Extensions

How to create Lua extensions that run in the Vehicle Engine (VE) context — structure, hooks, and differences from GE extensions.

Vehicle extensions run inside each vehicle's own Lua VM, giving you direct access to physics nodes, beams, electrics, and powertrain data. If you want to add custom behavior to a specific vehicle — new instruments, driver aids, sensor logic, or debug tools — a VE extension is how you do it.


File Location

VE extensions live in lua/vehicle/extensions/:

lua/vehicle/extensions/mymod/myfeature.lua

For mods, this path goes inside your mod's directory structure:

mods/unpacked/my_mod/lua/vehicle/extensions/mymod/myfeature.lua

Auto-Loading

Place a VE extension in the auto/ subdirectory to have it load automatically with every vehicle:

lua/vehicle/extensions/auto/mymod/myfeature.lua

Extensions outside auto/ must be loaded explicitly — either from JBeam, from another extension, or via console command.


Basic Structure

A VE extension follows the same module pattern as GE extensions:

local M = {}

function M.onInit()
  log('I', 'myVEMod', 'Vehicle extension loaded')
end

function M.onUpdate(dt)
  -- Called every physics frame
  -- dt = delta time in seconds
end

return M

The module table M is returned at the end. Only functions attached to M are accessible from outside.


Available Hooks

VE extensions can implement these hooks (among others):

HookWhen it fires
onInit()Extension is first loaded
onUpdate(dt)Every physics frame
onReset()Vehicle is reset (R key)
onBeamBroken(id, energy)A beam breaks
onCouplerAttached(nodeId, obj2id, obj2nodeId)Coupler connects
onCouplerDetached(nodeId, obj2id, obj2nodeId)Coupler disconnects

Use Ctrl+L to reload VE extensions live during development.


How VE Differs from GE

Vehicle Engine (VE)Game Engine (GE)
ScopeOne Lua VM per vehicleSingle global Lua VM
AccessNodes, beams, electrics, powertrain, wheelsWorld state, traffic, UI, map, extensions
File pathlua/vehicle/extensions/lua/ge/extensions/
ReloadCtrl+LCtrl+S
Use caseVehicle-specific behaviorGame-wide systems

VE extensions can directly read vehicle physics data — node positions, beam stress, electrical values, wheel state. GE extensions manage the broader game world.


Accessing Vehicle Data

Inside a VE extension, you have access to vehicle-specific APIs:

function M.onUpdate(dt)
  -- Read electrical values (speed, RPM, signals, etc.)
  local speed = electrics.values.wheelspeed or 0
  local rpm = electrics.values.rpm or 0

  -- Access powertrain devices
  local engine = powertrain.getDevice("mainEngine")
  if engine then
    local torque = engine.outputTorque1
  end
end

Communicating with GE

VE and GE run in separate Lua VMs. To communicate between them:

VE → GE

-- From inside a VE extension, send a command to GE
obj:queueGameEngineLua("extensions.mymod_mygefeature.onVehicleData(" .. dumps(data) .. ")")

GE → VE

-- From a GE extension, send a command to a specific vehicle
local veh = be:getPlayerVehicle(0)
if veh then
  veh:queueLuaCommand("extensions.mymod_myvefeature.doSomething()")
end

This string-based communication means you serialize data with dumps() and pass it as Lua code.


Example: Simple Speedometer Logger

local M = {}

local logInterval = 1.0  -- seconds
local timer = 0

function M.onInit()
  log('I', 'speedLog', 'Speed logger initialized')
end

function M.onUpdate(dt)
  timer = timer + dt
  if timer >= logInterval then
    timer = timer - logInterval
    local speed = electrics.values.wheelspeed or 0
    local speedKph = speed * 3.6
    log('I', 'speedLog', string.format('Speed: %.1f km/h', speedKph))
  end
end

function M.onReset()
  timer = 0
end

return M

See Also

  • VE Extensions Folder Overview — All 40+ built-in VE extensions
  • Creating a GE Extension — GE extension structure and lifecycle
  • VE–GE Communication — Communication patterns between VE and GE
  • Hook Catalog — All available hooks
  • Testing & Debugging — Console, logging, and live reload

JBeam Basics

Introduction to the JBeam vehicle definition format — nodes, beams, triangles, slots, and variables.

GE Hook Catalog

Every GE hook with signatures and descriptions — lifecycle, per-frame, vehicle, physics, world, input, and file system hooks.

On this page

File LocationAuto-LoadingBasic StructureAvailable HooksHow VE Differs from GEAccessing Vehicle DataCommunicating with GEVE → GEGE → VEExample: Simple Speedometer LoggerSee Also