Lumo UI — API
All exports are client side unless marked server. Call them as exports['lumo-ui']:Name(...). Scripts written for qb-target, qb-menu, qb-input, qb-radialmenu or progressbar can keep their old calls through the [compat] shims (see Migration).
Notifications
lua
exports['lumo-ui']:Notify(text, type, duration, icon, title)
-- type: 'info' (or 'primary') | 'success' | 'error' | 'warning'
-- text may also be a table: { text = '...', caption = 'Title' }
TriggerEvent('lumo-ui:client:notify', text, type, duration) -- same, as an event
TriggerClientEvent('lumo-ui:client:notify', src, text, type, duration) -- from the serverlumo-hud-ui:client:notify is still accepted for older scripts.
Text UI
lua
exports['lumo-ui']:ShowText('[E] Open door') -- '[E]' becomes the key cap
exports['lumo-ui']:ShowText('Open door', 'right', 'G') -- position: left (default) | right; players can override it in /ui
exports['lumo-ui']:ChangeText('[E] Close door')
exports['lumo-ui']:HideText()
-- DrawText is an alias of ShowText. KeyPressed() flashes the key cap.
exports['lumo-ui']:DisplayTextUI('Open', 'E') -- the text-UI module's own prompt
exports['lumo-ui']:HideTextUI()
exports['lumo-ui']:IsTextUIShown()
-- World labels pinned to a point, drawn only when near and on screen:
exports['lumo-ui']:Create3DTextUI('bin', { coords = vec3(...), displayDist = 6.0, interactDist = 2.0,
enableKeyClick = true, keyNum = 38, key = 'E', text = 'Search bin',
triggerData = { triggerName = 'myres:searchBin', args = {} } })
exports['lumo-ui']:Update3DTextUI('bin', { text = 'Empty' })
exports['lumo-ui']:Delete3DTextUI('bin')
-- Create3DTextUIOnPlayers(id, { id = serverId, ... }) / Delete3DTextUIOnPlayers(id): above another player.Target eye
Same names and arguments as qb-target, so code written for it moves over by changing 'qb-target' to 'lumo-ui' (or by keeping the shim).
lua
exports['lumo-ui']:AddBoxZone(name, center, length, width, { heading, minZ, maxZ }, targetOptions)
exports['lumo-ui']:AddCircleZone(name, center, radius, { useZ }, targetOptions)
exports['lumo-ui']:AddPolyZone(name, points, { minZ, maxZ }, targetOptions)
exports['lumo-ui']:AddComboZone(zones, { name }, targetOptions)
exports['lumo-ui']:AddEntityZone(name, entity, { length, width }, targetOptions)
exports['lumo-ui']:RemoveZone(name)
exports['lumo-ui']:AddTargetModel(models, targetOptions) -- RemoveTargetModel(models, labels)
exports['lumo-ui']:AddTargetEntity(entities, targetOptions) -- RemoveTargetEntity(entities, labels)
exports['lumo-ui']:AddTargetBone(bones, targetOptions) -- RemoveTargetBone(bones, labels)
exports['lumo-ui']:AddGlobalPed / AddGlobalVehicle / AddGlobalObject / AddGlobalPlayer(targetOptions)
exports['lumo-ui']:RemoveGlobalPed / ... (labels)
-- targetOptions:
{
distance = 2.5,
options = {
{
label = 'Search', icon = 'fas fa-magnifying-glass',
type = 'client', -- client | server | command | qbcommand
event = 'myres:search', -- or: action = function(entity) ... end
job = 'police', -- or { police = 2 } for a minimum grade; also gang, jobType, citizenid, item
excludejob = 'ambulance',
canInteract = function(entity, distance, data) return true end,
},
},
}Options are kept by label: adding a label again replaces it, removing by label removes it. SpawnPed, RemoveSpawnedPed, DeletePeds, GetPeds, UpdatePedsData, AllowTargeting(bool), IsTargetActive(), IsTargetSuccess() and the Get*Data readers work as in qb-target.
Zones need no PolyZone: box, circle, polygon, entity and combo zones are tested inside lumo-ui. /targetdebug (admins) adds test options to everything.
Radial menu
lua
local id = exports['lumo-ui']:AddRadialOption({
id = 'mdt', title = 'MDT', icon = 'tablet',
type = 'command', -- client | server | command | qbcommand
event = 'mdt', -- or action = function() ... end
shouldClose = true,
canOpen = function() return true end, -- hide the item when false
downed = false, -- true: the only kind of item shown while downed
-- items = { ... } -- a submenu instead of an event
}, optionalId)
exports['lumo-ui']:RemoveRadialOption(id)
exports['lumo-ui']:IsRadialOpen()
exports['lumo-ui']:CloseRadial()Items added by a resource are removed when that resource stops. Items come in this order: config.lua Items, the job's JobItems (as a "Work" submenu while on duty), added items sorted by id, then the vehicle menu while seated.
Events: lumo-ui:client:radialOpened, lumo-ui:client:radialClosed.
Context menu
lua
exports['lumo-ui']:OpenMenu({
{ header = 'Shop', isMenuHeader = true },
{ header = 'Water', txt = '$5', icon = 'fas fa-bottle-water', item = 'water',
params = { event = 'shop:server:buy', isServer = true, args = { item = 'water' } } },
{ header = 'Close', action = function() end },
})
exports['lumo-ui']:CloseMenu()
exports['lumo-ui']:ShowHeader(entries) -- header-only, focused with Left Alt
exports['lumo-ui']:IsMenuOpen()params takes isServer, isCommand, isQBCommand or isAction; otherwise event is a client event. item shows the inventory image. Function fields never reach the browser. Event: lumo-ui:client:menuClosed.
Input dialog
lua
local data = exports['lumo-ui']:ShowInput({
header = 'Fine', submitText = 'Send',
inputs = {
{ type = 'number', name = 'amount', text = 'Amount', isRequired = true },
{ type = 'select', name = 'reason', text = 'Reason', options = { { value = 'speed', text = 'Speeding' } } },
-- text | password | number | radio | checkbox | select | color | date | time
},
})
if data then print(data.amount, data.reason) end -- nil when closed
exports['lumo-ui']:CloseInput()ShowInput waits for the answer, so call it from a thread.
Progress bar
lua
exports['lumo-ui']:Progress({
name = 'repair', duration = 5000, label = 'Repairing', useWhileDead = false, canCancel = true,
controlDisables = { disableMovement = true, disableCarMovement = true, disableMouse = false, disableCombat = true },
animation = { animDict = 'mini@repair', anim = 'fixing_a_ped' },
prop = { model = 'prop_tool_wrench', bone = 57005, coords = vec3(0.1, 0, 0), rotation = vec3(0, 0, 0) },
}, function(cancelled) end)
-- ProgressWithStartEvent / ProgressWithTickEvent / ProgressWithStartAndTick as in progressbar
exports['lumo-ui']:CancelProgress()
exports['lumo-ui']:IsDoingSomething()Every start gets one answer: cancelled = false when it completes, true when it is cancelled or refused because another bar is running.
HUD
lua
exports['lumo-ui']:SetStatus('hunger', 80) -- hunger | thirst | stress, 0–100 (standalone/custom frameworks)
exports['lumo-ui']:GetStatus('stress')
exports['lumo-ui']:GetMapShape() -- 'square' | 'circle'QBCore/Qbox status comes from player metadata and hud:client:UpdateNeeds; ESX from esx_status:onTick. The hud:client:* and seatbelt:client:* events from qb-hud are handled (ToggleSeatbelt, UpdateNitrous, UpdateHarness, OnMoneyChange, ShowAccounts, …).
Server:
lua
exports['lumo-ui']:AddStress(src, amount)
exports['lumo-ui']:RemoveStress(src, amount)
exports['lumo-ui']:GetStress(src)
exports['lumo-ui']:GetAdminSettings()
TriggerServerEvent('hud:server:GainStress', amount) -- clamped
TriggerServerEvent('hud:server:RelieveStress', amount)Overlays
lua
-- Timers (several at once, no focus). Ids are per calling resource.
local id = exports['lumo-ui']:StartTimer({ id = 'delivery', seconds = 90, mode = 'countdown',
label = 'DELIVERY WINDOW', text = 'Reach the customer', position = 1, format = 'clock', urgent = 10000 })
exports['lumo-ui']:UpdateTimer(id, { text = 'Destination changed', position = 3 })
exports['lumo-ui']:HideTimer(id) -- StopTimer is an alias; IsTimerActive(id)
-- position: 1 centre-bottom, 2 centre-top, 3 right, 4 above location,
-- or { x = 72, y = 18, anchor = 'center' }. Finished: 'lumo-hud-ui:client:timerFinished' (id, owner)
-- Minigame bar (you drive the progress)
exports['lumo-ui']:ShowMinigame({ kind = 'shake', label = 'STRUGGLE', hint = 'SHAKE MOUSE', progress = 0 })
exports['lumo-ui']:UpdateMinigame(progress, outcome) -- outcome: nil | 'win' | 'fail'
exports['lumo-ui']:HideMinigame()
-- Repeat-tap minigame (lumo-ui drives it)
exports['lumo-ui']:StartTapMinigame({ difficulty = 'normal', label = 'Keep tapping' }, function(won, info) end)
exports['lumo-ui']:CancelTapMinigame() -- difficulty: normal | medium | hard
-- Key hints and noise meter
exports['lumo-ui']:ShowKeys({ { key = 'E', label = 'Pick up' }, { key = 'G', label = 'Drop' } })
exports['lumo-ui']:HideKeys()
exports['lumo-ui']:ShowNoise({ label = 'NOISE', level = 20, danger = 70 })
exports['lumo-ui']:UpdateNoise(level, sneaking)
exports['lumo-ui']:HideNoise()Settings and other events
| Event | Side | Meaning |
|---|---|---|
lumo-hud-ui:client:settingsChanged (settings) | client, fired | a player changed /ui |
lumo-hud-ui:client:requestSettings | client, listen | ask for a settingsChanged |
lumo-hud-ui:client:phoneState (open) | client, listen | phone open: HUD makes room |
lumo-hud-ui:client:startLayoutEdit | client, listen | open the layout editor |
lumo-ui:client:playerData (data) | client, fired | PlayerData refreshed |
lumo-ui:client:openMenu / closeMenu / progress / cancelProgress | client, listen | event forms of the exports |
Other UIs (inventory, phone…) can share the theme by including '@lumo-ui/client/bridge.lua' in their client scripts.