NUI & Assets
The interface lives in html/, and the weapon icons in images/icons/. Both ship as open files, so fonts, sounds and icons are yours to change.
This page covers what is safe to change, what it costs, and the two things that break the resource if you touch them.
html/ and images/icons/ are streamed to clients. After changing a file, restart the resource; players who were already connected pick up the new version when they reconnect.
Fonts
Two lists have to agree.
1. The whitelist — what the menu offers and what the server accepts on save:
F5Cfg.Validation.Fonts = {
'Impact', 'Bebas Neue', 'Teko', 'Russo One', 'Rajdhani', 'Bungee',
'Black Ops One', 'Quantico', 'Audiowide', 'Michroma', 'Press Start 2P',
'Arial', 'Verdana', 'Courier New', 'Inter', 'JetBrains Mono',
}
2. The stylesheet — what the browser can actually render:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=…&display=swap">
Sixteen fonts are offered. Twelve of them come from that Google Fonts link; four — Impact, Arial, Verdana, Courier New — are system fonts and are deliberately not in it.
Six dropdowns are built from the whitelist: damage numbers, killmarker text, killstreak announcement, killstreak counter, K/D HUD and kill feed.
Adding a font
- Add the family to the Google Fonts link in
html/index.html, exactly as Google names it. - Add the same name to
F5Cfg.Validation.Fonts. - Restart.
Add it to the whitelist but not to the stylesheet, and the menu offers it, the server saves it, and the browser silently renders something else — the CSS stack is the font name followed by sans-serif, with nothing in between.
Add it to the stylesheet but not to the whitelist, and it never appears in a dropdown; a save carrying it is replaced by that field's fallback.
Archivo Black (headings), Archivo Narrow (display and body text) and IBM Plex Mono (monospace) are not player-selectable — they are the interface's own typography. Removing them from the link changes how the menu itself looks.
Removing a font from the whitelist is safe but not free: players who had selected it fall back per field — Impact for damage numbers, and the style's own font for the killmarker text, killstreak, K/D HUD and kill feed.
Five of the six dropdowns are rebuilt entirely from the whitelist, so their first entry is always the first name in it. The kill feed select is the only one that ships with a Default (per style) option, because that option is written into html/index.html. To offer it elsewhere, add an option with an empty value to that select by hand.
Sounds
Twelve Ogg files, in two folders.
html/sounds/
hitmarker.ogg
killmarker.ogg
headshot.ogg
killstreak/
double_kill.ogg quadra_kill.ogg rampage.ogg
triple_kill.ogg penta_kill.ogg unstoppable.ogg
legendary.ogg godlike.ogg beyond_godlike.ogg
The three marker sounds
hitmarker.ogg, killmarker.ogg and headshot.ogg are loaded by name. To replace one, overwrite the file — keep the filename and the .ogg format.
Volume is per player, from their own settings (defaults: hitmarker 50 %, killmarker 50 %, headshot marker 20 %).
Killstreak sounds
These are bound in config, so both the file and the volume are yours:
{
kills = 5,
name = "PENTAKILL",
sound = true,
soundFile = 'killstreak/penta_kill.ogg',
soundVolume = 90,
-- …
},
soundFile is a path relative to html/sounds/. Point it at your own file, drop that file into html/sounds/ or html/sounds/killstreak/, and restart.
The manifest streams html/sounds/*.ogg and html/sounds/killstreak/*.ogg — nothing else. An .mp3, a .wav, or an Ogg in a new sub-folder never reaches the client, and the sound simply does not play. There is no error: soundFile is never validated in Lua, it goes straight to the browser.
Weapon Icons
Icons live in images/icons/ — in the resource root, not under html/. 101 PNGs ship: one for every weapon named in config/weapons.lua, plus gadget_parachute.png.
The naming convention is the weapon's spawn name in lowercase, plus .png:
images/icons/weapon_assaultrifle_mk2.png
images/icons/weapon_pistol.png
Images are drawn scaled to fit, so there is no required size or aspect ratio — the shipped files range from tall and narrow to wide and flat.
An addon weapon
For the kill feed, one file is enough. Name it after the weapon:
images/icons/weapon_my_addon_rifle.png
No manifest edit is needed; the folder is already streamed as a glob.
For the per-weapon crosshair picker, the weapon also has to be listed in a category:
{
id = 'rifles',
label = 'Assault Rifles',
weapons = { 'weapon_assaultrifle', 'weapon_my_addon_rifle' },
},
Borrowing an icon
Rather than drawing a new PNG, point one weapon at another's:
iconAliases = {
weapon_my_addon_rifle = 'weapon_assaultrifle',
},
Both sides are weapon names without .png — the code appends it.
extraIcons registers an icon for something that is not a weapon in any category. It ships with one entry, gadget_parachute.
When an icon is missing
Nothing breaks; the fallback depends on where it would have been drawn:
| Place | Fallback |
|---|---|
| Kill feed | The weapon name in square brackets — [Carbine Rifle] |
| Weapon picker | The tile stays, dimmed |
| Kill feed style preview | The literal text [weapon] |
Changing Fixed Text
A few visible strings are written into html/index.html rather than the locale files. They are safe to edit there:
| Text | What it is |
|---|---|
KILL | The word shown next to the killmarker. Its colour, font and size are configurable; the word itself is not |
BOB / ROB | Labels on the crosshair preview figure |
What Not to Touch
html/script.js are load-bearingThe resource name. GetParentResourceName() is redefined to return the literal f5_combathud, and every request the menu makes is addressed through it. If you rename the resource folder, this string must change with it; if you change it to anything else, every save, profile action and marketplace call fails while the menu still looks fine.
The features schema version. FEATURES_SCHEMA_VERSION = 8 must match what the server sends. When the menu receives a higher number it disables every feature and falls back to safe defaults — that is the intended behaviour for a stale interface paired with a newer server, and it is exactly what you would cause by lowering it by hand.
Two more things to know before editing html/script.js yourself:
- Messages arrive batched. The client groups several updates into one
__batchenvelope per tick, with two exceptions that are always sent alone. Custom handling that assumes one message per event will miss most of them. - Styling is fair game, structure is not. Element ids are what the menu wires itself to —
html/style.csscan be changed freely, but removing or renaming an element inhtml/index.htmlbreaks the control that belongs to it.
See Also
- Configuration → Fonts and limits — the font whitelist
- Configuration → Weapons — categories and aliases
- Localization — text that lives in locale files
- Features — what these assets are used for