Emergency Lights Siren Feature (for vehicles) - user-grinch/ModelExtras GitHub Wiki
The Emergency Lights Feature allows vehicles in the game to have customizable emergency, hazard, and steady burn lights. This documentation will guide you through the process of adapting vehicles to utilize this feature effectively.
Additionally, this update introduces the long-awaited support for rotating siren parts, which become active when the sirens are turned on—bringing a new level of realism and authenticity to emergency vehicles.
Every model with a siren must be configured with a JSONC manifest. Without a JSONC manifest, ModelExtras will not recognize the model as being adapted.
- The siren manifest is an object where the keys represent different siren states, toggled using the
R
key. Groups can be switched using keys1-9
- The first key in the object is always the default state.
- There is no limit to the number of states you can define.
- H or CapsLock: Turn on siren (and turn on from muted state).
- L: Toggles muted siren on/off.
- R: Switch siren state forwards.
- Shift+R: Switch siren state backwards.
- Shift: Clear turn lights.
In order for a material to be recognized as a siren material:
🔴 Red: 1-255
🟢 Green always 255
🔵 Blue always 255
Texture: Name should start with siren
. For example sirenlight128
In order for dummies to be recognized,
They must begin with the name sirenX
, X standing for the material index it's connected to. With that said, there can be an infinitive amount of duplicates; e.g. you can have siren1, siren2, siren3...
📌 Path: ModelExtras/data/<FILENAME>.jsonc
Both model & modelname are valid FILENAME
. 602.jsonc
or alpha.jsonc
both are valid (602
is the model index for the vehicle 'alpha`).
It is recommended to use modelnames instead of model index to avoid ID issues with other mods
Used to reference predefined configurations or templates stored elsewhere in the JSONC. This allows for reusability and modularity in siren configurations.
"colors": {
"nearlyRed": { "red": 248, "green": 95, "blue": 95, "alpha": 160 },
"OffWhite": { "red": 255, "green": 255, "blue": 255, "alpha": 160 },
"lightblue": { "red": 52, "green": 255, "blue": 221, "alpha": 160 }
},
"customProperties": {
"size": 0.3,
"state": 1,
"type": "rotator",
"inertia": 1,
"rotator": { "type": "linear" }
}
Now, these colors can be referenced anywhere in the JSONC:
"color": "lightblue"
Or even use the customProperties reference:
"reference": "customProperties"
You can put this line inside any corona or shadow property to apply properties of this object to them.
Defines the size of the corona or shadow. For comparison, a headlight corona is ~0.3.
"size": 1.5
Controls the diffuse properties of the material.
-
color
: (boolean) Enable/disable color. Itstrue
orfalse
. -
transparent
: (boolean) Enable/disable transparency. Itstrue
orfalse
.
{
"diffuse": {
"color": true,
"transparent": false
}
}
Defines the viewing angle of the corona
"radius": 270.0
270 deg - viewable from 3 sides
Defines the color of the siren corona or shadow.
- If
color
is a string, it references a predefined color fromreferences
. - If
color
is an object, it specifies the color usingred
,green
,blue
, andalpha
values.
"color": "lightBlue"
OR
"color": {
"red": 255,
"green": 0,
"blue": 0,
"alpha": 255
}
Defines the initial state of the siren (on/off). 1 make it start ON, 0 make it start OFF.
"state": 1
Defines a sequence of colors and timing for dynamic siren effects.
- Each entry consists of:
- A delay (time in milliseconds).
- A color (either a string reference or an object with
red
,green
,blue
,alpha
values).
{
"colors": [
[1000, "lightBlue"],
[1000, { "red": 255, "green": 0, "blue": 0, "alpha": 255 }]
]
}
The pattern property is an array of integers that represent milliseconds, leaving the array empty ([ ]) makes it a steady burn; the milliseconds does not stack, unlike IVF. They execute after each other.
- Array of numbers → Each number represents a delay in milliseconds.
- Array of arrays → First element is the number of iterations, the rest are delays.
"pattern": [500, 500, 1000]
If you have multiple sirens, make sure the total time specified in their patterns is the same. This ensures they synchronize and reset together after completing one cycle.
When a pattern resets, the siren state also resets to its initial setting, regardless of where it was in the pattern. To prevent this, you can add a 0 millisecond stage at the end of the pattern. To clarify, if a state consists of a single interval in the pattern, it will continuously reset. Thus, each interval must be repeated at least twice. For instance, to toggle states every 500 milliseconds, the pattern would be [500, 500].
Defines the type of siren's corona or sets a special type 'rotator'.
-
directional
→ Corona is directionalIVF type 0
-
non-directional
→ Corona is omnidirectionalIVF type 2
Can be seen from all angles. -
inversed-directional
→ Directional corona, but invertedIVF type 1
-
rotator
→ This is a special type that alters the behavior of the shadow and the corona (enabling rotation) and allows the creation of the rotating parts! More information can be found in the 'Rotators' section.
Defines shadow properties for the siren.
-
size
: Shadow size. -
type
: Shadow type, texture name in "me_texdb.txd" file ("pointlight"
,"narrow"
,"round"
,"tightfocued"
or any other similar texture). -
offset
: Shadow offset. -
angleoffset
: Adds rotation offset to the model value. Useful for ImVehFt vehicles.
"shadow": {
"size": 2.0,
"type": "pointlight",
"offset": 1.0,
"angleoffset": 0.0
}
Defines a delay before the siren effect starts.
"delay": 1000
Defines the smoothness of transitions between siren states.
"inertia": 0.5
Makes IVF siren dummies and materials compatible with JSON ModelExtras configurations. Use this only for ImVehFT-adapted vehicles.
"ImVehFt": true,
The rotator works by creating a node named after the siren (e.g., siren1) and assigning a geometry (such as a rotating mirror used in classic police beacons) as its child object. When siren1 is defined as a rotator in the JSON configuration, the child geometry will perform a continuous rotation when the sirens are activated, accurately simulating the behavior of real-world rotating emergency lights.
Additionally, the rotation is visually applied to the light shadow texture on the ground.
🔄direction
Defines the rotation direction of the rotator:
- clockwise (or 0) – rotates in a clockwise direction,
- counter-clockwise (or 1) – rotates in a counter-clockwise direction,
- switch (or 2) – alternates the rotation direction every few seconds, simulating more dynamic light patterns (e.g., spinning one way, then reversing).
⚙️type
Defines the style of movement:
- linear (or 0) – instead of rotating, the part moves back and forth along an axis (e.g., left to right across the vehicle). Useful for strobe or scanning light effects.
- ease (or 1) – performs a smooth 360° continuous rotation. This is ideal for recreating traditional rotating beacons used on classic emergency vehicles.
🔄radius
Defines rotation angle of the shadow.
🔄time
Time for one rotation of the rotator/shadow.
🔄Offset
Angle from where start the rotation
"type": "rotator",
"rotator": {
"time": 1000,
"radius": 360,
"direction": "clockwise"
"type": "linear"
}
{
"sirens": { // Start of siren configuration
"references": { // Start of reference settings
"colors": { // Defines a set of named colors with RGBA values
"red": { "red": 248, "green": 95, "blue": 95, "alpha": 160 },
"white": { "red": 255, "green": 255, "blue": 255, "alpha": 160 },
"yellow": { "red": 255, "green": 149, "blue": 0, "alpha": 160 },
"blueTint": { "red": 98, "green": 156, "blue": 236, "alpha": 160 },
"lightblue": { "red": 52, "green": 255, "blue": 221, "alpha": 160 }
},
"myReference": { // Defines a reusable myReference object
"size": 0.3, // Defines the size of the rotator
"state": 1, // Initial state of the rotator
"type": "rotator", // Type identifier
"rotator": { "type": "linear" }, // Specifies the rotation type
"inertia": 1 // Defines how smoothly it rotates
}
},
"states": { // Defines each siren group, you can rotate between which group is active using hotkeys
"FirstGroup": { // Defines group 1 of sirens, can be named anything
"1": { // These siren numbers need to match the dummies inside the model
"color": "lightblue", // Use predefined color in the "colors" reference
"reference": "myReference", // References the myReference definition
"rotator": { "time": 800 } // Defines rotation speed
},
"2": {
"color": "lightblue",
"size": 0.3,
"inertia": 1.5, // Higher inertia for smoother transitions
"state": 1, // Active state
"pattern": [ 300,300 ] // Defines the blink pattern (in milliseconds)
},
"3": {
"color": "white",
"reference": "myReference",
"rotator": {
"direction": 0,
"radius": 70.0, // Defines rotation radius
"offset": -35.0, // Offset angle
"time": 600 // Time duration for one full cycle
}
},
"4": {
"color": "blueTint",
"size": 0.3,
"state": 1,
"pattern": [ 50,50,50,50,50,300,50,50,50,50,50,300 ] // Complex blink pattern
},
},
"Group 2": { // This is a totally separate group
"15": {
"size": 0.4,
"color": {
"red": 255,
"green": 255,
"blue": 255,
"alpha": 255
},
"shadow": {
"offset": 0.0,
"size": 1.0,
"type": 11
},
"state": 1,
"pattern": []
},
"16": {
"size": 0.4,
"color": {
"red": 255,
"green": 255,
"blue": 255,
"alpha": 255
},
"shadow": {
"offset": 0.0,
"size": 1.0,
"type": "pointlight"
},
"state": 1,
"pattern": []
}
}
}
}
}