Player settings
Every player can restyle their own HUD from the settings menu (/settings).
editable/shared/js.json decides what a player starts with before they change anything, adds your Discord link, logo and key hints, and describes the settings menu itself.
The file has three parts:
| Key | What it holds |
|---|---|
default_settings | What a new player's HUD looks like |
ui | Server branding: Discord, logo, key hints, built-in binds |
options_settings | Which options appear in the settings menu, grouped into windows |
Where player choices are stored
A player's choices are saved in their own game client (the NUI browser storage), not on the server. They follow the player's PC, not their character, and survive server restarts and resource updates.
What a player sees is your default_settings with their own changes laid on top.
So when you change a default, everybody who has not touched that particular option gets the new value; players who changed it keep theirs.
Two defaults come from config.lua instead and win over js.json:
| Setting | Comes from |
|---|---|
minimap.visibility | KOJA.HideMinimapOnFoot — true gives vehicle, false gives always |
killfeed.enabled, killfeed.anyDistance, killfeed.distance | KOJA.Killfeed |
default_settings
HUD, status and speedometer
"hud": { "visibility": true },
"status": {
"visibility": true,
"style": "default",
"colors": { "health": "#ff4444", "shield": "#e2e2e2", "food": "#d8932b", "water": "#60b7ff",
"stamina": "#8dd82b", "oxygen": "#4b7dad", "voice": "#ffb74d", "stress": "#ff6666" },
"percent": { "health": { "value": 50, "action": "below", "visibility": true }, "...": {} },
"enabled": { "health": true, "shield": true, "food": true, "water": true,
"stamina": true, "oxygen": true, "voice": true, "stress": true },
"borderradius": 0.5,
"scale": "1.5"
},
"carhud": {
"visibility": true,
"style": "gauge",
"metertype": "kmh",
"elements": { "gear": true, "fuel": true, "nitro": true, "seatbelt": true, "engine": true,
"rpm": false, "engineHealth": false, "lights": false, "indicators": false, "cruise": false }
}| Setting | Values | What it does |
|---|---|---|
hud.visibility | true / false | The whole HUD |
status.visibility | true / false | The status bars |
status.style | default, circle, echo, minimal, hexagon | Status bar style |
status.colors.<id> | hex colour | Colour of each bar |
status.enabled.<id> | true / false | Show or hide a single bar |
status.percent.<id> | value, action, visibility | Show a bar only above or below a value — see below |
status.borderradius | 0.01–1.5 | Corner rounding |
status.scale | "0.5", "1.5", "3" | Small, Default, Big. A string, not a number |
carhud.visibility | true / false | The speedometer |
carhud.style | gauge, default, compact, minimal, pvp | Speedometer style |
carhud.metertype | kmh, mph | Speed unit |
carhud.elements.<id> | true / false | gear, fuel, nitro, seatbelt, engine, rpm, engineHealth, lights, indicators, cruise |
The status ids are health, shield (armour), food (hunger), water (thirst), stamina, oxygen, voice and stress.
Conditional bars. status.percent can hide a bar until it matters.
"visibility": true — the default for every bar — means always show, and the rule is ignored.
Set it to false and the rule applies: with "action": "below" and "value": 50 the bar shows only while it is under 50%, so hunger appears when the player gets hungry.
"above" is the opposite, which suits oxygen and stress.
In the menu this is Settings → STATUS → Status Percents Settings: Show, Show if over, Show if under.
Messages and information
"notify": { "visibility": true, "position": "top-right", "style": "default" },
"informations": {
"visibility": true,
"opacity": 1,
"items": { "logo": false, "voice": true, "id": true, "time": true,
"cash": true, "bank": true, "job": true, "discord": true }
},
"keybinds": { "visibility": true },
"compass": { "visibility": "always", "style": "bar" },
"weapon": { "visibility": false },
"minimap": { "visibility": "always" }| Setting | Values | What it does |
|---|---|---|
notify.visibility | true / false | Notifications |
notify.position | top-right, bottom-left | Where they stack |
notify.style | default, minimalistic, modern | Notification style |
informations.visibility | true / false | The information panel |
informations.opacity | 0–1 | Its opacity |
informations.items.<id> | true / false | logo, voice, id, time, cash, bank, job, discord |
keybinds.visibility | true / false | The key hints list |
compass.visibility | always, vehicle, foot, never | When the compass shows |
compass.style | bar, minimal, cardinal | Compass style |
weapon.visibility | true / false | Weapon and ammo panel |
minimap.visibility | always, vehicle, foot, never | Overridden by KOJA.HideMinimapOnFoot, see above |
Watermark, PVP, warnings, killfeed, effects
"watermark": { "visibility": true, "style": "default", "font": "Poppins", "size": 0.95,
"color": { "text": "#f2f2f5" } },
"pvp": { "enabled": false },
"warnings": { "lowHealth": true, "lowFuel": true, "sound": true,
"healthThreshold": 20, "fuelThreshold": 15 },
"killfeed": { "enabled": false, "style": "default", "anyDistance": true, "distance": 100 },
"statuseffects": { "enabled": true }| Setting | Values | What it does |
|---|---|---|
watermark.visibility | true / false | Only matters when KOJA.Watermark.Enabled is true |
watermark.style | default, line, bracket | Watermark style |
watermark.font | Poppins, Inter, Montserrat, Proxima, SF Pro | Font |
watermark.size | 0.6–1.8 | Text size |
watermark.color.text | hex colour | Text colour |
pvp.enabled | true / false | PVP mode — see Features |
warnings.lowHealth, warnings.lowFuel | true / false | Low health and low fuel warnings |
warnings.healthThreshold, warnings.fuelThreshold | 5–50 | Percent at which each warning starts |
warnings.sound | true / false | Beep with the warnings |
killfeed.style | default, minimal, modern | Killfeed style |
statuseffects.enabled | true / false | The status effects row |
Binds and layout
"customBinds": [],
"builtinBinds": [
{ "id": "engine", "key": "B", "command": "+toggle_engine" },
{ "id": "seatbelt", "key": "L", "command": "+toggle_seatbelt" },
{ "id": "cruise", "key": "T", "command": "+toggle_cruisemode" },
{ "id": "nitro", "key": "N", "command": "+toggle_nitro" },
{ "id": "vehicleMenu", "key": "U", "command": "koja_vehiclemenu" }
],
"layout": {
"status": { "x": 0, "y": 0 },
"minimap": { "x": 0, "y": 0, "scale": 1 }
}customBinds— key-to-command binds every new player starts with, for example{ "key": "F5", "command": "e sit" }. The command runs as if typed in chat, without the slash.builtinBinds— the starting keys of the HUD's own actions. Keep these in line with theKeyvalues inconfig.lua.layout— starting offsets for each element, in percent of the screen width (x) and height (y). Players set these by dragging in Edit layout; you rarely need to touch them.
ui
"ui": {
"discord": "discord.gg/hexelstore",
"logo": "",
"keybinds": {
"position": "right",
"hints": [
{ "key": "M", "label": "Main menu" },
{ "key": "F3", "label": "Reload voice" }
]
},
"activeBinds": [
{ "id": "engine", "key": "B", "command": "+toggle_engine",
"label": "Engine", "description": "Toggle the vehicle engine" }
]
}| Key | What it does |
|---|---|
discord | Invite shown in the information panel. Empty string hides it. |
logo | URL of your server logo, shown at the top of the information panel when the player enables Server Logo. Use an https:// image link. |
keybinds.position | right or left — which side of the screen the key hints sit on. |
keybinds.hints | The list of key hints. They are only labels: changing them does not bind anything. Put your server's real keys here. |
activeBinds | The HUD's built-in actions as listed in Settings → BINDS, with the label and description players see. |
options_settings
This part builds the settings menu.
It has three categories — hud (shown as MAIN), status and carhud (SPEEDOMETER) — and each is a list of windows:
{
"window": "notify",
"icon": "fa-solid fa-bell",
"title": "notify_settings.title",
"description": "notify_settings.description",
"color": "#ff6666",
"settings": [
{
"type": "dropdown",
"id": "notify.position",
"title": "notify_settings.settings.position_title",
"description": "notify_settings.settings.position_description",
"options": [
{ "id": "top-right", "label": "notify_settings.options.position.top-right" },
{ "id": "bottom-left", "label": "notify_settings.options.position.bottom-left" }
]
}
]
}| Field | Meaning |
|---|---|
window | Window id |
icon | A Font Awesome class |
title, description, label | Keys into ui.settings of the locale file — see Translations |
color | Accent colour of the window |
settings[].id | The default_settings path the control changes, for example notify.position |
settings[].type | switch, dropdown, slider (with min and max), color (one picker per option), toggles (one switch per option) or percent (value, above/below, on/off) |
What you can safely do here:
- Remove a setting or a whole window, to stop players changing it. The default still applies.
- Reorder windows and settings.
- Remove options from a dropdown — for example offer only two speedometer styles.
What does not work: adding a setting whose id the UI does not read, or a dropdown value the component has no style for.
New behaviour needs a change in web/src — see UI development.
Resetting a player
A player resets their own settings from the settings menu. There is no server-side reset, because the settings are not stored on the server.