UI / NUI conventions
Each resource has its own NUI page (ui_page 'html/index.html'). bs_ui is the HUD, the notifications and the shared bits.
One panel at a time: bs:ui:opened / bs:ui:closed
Section titled “One panel at a time: bs:ui:opened / bs:ui:closed”When your panel opens you announce it. Every other panel hears it and closes itself. When yours closes, you announce that too. Real code from bs_config:
local function close() if not isOpen then return end isOpen = false SetNuiFocus(false, false) SendNUIMessage({ action = 'close' }) TriggerEvent('bs:ui:closed', 'config')end
local function open() if isOpen then return close() end isOpen = true SetNuiFocus(true, true) SendNUIMessage({ action = 'open', data = data }) TriggerEvent('bs:ui:opened', 'config')end
-- another UI took over: step asideAddEventHandler('bs:ui:opened', function(what) if what ~= 'config' and isOpen then close() endend)
AddEventHandler('onResourceStop', function(res) if res == GetCurrentResourceName() and isOpen then SetNuiFocus(false, false) TriggerEvent('bs:ui:closed', 'config') endend)Rules:
- Pass your panel name in both events. Handlers check it, a handler that reacts to any close broke the field map for months.
- Pair them on every exit: close button, Esc, toggle key, another UI opening, resource stop. Miss one and the player is stuck with a mouse cursor and no game.
- Announce
openedafter you are open, and close yourself from your own handler, don’t assume others will.
/refreshui (bs_ui) is the panic button: it closes everything, drops focus and fires bs:ui:closed with nil.
Notifications
Section titled “Notifications”-- clientTriggerEvent('bs:ui:notify', { type = 'info', title = 'Radio', message = 'Signal found.', duration = 3000 })-- serverTriggerClientEvent('bs:ui:notify', src, { type = 'error', title = 'Denied', message = 'Nope.' })Types used around the code: info, success, error.
scale.js
Section titled “scale.js”Pages are laid out for 1920x1080. Include the shared scaler so they fit any resolution:
<script src="https://cfx-nui-bs_ui/html/shared/scale.js"></script>It scales <body> with a transform: --ui-scale = clamp(min(w/1920, h/1080), 0.6, 1.25). Players can override it (0.6 to 1.4) in settings.
Things to know when you use it:
- In page CSS write
vh/vwascalc(Nvh / var(--ui-scale, 1)), so they stay real viewport fractions. - JS that sets
style.left/topfromclientX/clientYor a bounding rect must divide byBSScale.get().BSScale.w()/BSScale.h()give the local viewport. - Opt out with
<html data-bs-noscale>.
House style
Section titled “House style”html, body { background: transparent !important; }on every page. Otherwise you get a black screen over the game.- No NUI messages every frame while idle. Push on change, or throttle (the drone HUD sends every 150 ms while flying, that’s about the max).
- Palette is amber / rust / bone / dust on near-black. Reuse the bs_ui CSS tokens and
bs_menu/html/css/faction-hub.css. No external fonts or CDNs, players may not have internet access to them and it’s a privacy thing anyway. - Icons: line icons in
bs_ui/html/js/icons.js. - Sounds:
bs_ui/html/js/sound.jshandles positional sounds (maxDistance, panning).
bs19.org · Privacy · Terms · Cookie settings