Skip to content

Interface overview ​

tm_lib ships its own interface: toasts, text prompts, dialogs, menus, a radial menu, progress bars and skill checks. It is the replacement for ox_lib's UI in every Twilight Moon resource (resources never call ox_lib's UI directly), and it is fully themed from the in game admin panel.

There are two interface pages in tm_lib. Do not mix them up:

PageFolderWhat it isDocs
Interface (this section)ui/The fixed set of ready made widgets below. tm_lib owns the page, you call functions.this section
Windowsui-windows/A schema driven page for custom forms, panels and tabs: you describe a window as a Lua table. Your resource points its own ui_page at it.tm.ui.window

Use the interface functions for the common things (tell the player something, ask a yes or no, pick from a list, show a progress bar). Reach for tm.ui.window when you need a screen of your own.

Setup ​

Nothing beyond the usual two lines. There is no ui_page to set and nothing to build:

lua
-- fxmanifest.lua
dependencies { 'ox_lib', 'tm_lib' }
shared_scripts { '@ox_lib/init.lua', '@tm_lib/init.lua' }

tm_lib must be started before your resource (ensure tm_lib first). Every function below is then a field of tm.

What is available ​

FeatureFunctionsSidePage
Toaststm.notify, tm.dismissNotification, tm.clearAllNotificationsclient and serverNotifications
Text promptstm.showTextUI, tm.updateTextUI, tm.hideTextUI, tm.isTextUIOpenclientNotifications
Confirm dialogtm.alertDialog, tm.closeAlertDialogclientDialogs
Form dialogtm.inputDialog, tm.closeInputDialogclientDialogs
Context menustm.registerContext, tm.showContext, tm.hideContext, tm.getOpenContextMenuclientMenus
List menustm.registerMenu, tm.showMenu, tm.hideMenu, tm.getOpenMenu, tm.setMenuOptionsclientMenus
Radial menutm.radial.addItem, tm.radial.removeItem, tm.radial.registerMenu, tm.radial.open, tm.radial.close, tm.radial.disable and moreclientRadial menu
Progresstm.progressBar, tm.progressCircle, tm.progressActive, tm.cancelProgressclientProgress
Skill checktm.skillCheck, tm.skillCheckActive, tm.cancelSkillCheckclientSkill checks
Themetm.theme.tokens, tm.theme.push, tm.theme.bindclientTheme
Admin hubtm.admin.registerPanel, tm.admin.openForserverSettings and the admin panel

The names match ox_lib's UI functions on purpose, so moving a script over is mostly replacing lib. with tm..

Rules that apply to all of it ​

  • Client only, except tm.notify. tm.notify(source, data) also exists on the server. Everything else needs the client.
  • Blocking calls wait for the player. alertDialog, inputDialog, progressBar, progressCircle and skillCheck pause the calling thread until the player answers (they use a promise internally), so call them from a thread, an event handler or a callback, never from the main chunk of a file.
  • One at a time. There is one alert dialog, one input dialog, one context menu, one list menu, one progress and one skill check on screen. Opening another dialog or menu replaces the current one and its waiting caller gets the cancel result ('cancel' or nil). Starting a progress or skill check while another runs returns false immediately and logs a warning. Toasts and text prompts stack.
  • Cleanup is automatic. When your resource stops, everything it opened is closed, so a player is never left with a focused dialog nothing will answer. When tm_lib stops, everything closes.
  • Focus is shared. The interface tracks NUI focus across all open widgets, so closing one never steals focus from another that is still open.
  • A bad callback cannot break the interface. Your onSelect, onClose and similar callbacks run protected. An error is logged (tm.log.error) and the interface carries on.
  • Text is a locale key. Pass tm.locale.t('your.key') as the text of anything the player reads, never a literal.

Icons ​

Wherever a function takes an icon, it accepts:

FormExample
Lucide (bundled, always works)'lucide:car'
Font Awesome class names'fas fa-coins', 'fa-solid fa-car', or the bare name 'car'
ox_lib style tuple{ 'fas', 'star' }
Inventory item image'item:water'
Image URL'https://...'

Prefer lucide: names. Font Awesome is bundled too, so none of these are fetched online.

Colors ​

type, color, iconColor and colorScheme take a tone name, a scheme name or any CSS color.

KindValues
Tonessuccess (alias positive), error (negative), warning, info (inform, ongoing), primary, accent, dark
Schemesred, orange, yellow, green, teal, blue, indigo, purple, pink, gray, white
Anything elsepassed through as a CSS color: '#ff8800', 'rgb(255 136 0)'

Screen positions ​

Toasts and text prompts use nine zones: top-left, top-center, top-right, center-left, center, center-right, bottom-left, bottom-center, bottom-right. The short names top, bottom, left, right, left-center and right-center also work. Menus use top-left, top-right, bottom-left, bottom-right, or a table { x = 40, y = 120 } / { right = 40, y = 120 } in pixels.

Autocomplete ​

The interface functions are typed in tm_lib/types (see Lua types), so with the language server set up you get hover docs and parameter hints for TmNotifyData, TmAlertData, TmInputRow, TmContextMenu, TmMenuData, TmProgressData and the rest.

Next ​