Starting with version 0.39, official vehicles moved away from defining lights directly inside props sections with embedded lights
. Instead, they now use shared light emitter parts located in vehicles/common/lightEmitters/.
This approach allows multiple vehicles to reuse the same light definitions (for example, halogen headlights or tail light bulbs), ensuring consistent behavior and easier maintenance. Any updates to light calibration, beam shape, or cookies can be made in one place and automatically apply to all vehicles using that emitter.
Each file in vehicles/common/lightEmitters/ defines one or more auxiliary parts. These parts contain a props section with a light definition that uses $-prefixed variables (such as $posX, $electric, etc.).
Vehicle lamp housing parts do not define lights directly. Instead, they reference emitters using the slots2 system. At runtime, the selected emitter is attached to the vehicle and its variables are resolved, resulting in a fully functional light with the correct position, behavior, and settings.
Bulb slots use the standard Slots2 structure:
name
Unique slot identifier. Must not be reused anywhere else on the same vehicle.
allowTypes
List of allowed slotType values. These are matched against the slotType field inside emitter parts (not the part name itself).
In most cases, bulb slots should only allow a single type.
denyTypes
Typically left as an empty array [].
default
The default emitter part to load. This must be the internal part name (the key used in the JBeam file), not the display name. It may or may not match the slotType.
These slots are marked with "coreSlot": true and are not intended to be user-selectable. Emitters themselves use the isAuxiliary tag, which keeps them hidden from the parts selector.
Emitter-specific parameters are defined in the parent part under variables. These values are passed into the emitter and control things like position, direction, and electrical behavior.
This system avoids duplicating light definitions while keeping vehicle-specific configuration flexible and maintainable.
"slots2":[
["name", "allowTypes", "denyTypes", "default", "description"],
//headlight emiters
["fullsize_headlight_R_low_bulb", ["headlightBulb_halogen_55W"], [], "headlightBulb_halogen_55W", "Right Lowbeam Headlight Bulb"
{
"coreSlot":true,
"variables":{
"$electric": "lowhighbeam_filament",
"$lightPattern": "US",
"$nodeRef":"he4l", "$nodeX": "he3l", "$nodeY":"he2l"
"$deformGroup": "headlightglass_R_break"
"$posX": -0.675,
"$posY": -2.20,
"$posZ": 0.67,
"$rotX":-0.57,
"$rotY": 0,
"$rotZ": 180,
//"$cookieName": "art/special/BNG_cookie_test_1.png"
"$shadowEnable":0
}
}],
]
Rear lamps reuse the same general idea as headlamps ($electric, nodes, pose, and so on) but usually omit $lightPattern, since non-headlight bulbs generally do not use dedicated road-beam cookies. You can still override the cookie from the slot if you need to.
"slots2": [
["name", "allowTypes", "denyTypes", "default", "description"],
["pigeon_taillight_R_reverse_bulb", ["incandescent_white_21W"], [], "incandescent_white_21W", "Right Reverse Bulb",
{
"coreSlot":true,
"variables":{
"$electric":"reverselight_filament",
"$nodeRef":"rb4rr", "$nodeX":"rb4r", "$nodeY":"rb3rr",
"$deformGroup":"taillight_R_break",
"$posX":-0.385, "$posY":1.778, "$posZ":0.363,
"$rotX":0, "$rotY":0, "$rotZ":0,
"$shadowEnable":1,
}
}],
["pigeon_taillight_R_tailbrake_bulb", ["incandescent_red_21W"], [], "incandescent_red_21W", "Right Tail/Brake Bulb",
{
"coreSlot":true,
"variables":{
"$electric":"lowhighBrake_filament",
"$nodeRef":"rb4rr", "$nodeX":"rb4r", "$nodeY":"rb3rr",
"$deformGroup":"taillight_R_break",
"$posX":-0.441, "$posY":1.778, "$posZ":0.363,
"$rotX":0, "$rotY":0, "$rotZ":0,
"$shadowEnable":1,
}
}],
["pigeon_taillight_R_signal_bulb", ["incandescent_amber_21W"], [], "incandescent_amber_21W", "Right Signal Bulb",
{
"coreSlot":true,
"variables":{
"$electric":"signal_R_filament",
"$nodeRef":"rb4rr", "$nodeX":"rb4r", "$nodeY":"rb3rr",
"$deformGroup":"taillight_R_break",
"$posX":-0.499, "$posY":1.778, "$posZ":0.363,
"$rotX":0, "$rotY":0, "$rotZ":0,
"$shadowEnable":1,
}
}]
],
These are the variables most vehicle-mounted bulb slots are expected to supply so the emitter can place and drive the spotlight.
baseTranslationGlobal.baseRotationGlobal on SPOTLIGHT props (aim of the beam).Electrics naming and custom filaments are documented under vehicle electrics .
$posX, $posY, and $posZ with baseTranslationGlobal. The flashlightBulbs.jbeam and streetLightBulbs.jbeam emitters are offset-based instead: they use $offsetX, $offsetY, and $offsetZ, and they allow $lightIntensityCd to override their default intensity.These are not mandatory for every spotlight to work, but can be used to fine-tune emitters that expose them.
flashlightBulbs.jbeam and streetLightBulbs.jbeam instead of $posX, $posY, and $posZ.variables / Tuning UI, not hard-coded on every slot.$headlightPitchComp
On official vehicles, high beams are aimed straight forward: $rotX = 0 (no extra pitch on X). Low beams use a small downward pitch on X of -0.57 degrees in the vehicle’s as-spawned pose. Those angles are not meant to include suspension trim or wheel-size pitch changes.
To compensate per configuration, supported headlight emitters add $headlightPitchComp inside their rotation expression. You normally expose that on the root vehicle part as a tuning variable so players can trim pitch in the Tuning UI: use the negative of what the in-game Pitch UI app shows for the headlight line you are correcting (if the app reads -0.5, set compensation to +0.5).
Example from pickup root part variables (range in degrees, category Headlights):
"variables": [
["name", "type", "unit", "category", "default", "min", "max", "title", "description"],
["$brakestrength", "range", "", "Brakes", 1, 0.6, 1.0, "Brake Force Multiplier", "Scales the overall brake torque for this setup", {"minDis":60, "maxDis":100}],
["$ffbstrength", "range", "", "Chassis", 1, 0.5, 1.5, "Setup-Specific Force Feedback Multiplier", "Scales the force feedback strength for THIS SETUP ONLY", {"minDis":50, "maxDis":150}],
["$headlightPitchComp", "range", "degree", "Headlights", 0, -3, 3, "Setup Specific Headlight Pitch Compensation", "Adjusts the headlight pitch for this setup", {"minDis":-3, "maxDis":3}]
],
If your vehicle does not define $headlightPitchComp yet, add a similar variables row on the main part so tuning can adjust pitch without editing each headlamp slot.
The lightIntensityCd value on each emitter is the peak luminous intensity in candela (cd) for a single bulb (one side, not a pair). For separate low/high setups the low-beam and high-beam bulbs are defined independently; combined bulbs use H4-style dual-filament tech, so their low and high values are listed separately.
The forward road beams below are calibrated against real photometric standards: ECE R112 (EU low/high beam) and FMVSS 108 (US). Reference points used:
Imax) must not exceed 215 000 cd under ECE; the US limit is 75 000 cd at H-V per side. A typical halogen high beam sits around an ECE reference value of 12.5-30 (≈ 54 000-129 000 cd).lightIntensityCd) and darker values dim it proportionally (50% grey ≈ half). A cookie can only attenuate, it can never push output above the set value. So set lightIntensityCd to the true beam peak, then let the cookie shape and dim the rest.
Rear signalling values follow FMVSS 108 / ECE photometric ranges (per single bulb). Colour variants of the same wattage share their intensity.
Emergency warning lamps are regulated: in the EU by ECE R65, and in the US by SAE J595 (directional) and SAE J845 (omnidirectional, 360 degrees). Both express limits in effective candela:
Off-road driving lights, steerable search / spot lights, and decorative or environment emitters are not bound by a road-beam standard, so they are tuned for believable effect and can be very bright. Off-road lights are generally not road-legal for on-road use.
The shared emitters reference ready-made cookie textures that ship in art/special/. .color.png files are greyscale beam masks. Assign one through the cookieName field, or override it per slot with $cookieName.
Road-beam cookies come in left-hand-traffic, right-hand-traffic, and US variants. Headlight emitters pick the right one automatically from $lightPattern (LHD / RHD / US) and fall back to a sensible default when it is unset.
Beyond the emitter defaults, individual vehicles often set $cookieName on a bulb slot to reuse these masks for non-headlight functions, for example BNG_light_cookie_lightbar.dds to shape blinkers and flashers, or BNG_light_cookie_taillight_incandescent.color.png to shape tail and brake lamps.
"") emits a plain, unshaped cone, used by some small 6 V and marker lamps. Remember that a cookie only attenuates: white passes the full lightIntensityCd, so pick the cookie for the shape and set the intensity separately.Environment fixtures (street and tunnel lights) instead use IES-derived cookies stored in art/special/ies/. See the IES light profiles
section on the PBL page.
Example light emitter:
"headlightBulb_halogen_55W": { // Internal name: use this string in the slot `default` field
"information":{
"authors":"BeamNG",
"name":"55W Halogen Bulb", // UI name in parts selector
"value":0,
"isAuxiliary": true, // Hides part from selector unless "Include auxiliary / debug content" is enabled
},
"slotType" : "headlightBulb_halogen_55W", // Goes in slot `allowTypes`
"props": [ // Standard SPOTLIGHT prop row; many fields are filled from the parent slot `variables`
["func" , "mesh" , "idRef:", "idX:", "idY:" , "baseRotation" , "rotation" , "translation" , "min", "max", "offset", "multiplier"],
//low beams
["$electric" , "SPOTLIGHT" , "$nodeRef", "$nodeX", "$nodeY", {"x":0, "y":0, "z":0} , {"x":0, "y":0, "z":0} , {"x":0, "y":0, "z":0}, 0, 0, 0, 1,
{
"baseTranslationGlobal":{"x":"$posX", "y":"$posY", "z":"$posZ"},
"baseRotationGlobal":{"x":"$= $rotX + ($headlightPitchComp == nil and 0 or $headlightPitchComp)", "y":"$rotY", "z":"$rotZ"},
"deformGroup":"$deformGroup",
"breakGroup":"$= $breakGroup ~= nil and $breakGroup or ''",
"lightScaling":{},
"disable":"$= $disable == 1 and true or false",
"lightRange":"$=$lightRange == nil and 150 or $lightRange",
"lightInnerAngle":"$=$lightInnerAngle == nil and 105 or $lightInnerAngle",
"lightOuterAngle":"$=$lightOuterAngle == nil and 110 or $lightOuterAngle",
"flareScale":0,
"lightIntensityCd":13000, // Intensity (candela)
"lightColor":{"r":255, "g":178, "b":115, "a":255}, // Emitted light colour
"lightCastShadows":"$= $shadowEnable == 0 and false or true",
"flareName":"",
"cookieName":"$= $cookieName ~= nil and $cookieName or ($lightPattern == 'LHD' and 'art/special/BNG_light_cookie_reflector_lhd_eu.color.png' or $lightPattern == 'RHD' and 'art/special/BNG_light_cookie_reflector_rhd.color.png' or $lightPattern == 'US' and 'art/special/BNG_light_cookie_sealed_beam_low.color.png' or 'art/special/BNG_light_cookie_sealed_beam_low.color.png')", // Beam cookie; this headlight picks LHD / RHD / US from $lightPattern
"texSize":512,
"shadowSoftness":0.5,
}],
],
},
Was this article helpful?