Exports & Developer API
These are client exports unless stated otherwise. Add dependency 'finals_UI' to the caller and start Finals first. Waiting APIs must run in a yieldable thread/event/callback.
Optional helper
-- Your fxmanifest.lua:
client_scripts {'@finals_UI/init.lua','client.lua'}
dependency 'finals_UI'
-- Your client.lua:
fui.notify({title='Hello',type='success'})Direct calls use exports.finals_UI:method(...).
Notification and TextUI
exports.finals_UI:notify({
title='Outfit saved',description='Your new look is ready.',
type='success',duration=4000,position='top-right',icon='check'
})
exports.finals_UI:showTextUI('[E] Open locker [G] View options',{
icon='hand',position='right-center'
})
exports.finals_UI:hideTextUI()
local open,text=exports.finals_UI:isTextUIOpen()defaultNotify is also available. TextUI uses separate bracketed key tokens. Notifications do not take menu focus.
Progress bar and circle
CreateThread(function()
local success=exports.finals_UI:progressCircle({
duration=5000,label='Searching for the car keys...',position='middle',
canCancel=true,disable={move=true,car=true,combat=true}
})
print(success and 'Completed' or 'Canceled')
end)Use progressBar(data) for a linear bar. Duration is milliseconds. These calls wait and return completion/cancellation. progressActive() checks activity; cancelProgress() cancels. Optional animation/prop settings are supported. Revalidate rewards on the server.
Timer
exports.finals_UI:showTimer({
id='event',label='Event countdown',seconds=5652,position='left-center',
onComplete=function() print('Countdown finished') end
})
exports.finals_UI:updateTimer('event',{seconds=120,label='Final round'})
local timer=exports.finals_UI:getTimer('event')
local active=exports.finals_UI:isTimerActive('event')
exports.finals_UI:hideTimer('event')Timer duration is seconds, unlike progress. IDs are caller-scoped; update/remove from that resource. autoHide=false keeps a completed timer until hidden. Timers are display utilities, not authoritative server clocks.
Input and confirmation
CreateThread(function()
local input=exports.finals_UI:inputDialog('Save outfit',{
{type='input',label='Name',required=true},
{type='select',label='Category',options={{value='casual',label='Casual'},{value='work',label='Work'}}}
})
if not input then return end
print(input[1],input[2])
local answer=exports.finals_UI:alertDialog({
header='Save this outfit?',content='You can change it later.',centered=true,cancel=true
})
if answer=='confirm' then print('Confirmed') end
end)Supported controls include inputs/passwords, number, checkbox, select/multi-select, slider and supported date/time fields. closeInputDialog() and closeAlertDialog() close active dialogs. Handle cancellation and validate values on the server.
Context menu
exports.finals_UI:registerContext({
id='my_garage',title='Garage',options={
{title='View vehicles',icon='car',onSelect=function() print('Open garage') end},
{title='Unavailable',disabled=true}
}
})
exports.finals_UI:showContext('my_garage')
-- hideContext(onExit?) / getOpenContextMenu()Submenus use menu on an option and a registered child context. Give the child the parent menu ID for Back navigation. Keep IDs unique.
List menu
exports.finals_UI:registerMenu({
id='vehicle_prefs',title='Vehicle preferences',position='top-right',
options={{label='Headlights',values={'Off','Low','High'}},{label='Lock doors',checked=true}}
},function(selected,scrollIndex,args)
print(selected,scrollIndex)
end)
exports.finals_UI:showMenu('vehicle_prefs')
-- hideMenu(onExit?) / getOpenMenu() / setMenuOptions(id,options,index?)Radial menu
exports.finals_UI:addRadialItem({
id='example',label='Information',icon='circle-info',
onSelect=function() print('Selected radial item') end
})
-- removeRadialItem('example') / clearRadialItems() / hideRadial()registerRadial(data) defines a submenu; root items may reference its menu ID. Other APIs are showRadial(), disableRadial(boolean), getCurrentRadialId(). Use the configured key rather than duplicating the binding in another script.
Skill check
CreateThread(function()
local passed=exports.finals_UI:skillCheck({'easy','medium'},{'e'})
print(passed and 'Success' or 'Failed/canceled')
end)
-- skillCheckActive() / cancelSkillCheck()Visibility
exports.finals_UI:hideHud()
exports.finals_UI:showHud()
exports.finals_UI:setHudVisible(false)
exports.finals_UI:hideUI('speedometer')
exports.finals_UI:showUI('speedometer')
exports.finals_UI:setComponentVisible('minimap',false)
exports.finals_UI:hideUI() -- all UI
exports.finals_UI:showUI()
local visible=exports.finals_UI:isComponentVisible('hud')
local state=exports.finals_UI:getUIVisibility()Each caller owns its hides. Show from the same resource to release a hide; other resources' hides remain active. Requests clear on caller stop. Config/player settings and parent hides retain priority. Show does not reopen a canceled dialog or force an inactive component open.
Names: hud, stats, speedometer, minimap, compass, voice, logo, info, infoName, infoServer, infoCash, infoBank, infoJob, infoGang, chat, notify, textui, timer, progress, context, menu, radial, input, alert, skillcheck, target, interaction, pausemenu, editor, all.
Hiding an interactive component closes/releases focus; progress/input/skill checks cancel. HUD visibility does not hide unrelated chat/notifications/menus. Voice includes the world mic; speedometer includes the hologram. Server scripts should use their own validated client event for these calls.
Other APIs
- setClipboard(text) copies client text.
- getTheme() returns the palette; setUiTheme(key) selects a configured theme.
- setSeatbelt(boolean) pushes belt display state.
- World registration methods are covered in Targets & 3D World Interactions.
- registerTargetProvider, targetMessage and setTargetFocus are adapter plumbing. Ordinary scripts should continue calling their target API.
Server authority
Never treat a client UI success as authorization. Revalidate permissions, distance, inventory, cooldown and transaction/reward conditions server-side before changing gameplay state.