ngd-ui
Custom menu, input, cameras, ped interaction and more!
Installation Steps
-
Install ngd-ui
Putngd-uiinto your resources folder. Preferably into a[ngd]folder that is started after all of your main resources. If you are using this with ngd-Bridge, please refer to the start page to make sure your start order is correct. -
Click the UI element below to view it's features.
Helper Text (Click to Expand)
Help Text System
Overview
A bottom-center screen text display system for showing control hints and instructions to players. Supports both vertical and horizontal layouts with GTA color codes.
Features
- Two Layouts - Vertical (stacked) or horizontal (inline) text display
- Color Support - Full GTA color code support for highlighting
- Update Support - Change text without hiding/reshowing
- Protected Display - Prevents multiple instances from conflicting
- Zero Configuration - Works out of the box
Usage
Show Help Text
Display help text at the bottom center of the screen.
-- Basic usage (vertical layout)
exports['ngd-ui']:ShowHelpText('E: ~g~Interact | G: ~r~Cancel')
-- Horizontal layout
exports['ngd-ui']:ShowHelpText('Arrow Keys: Move | ENTER: ~g~Confirm', 'horizontal')
-- Force show (override existing)
exports['ngd-ui']:ShowHelpText('New text', 'vertical', true)
Update Help Text
Update the text without hiding/reshowing (useful for timers or counters).
exports['ngd-ui']:UpdateHelpText('TIME: ~r~5s~w~ remaining')
Hide Help Text
exports['ngd-ui']:HideHelpText()
Check if Showing
local isShowing = exports['ngd-ui']:IsHelpTextShowing()
if not isShowing then
-- Safe to show new help text
end
Parameters
ShowHelpText
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
text | string | Yes | - | Text to display with pipe-separated items |
layout | string | No | 'vertical' | 'vertical' or 'horizontal' |
force | boolean | No | false | Override existing help text |
Returns: boolean - true if shown, false if blocked
UpdateHelpText
| Parameter | Type | Required | Description |
|---|---|---|---|
text | string | Yes | New text to display |
Returns: boolean - true if updated, false if not showing
Implementation Examples
Placement Mode
CreateThread(function()
while placementMode do
exports['ngd-ui']:ShowHelpText('Arrow Keys: Move | Q/E: Rotate | ENTER: ~g~Place | BACKSPACE: ~r~Cancel')
Wait(0)
end
exports['ngd-ui']:HideHelpText()
end)
Vehicle Entry
CreateThread(function()
while nearVehicle do
exports['ngd-ui']:ShowHelpText('F: ~g~Enter Vehicle | H: ~y~Lock/Unlock', 'horizontal')
Wait(0)
end
exports['ngd-ui']:HideHelpText()
end)
Countdown Timer
CreateThread(function()
for i = 10, 0, -1 do
local color = i <= 3 and '~r~' or '~y~'
exports['ngd-ui']:UpdateHelpText('TIME: ' .. color .. i .. 's~w~ remaining | SPACE: ~g~Skip')
Wait(1000)
end
exports['ngd-ui']:HideHelpText()
end)
ATM Instructions
AddEventHandler('bank:atmOpened', function()
exports['ngd-ui']:ShowHelpText('Arrow Keys: Navigate | ENTER: ~g~Confirm | BACKSPACE: ~r~Exit')
end)
AddEventHandler('bank:atmClosed', function()
exports['ngd-ui']:HideHelpText()
end)
Dynamic Interaction Help
local function UpdateInteractionHelp(options)
local helpText = ''
for i, opt in ipairs(options) do
if i > 1 then helpText = helpText .. ' | ' end
helpText = helpText .. opt.key .. ': ' .. opt.color .. opt.label
end
exports['ngd-ui']:ShowHelpText(helpText, 'horizontal')
end
-- Usage
UpdateInteractionHelp({
{ key = 'E', color = '~g~', label = 'Open' },
{ key = 'G', color = '~b~', label = 'Lock' },
{ key = 'H', color = '~r~', label = 'Break In' }
})
Color Codes
Use GTA color codes to highlight text:
- Redr- Greeng- Blueb- Yellowy- Purplep- Whitew- Defaults
Example: 'E: gConfirmw | BACKSPACE: rCancel'
Layout Options
Vertical Layout (Default)
E: Open Door
G: Lock Door
H: Break In
Horizontal Layout
E: Open Door | G: Lock Door | H: Break In
Best Practices
- Always Hide When Done - Call
HideHelpText()when the context ends to prevent lingering text - Use in Loops - Call
ShowHelpText()every frame in your interaction loops withWait(0) - Update Don't Replace - Use
UpdateHelpText()for changing values (timers, counters) instead of hide/show
Notes
- Help text automatically prevents multiple instances unless
forceis true - Text remains on screen until manually hidden or overridden
- Works seamlessly with other UI elements (doesn't block NUI focus)
- Supports unlimited text length, but keep it concise for readability
Input (Click to Expand)
Input Dialog System
Overview
A comprehensive input dialog system supporting multiple field types including text, password, number, date, time, select, checkbox, and textarea. Perfect for forms, character creation, transactions, and data collection.
Features
- 9 Input Types - Text, password, number, date, time, select, checkbox, textarea, and multi-select
- Field Validation - Required fields, min/max values, character limits
- Rich Formatting - Icons, descriptions, placeholders, default values
- Flexible Layout - Standard or full-width fields
- Promise-based - Clean async/await pattern for handling results
Usage
Basic Input Dialog
local result = exports['ngd-ui']:InputDialog('Dialog Title', {
{ type = 'input', label = 'Player Name', required = true },
{ type = 'number', label = 'Amount', min = 1, max = 1000 }
}, { allowCancel = true })
if result then
local name = result[1]
local amount = result[2]
-- Process results
end
All Available Input Types
local result = exports['ngd-ui']:InputDialog('Form Title', {
-- Text Input
{
type = 'input',
label = 'Text Field',
description = 'Enter some text',
placeholder = 'Type here...',
icon = 'font',
required = true,
min = 3, -- Min characters
max = 50 -- Max characters
},
-- Password Input
{
type = 'password',
label = 'Password',
placeholder = 'Enter password...',
icon = 'lock',
min = 4,
max = 20
},
-- Number Input
{
type = 'number',
label = 'Amount',
icon = 'dollar-sign',
default = 0,
min = 0,
max = 999999,
precision = 2, -- Decimal places
step = 0.01 -- Increment step
},
-- Date Picker
{
type = 'date',
label = 'Select Date',
icon = 'calendar',
format = 'MM/DD/YYYY',
minDate = '01/01/2020',
maxDate = '12/31/2025'
},
-- Time Picker
{
type = 'time',
label = 'Select Time',
icon = 'clock'
},
-- Select Dropdown
{
type = 'select',
label = 'Choose Option',
icon = 'list',
options = {
{ value = 'option1', label = 'Option 1' },
{ value = 'option2', label = 'Option 2' },
{ value = 'option3', label = 'Option 3' }
},
searchable = true -- Enable search in dropdown
},
-- Multi-Select
{
type = 'multi-select',
label = 'Choose Multiple',
icon = 'list-check',
options = {
{ value = 'a', label = 'Choice A' },
{ value = 'b', label = 'Choice B' },
{ value = 'c', label = 'Choice C' }
},
maxSelectedValues = 3
},
-- Checkbox
{
type = 'checkbox',
label = 'I agree to terms',
checked = false,
required = true
},
-- Textarea
{
type = 'textarea',
label = 'Description',
placeholder = 'Enter detailed description...',
autosize = true,
fullWidth = true -- Makes dialog wider for this field
}
})
Parameters
Common Field Properties
| Property | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | Yes | 'input' | Field type (input, password, number, date, time, select, checkbox, textarea) |
label | string | Yes | - | Field label displayed to user |
description | string | No | - | Helper text below label |
placeholder | string | No | - | Placeholder text in input |
icon | string | No | - | FontAwesome icon name |
default | any | No | - | Default value |
required | boolean | No | false | Field is required |
disabled | boolean | No | false | Field is disabled |
fullWidth | boolean | No | false | Makes dialog wider for this field |
Text/Password Specific
| Property | Type | Description |
|---|---|---|
min | number | Minimum character length |
max | number | Maximum character length |
Number Specific
| Property | Type | Description |
|---|---|---|
min | number | Minimum value |
max | number | Maximum value |
precision | number | Decimal places (e.g., 2 for currency) |
step | number | Increment/decrement step |
hideControls | boolean | Hide +/- buttons |
Date Specific
| Property | Type | Description |
|---|---|---|
format | string | Date format (e.g., 'MM/DD/YYYY') |
minDate | string | Minimum selectable date |
maxDate | string | Maximum selectable date |
clearable | boolean | Show clear button |
returnString | boolean | Return as string instead of date object |
Select/Multi-Select Specific
| Property | Type | Description |
|---|---|---|
options | table | Array of {value, label} objects |
searchable | boolean | Enable search in dropdown |
maxSelectedValues | number | Max selections (multi-select only) |
Textarea Specific
| Property | Type | Description |
|---|---|---|
autosize | boolean | Auto-resize based on content |
Implementation Examples
Character Creation
local result = exports['ngd-ui']:InputDialog('Create Character', {
{ type = 'input', label = 'First Name', icon = 'user', required = true, min = 2, max = 20 },
{ type = 'input', label = 'Last Name', icon = 'user', required = true, min = 2, max = 20 },
{ type = 'date', label = 'Date of Birth', icon = 'calendar', required = true },
{ type = 'number', label = 'Height (cm)', icon = 'ruler-vertical', min = 100, max = 220, default = 170 },
{ type = 'select', label = 'Gender', icon = 'venus-mars', options = {
{ value = 'male', label = 'Male' },
{ value = 'female', label = 'Female' }
}},
{ type = 'checkbox', label = 'I agree to server rules', required = true }
})
if result then
local firstName = result[1]
local lastName = result[2]
local dob = result[3]
local height = result[4]
local gender = result[5]
local agreedToRules = result[6]
-- Create character
end
Bank Transfer
local result = exports['ngd-ui']:InputDialog('Bank Transfer', {
{ type = 'number', label = 'Recipient ID', icon = 'user', required = true, min = 1 },
{ type = 'number', label = 'Amount', icon = 'dollar-sign', required = true, precision = 2, min = 0.01 },
{ type = 'textarea', label = 'Note (optional)', placeholder = 'Add a message...', autosize = true }
})
if result then
local recipientId = result[1]
local amount = result[2]
local note = result[3] or ''
TriggerServerEvent('bank:transfer', recipientId, amount, note)
end
Job Application
local result = exports['ngd-ui']:InputDialog('Job Application', {
{ type = 'input', label = 'Full Name', icon = 'user', required = true },
{ type = 'number', label = 'Age', icon = 'calendar', min = 18, max = 99, required = true },
{ type = 'select', label = 'Position', icon = 'briefcase', required = true, options = {
{ value = 'officer', label = 'Police Officer' },
{ value = 'detective', label = 'Detective' },
{ value = 'cadet', label = 'Cadet' }
}},
{ type = 'textarea', label = 'Why do you want this job?', required = true, fullWidth = true }
})
if result then
local name = result[1]
local age = result[2]
local position = result[3]
local reason = result[4]
TriggerServerEvent('job:submitApplication', name, age, position, reason)
end
Vehicle Sale
local result = exports['ngd-ui']:InputDialog('Sell Vehicle', {
{ type = 'input', label = 'Buyer Name', icon = 'user', required = true },
{ type = 'number', label = 'Sale Price', icon = 'dollar-sign', required = true, precision = 2, min = 1 },
{ type = 'select', label = 'Payment Method', icon = 'credit-card', options = {
{ value = 'cash', label = 'Cash' },
{ value = 'bank', label = 'Bank Transfer' }
}},
{ type = 'checkbox', label = 'Include vehicle warranty', checked = true }
})
if result then
TriggerServerEvent('vehicle:processSale', result[1], result[2], result[3], result[4])
end
Store Order Form
local result = exports['ngd-ui']:InputDialog('Place Order', {
{ type = 'select', label = 'Product', icon = 'box', required = true, searchable = true, options = {
{ value = 'burger', label = 'Hamburger - $5' },
{ value = 'fries', label = 'French Fries - $3' },
{ value = 'soda', label = 'Soda - $2' }
}},
{ type = 'number', label = 'Quantity', icon = 'hashtag', min = 1, max = 99, default = 1 },
{ type = 'multi-select', label = 'Extra Toppings', icon = 'plus', options = {
{ value = 'cheese', label = 'Cheese (+$1)' },
{ value = 'bacon', label = 'Bacon (+$2)' },
{ value = 'onions', label = 'Onions (+$0.5)' }
}},
{ type = 'textarea', label = 'Special Instructions', placeholder = 'Any special requests?' }
})
if result then
local product = result[1]
local quantity = result[2]
local toppings = result[3] or {}
local instructions = result[4] or ''
TriggerServerEvent('store:placeOrder', product, quantity, toppings, instructions)
end
Return Values
The dialog returns:
- nil if cancelled
- table of values in field order if submitted
local result = exports['ngd-ui']:InputDialog('Title', {
{ type = 'input', label = 'Name' },
{ type = 'number', label = 'Age' }
})
if result then
local name = result[1] -- First field value
local age = result[2] -- Second field value
end
Notes
- Dialog automatically closes when submitted or cancelled
- Required fields prevent submission if empty
- Number fields enforce min/max constraints
- Date fields show a calendar picker
- Select fields support search with
searchable = true - Use
fullWidth = trueon textarea for better multi-line input - Icons use FontAwesome class names (without 'fa-' prefix)
Menu (Click to Expand)
Menu System
Overview
A flexible context menu system for creating interactive menus with support for buttons, checkboxes, and nested submenus. Perfect for game menus, interaction menus, and admin panels.
Features
- Multiple Option Types - Buttons, checkboxes, menu headers
- Event Triggers - Client events, server events
- Nested Menus - Support for submenu navigation with history
- Icon Support - FontAwesome icons or custom images
- Menu Registration - Register reusable menus by ID
- Position Control - Place menu anywhere on screen
Usage
Simple Menu (CreateMenu)
Create and display a menu immediately.
exports['ngd-ui']:CreateMenu({
{ header = 'Main Menu', isMenuHeader = true },
{
header = 'Option 1',
txt = 'Description of option 1',
icon = 'circle',
params = {
event = 'my:clientEvent',
args = {{ data = 'value', shouldClose = true }}
}
},
{
header = 'Option 2',
txt = 'This triggers a server event',
icon = 'square',
params = {
isServer = true,
event = 'my:serverEvent',
args = {{ id = 123, shouldClose = true }}
}
}
})
Registered Menu (RegisterMenu + OpenMenu)
Register a menu for reuse and open it later.
-- Register the menu
exports['ngd-ui']:RegisterMenu('main_menu', {
title = 'Main Menu',
position = 'center-right',
options = {
{ header = 'Settings Menu', isMenuHeader = true },
{
header = 'Settings',
txt = 'Configure your settings',
icon = 'gear',
params = {
event = 'menu:openSettings'
}
},
{
header = 'Exit',
txt = 'Close the menu',
icon = 'times',
params = {
event = 'menu:close'
}
}
}
})
-- Open the menu later
exports['ngd-ui']:OpenMenu('main_menu')
Menu Option Properties
| Property | Type | Required | Description |
|---|---|---|---|
header | string | Yes | Main text displayed |
txt | string | No | Description/subtitle text |
icon | string | No | FontAwesome icon (without 'fa-' prefix) or image path |
isMenuHeader | boolean | No | Makes this a non-clickable header |
disabled | boolean | No | Disable the option |
params | table | No | Event/action parameters |
Params Properties
| Property | Type | Description |
|---|---|---|
event | string | Event name to trigger |
args | table | Arguments to pass to event |
isServer | boolean | If true, triggers server event |
⚠️ Important Note on Args: Due to NUI serialization, args must be wrapped in a double table format.
Menu Functions
CreateMenu
Create and immediately display a menu.
exports['ngd-ui']:CreateMenu(options, position)
Parameters:
options- Table of menu optionsposition- Menu position ('center-right', 'top-right', etc.) - Default: 'center-right'
RegisterMenu
Register a menu for later use.
exports['ngd-ui']:RegisterMenu(id, menuData)
Parameters:
id- Unique menu identifiermenuData- Table containing title, position, options
OpenMenu
Open a previously registered menu.
exports['ngd-ui']:OpenMenu(id, keepHistory)
Parameters:
id- Menu identifierkeepHistory- If true, adds to navigation history - Default: false
CloseMenu
Close the currently open menu.
exports['ngd-ui']:CloseMenu()
GoBackMenu
Navigate to the previous menu in history.
exports['ngd-ui']:GoBackMenu()
UpdateMenuOptions
Update options of a registered menu.
exports['ngd-ui']:UpdateMenuOptions(id, options)
IsMenuOpen
Check if any menu is currently open.
local isOpen = exports['ngd-ui']:IsMenuOpen()
GetOpenMenu
Get the ID of the currently open menu.
local menuId = exports['ngd-ui']:GetOpenMenu()
Implementation Examples
Crafting Menu
exports['ngd-ui']:CreateMenu({
{ header = 'Pour Wine Menu', isMenuHeader = true },
{
header = 'Red Wine',
txt = 'Required: Grapes, Sugar',
icon = 'wine-bottle',
params = {
event = 'wine:pour',
args = {{ drink = 'red_wine' }}
}
},
{
header = 'White Wine',
txt = 'Required: White Grapes, Sugar',
icon = 'wine-glass',
params = {
isServer = true,
event = 'wine:pourServer',
args = {{ drink = 'white_wine' }}
}
},
{
header = 'Champagne',
txt = 'Required: Special Grapes',
icon = 'glass-cheers',
disabled = true
}
})
Vehicle Interaction Menu
exports['ngd-ui']:CreateMenu({
{ header = 'Vehicle Options', isMenuHeader = true },
{
header = 'Toggle Engine',
txt = 'Turn engine on/off',
icon = 'car',
params = {
event = 'vehicle:toggleEngine'
}
},
{
header = 'Open Trunk',
txt = 'Access vehicle storage',
icon = 'box',
params = {
event = 'vehicle:openTrunk'
}
},
{
header = 'Lock/Unlock',
txt = 'Toggle vehicle locks',
icon = 'lock',
params = {
event = 'vehicle:toggleLock'
}
}
})
Position Options
Available menu positions:
'center-right'(default)'center-left''top-left''top-right''bottom-left''bottom-right''center'
Event Handling
Client Event
RegisterNetEvent('myEvent', function(args)
print('Received:', args.data)
end)
Server Event
RegisterNetEvent('myServerEvent', function(args)
local src = source
print('Player:', src, 'Args:', args.id)
end)
Checkbox Event
RegisterNetEvent('settings:toggleHUD', function(checked)
print('HUD toggled:', checked) -- true or false
end)
Icon Usage
Icons can be specified in two ways:
FontAwesome Icons
Use the icon name without the fa- prefix:
icon = 'circle' -- renders as fa-solid fa-circle
icon = 'gear' -- renders as fa-solid fa-gear
icon = 'wine-bottle' -- renders as fa-solid fa-wine-bottle
Custom Images
Use NUI path for custom images:
icon = 'nui://myresource/images/custom.png'
Notes
- Menus automatically handle NUI focus (mouse cursor)
- Args use single table format (not double-nested like other exports)
- Menu headers with
isMenuHeader = trueare non-clickable section labels - Checkbox options trigger events with boolean checked state
- Menu history allows navigation with GoBackMenu()
- Default menu position is
center-right - Icons without path prefix are treated as FontAwesome icons
Security Camera (Click to Expand)
Security Camera System
Overview
The Security Camera System provides an optimized camera viewing interface with zero idle CPU usage when cameras are not active. Players can cycle through multiple security cameras with keyboard controls and a clean HUD overlay.
Features
- Zero Idle Performance Impact - No CPU usage when cameras are inactive
- Multiple Camera Support - Configure unlimited cameras per system
- Smooth Navigation - Arrow key controls to switch between cameras
- System Branding - Custom system name and subtitle for each installation
- HUD Integration - Automatic HUD hiding with camera info overlay
- Debounced Switching - 500ms cooldown prevents accidental double-switches
Configuration
Basic Setup
Config.CameraSystem = {
systemName = "Daddy Tobacco",
systemSubtitle = "Security System",
cameras = {
{
coords = vector3(-34.05, 2895.45, 63.90),
heading = 225.31,
pitch = -20.0,
roll = 0.0,
name = "Front Gate"
},
{
coords = vector3(-72.86, 2927.90, 65.13),
heading = 277.27,
pitch = -35.0,
roll = 0.0,
name = "North Sideyard"
},
}
}
Camera Properties
| Property | Type | Required | Description |
|---|---|---|---|
coords | vector3 | Yes | Camera position in world space |
heading | float | Yes | Camera yaw rotation (0-360) |
pitch | float | No | Camera pitch rotation (default: 0.0) |
roll | float | No | Camera roll rotation (default: 0.0) |
name | string | Yes | Display name shown in UI |
System Properties
| Property | Type | Required | Description |
|---|---|---|---|
systemName | string | No | Main title (e.g., "Daddy Tobacco") |
systemSubtitle | string | No | Subtitle (e.g., "Security System") |
cameras | table | Yes | Array of camera configurations |
Usage
Opening Camera System
-- With full configuration
exports['ngd-ui']:OpenCameras(Config.CameraSystem)
-- With just cameras array (no system name/subtitle)
exports['ngd-ui']:OpenCameras({
{ coords = vector3(x, y, z), heading = 0.0, name = "Camera 1" },
{ coords = vector3(x, y, z), heading = 90.0, name = "Camera 2" }
})
Closing Camera System
exports['ngd-ui']:CloseCameras()
Manual Camera Navigation
-- Switch to next camera
exports['ngd-ui']:NextCamera()
-- Switch to previous camera
exports['ngd-ui']:PreviousCamera()
Controls
| Key | Action |
|---|---|
| Left Arrow (174) | Previous camera |
| Right Arrow (175) | Next camera |
| Backspace (194) | Exit camera system |
Exports
OpenCameras
Opens the camera viewing system.
Parameters:
data(table): Configuration table or camera array
Example:
exports['ngd-ui']:OpenCameras({
systemName = "Prison",
systemSubtitle = "Maximum Security",
cameras = {
{ coords = vector3(1845.0, 2585.0, 45.0), heading = 180.0, name = "Cell Block A" }
}
})
CloseCameras
Closes the camera system and restores normal view.
Example:
exports['ngd-ui']:CloseCameras()
NextCamera
Switches to the next camera in the sequence (wraps to first camera at end).
Example:
exports['ngd-ui']:NextCamera()
PreviousCamera
Switches to the previous camera in the sequence (wraps to last camera at start).
Example:
exports['ngd-ui']:PreviousCamera()
Implementation Examples
Example 1: Simple Security Office
RegisterCommand('officesecurity', function()
exports['ngd-ui']:OpenCameras({
systemName = "Downtown Office",
systemSubtitle = "Security Cameras",
cameras = {
{ coords = vector3(-75.0, -818.0, 326.0), heading = 90.0, pitch = -25.0, name = "Lobby" },
{ coords = vector3(-75.0, -827.0, 326.0), heading = 180.0, pitch = -30.0, name = "Elevator" },
{ coords = vector3(-68.0, -823.0, 326.0), heading = 270.0, pitch = -20.0, name = "Parking" }
}
})
end)
Example 2: Store Security System
local storeCameras = {
systemName = "24/7 Supermarket",
systemSubtitle = "Store #143",
cameras = {
{ coords = vector3(28.0, -1339.0, 31.0), heading = 225.0, pitch = -30.0, name = "Entrance" },
{ coords = vector3(25.0, -1345.0, 31.0), heading = 135.0, pitch = -25.0, name = "Counter" },
{ coords = vector3(31.0, -1343.0, 31.0), heading = 315.0, pitch = -20.0, name = "Aisles" }
}
}
-- Triggered by interaction with security monitor
RegisterNetEvent('store:viewCameras', function()
exports['ngd-ui']:OpenCameras(storeCameras)
end)
Notes
- No idle CPU usage when cameras are inactive
- 500ms cooldown between camera switches prevents accidental double-switching
- Camera rotation uses standard FiveM format: Heading (0-360┬░), Pitch (negative looks down), Roll (usually 0.0)
Flipbook (Click to Expand)
Flipbook/Menu System
Overview
A visual flipbook system for displaying multi-page menus, catalogs, or documents. Players can flip through pages with a clean interface and optional title/subtitle branding.
Features
- Multi-Page Support - Display unlimited pages with automatic numbering
- Custom Branding - Optional title and subtitle for each flipbook
- Flexible Format - Supports JPG, PNG, and other image formats
- Resource Integration - Load images from any resource using NUI paths
- Simple Controls - Arrow keys or buttons to flip pages
Configuration
Basic Setup
Config.Menu = {
title = "Vanilla Unicorn",
subtitle = "Drink Menu",
imagePath = "nui://ngd-vu/web/images/",
pages = 2,
imageFormat = "jpg"
}
Image File Structure
Your images should be named sequentially starting from 1:
your-resource/
web/
images/
1.jpg
2.jpg
3.jpg
Usage
Opening a Flipbook
-- With full configuration
exports['ngd-ui']:OpenFlipbook(Config.Menu)
-- Inline configuration
exports['ngd-ui']:OpenFlipbook({
title = "Gun Store",
subtitle = "Available Weapons",
imagePath = "nui://myresource/web/pages/",
pages = 5
})
-- Simple version (no title/subtitle)
exports['ngd-ui']:OpenFlipbook({
imagePath = "nui://ngd-vu/web/images/",
pages = 2
})
Closing a Flipbook
exports['ngd-ui']:CloseFlipbook()
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
title | string | No | '' | Main title displayed on flipbook |
subtitle | string | No | '' | Subtitle displayed under title |
imagePath | string | Yes | - | NUI path to image folder (must end with /) |
pages | number | Yes | - | Number of page images |
imageFormat | string | No | 'jpg' | Image file extension (jpg, png, etc.) |
Implementation Examples
Restaurant Menu
exports['ngd-ui']:OpenFlipbook({
title = "Burger Shot",
subtitle = "Menu",
imagePath = "nui://burgershot/web/menu/",
pages = 4,
imageFormat = "png"
})
Nightclub Drink Menu
local vuMenu = {
title = "Vanilla Unicorn",
subtitle = "Drink Menu",
imagePath = "nui://ngd-vu/web/images/",
pages = 2
}
RegisterNetEvent('vu:openMenu', function()
exports['ngd-ui']:OpenFlipbook(vuMenu)
end)
Clothing Catalog
exports['ngd-ui']:OpenFlipbook({
title = "Ponsonbys",
subtitle = "Spring Collection 2024",
imagePath = "nui://clothing-store/catalog/",
pages = 8
})
Gun Store Catalog
AddEventHandler('gunstore:openCatalog', function()
exports['ngd-ui']:OpenFlipbook({
title = "Ammu-Nation",
subtitle = "Firearms Catalog",
imagePath = "nui://gunstore/web/catalog/",
pages = 6,
imageFormat = "png"
})
end)
Simple Product Catalog (No Branding)
exports['ngd-ui']:OpenFlipbook({
imagePath = "nui://my-store/products/",
pages = 3
})
Image Preparation Tips
- Naming Convention: Name your images sequentially:
1.jpg,2.jpg,3.jpg, etc. - Resolution: Recommended 1920x1080 or 16:9 aspect ratio for best display
- File Size: Optimize images to reduce load times (under 500KB per image recommended)
- Path: Always end
imagePathwith a forward slash/
NUI Path Examples
-- From your resource
imagePath = "nui://my-resource/web/images/"
-- From another resource
imagePath = "nui://qb-shops/html/menus/"
-- Nested folders
imagePath = "nui://server-ui/public/catalogs/guns/"
Notes
- Players can close the flipbook by pressing ESC or clicking the close button
- Images are loaded dynamically as players flip through pages
- The
imagePathmust be a valid NUI path accessible from your resource - Image files must be sequential starting from 1 (no gaps in numbering)
3D Drawtext (Click to Expand)
3D Draw Text & Interaction System
Overview
An optimized 3D text rendering and interaction system that replaces traditional target systems. Features distance-based rendering, persistent markers, and interactive prompts with zero idle CPU usage.
Features
- Interaction System - Target replacement with keypress detection
- Text Markers - Persistent 3D text labels (no interaction)
- 3D Text - Persistent text that auto-manages rendering
- Draw3DText - Simple draw function for manual loops
- Smart Sleep - Distance-based thread optimization
Configuration
None required. Optional debug flag: Config.ThreeDTextDebug = true
Usage
Interaction System
Create interactive points that respond to key presses.
Single Option
exports['ngd-ui']:AddInteraction({
id = 'shop_door',
coords = vector3(25.0, -1347.0, 29.5),
key = 'E',
keyLabel = 'E',
label = 'Open Shop',
icon = 'fa-solid fa-store',
color = '~g~',
range = 2.5,
onInteract = function(id, data)
-- Your code here
end
})
Multiple Options
exports['ngd-ui']:AddInteraction({
id = 'boss_safe',
coords = vector3(25.0, -1347.0, 29.5),
icon = 'fa-solid fa-briefcase',
range = 3.0,
options = {
{
key = 'E',
keyLabel = 'E',
label = 'Open Stash',
color = '~g~',
onInteract = function()
-- Your code here
end
},
{
key = 'G',
keyLabel = 'G',
label = 'Boss Menu',
color = '~b~',
job = 'police',
onInteract = function()
-- Your code here
end
}
}
})
Managing Interactions
-- Update label
exports['ngd-ui']:UpdateInteraction('shop_door', 'Shop Closed')
-- Update position
exports['ngd-ui']:UpdateInteractionCoords('shop_door', vector3(x, y, z))
-- Remove specific interaction
exports['ngd-ui']:RemoveInteraction('shop_door')
-- Clear all interactions
exports['ngd-ui']:ClearAllInteractions()
Text Markers
Display 3D text without interaction (informational only).
-- Add marker
exports['ngd-ui']:AddTextMarker(
'parking_sign',
vector3(215.0, -810.0, 30.0),
'Public Parking',
10.0,
'fa-solid fa-parking'
)
-- Update text
exports['ngd-ui']:UpdateTextMarker('parking_sign', 'Parking Full')
-- Update position
exports['ngd-ui']:UpdateTextMarkerCoords('parking_sign', vector3(x, y, z))
-- Remove marker
exports['ngd-ui']:RemoveTextMarker('parking_sign')
-- Clear all markers
exports['ngd-ui']:ClearAllTextMarkers()
Persistent 3D Text
Auto-managed 3D text that handles its own rendering loop.
-- Add persistent text
exports['ngd-ui']:Add3DText(
'welcome_sign',
vector3(0.0, 0.0, 70.0),
'Welcome to Los Santos',
15.0,
'fa-solid fa-star'
)
-- Update text
exports['ngd-ui']:Update3DText('welcome_sign', 'Welcome Back!')
-- Update position
exports['ngd-ui']:Update3DTextCoords('welcome_sign', vector3(x, y, z))
-- Remove text
exports['ngd-ui']:Remove3DText('welcome_sign')
-- Clear all texts
exports['ngd-ui']:ClearAll3DTexts()
Draw3DText (Manual Loop)
Simple draw function for use inside your own loops.
CreateThread(function()
while someCondition do
exports['ngd-ui']:Draw3DText(
vector3(x, y, z),
'E: ~g~Interact',
10.0,
'fa-solid fa-hand'
)
Wait(0)
end
exports['ngd-ui']:Hide3DText()
end)
Parameters
Interaction Options
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | - | Unique identifier |
coords | vector3 | Yes | - | World position |
key | string/number | No | - | Key to press (single option) |
keyLabel | string | No | 'E' | Display label for key |
label | string | No | - | Text to display (single option) |
icon | string | No | - | FontAwesome icon class |
color | string | No | ' | GTA color code |
range | number | No | 2.5 | Interaction range |
job | string/table | No | - | Required job(s) |
notJob | string/table | No | - | Excluded job(s) |
onInteract | function | No | - | Callback function |
options | table | No | - | Array of multiple options |
Text Marker Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | - | Unique identifier |
coords | vector3 | Yes | - | World position |
text | string | Yes | - | Text to display |
range | number | No | 5.0 | Visibility range |
icon | string | No | - | FontAwesome icon class |
3D Text Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | Yes | - | Unique identifier |
coords | vector3 | Yes | - | World position |
text | string | Yes | - | Text to display |
distance | number | No | 10.0 | Visibility distance |
icon | string | No | - | FontAwesome icon class |
Color Codes
Use GTA color codes in your text:
- Redr- Greeng- Blueb- Yellowy- Purplep- Whitew- Defaults
Example: 'E: gOpen w| rG: Close'
Job Filtering
-- Single job
job = 'police'
-- Multiple jobs
job = {'police', 'ambulance'}
-- Exclude jobs
notJob = 'unemployed'
notJob = {'unemployed', 'civilian'}
Implementation Examples
Store Entrance
exports['ngd-ui']:AddInteraction({
id = 'store_24_7',
coords = vector3(25.0, -1347.0, 29.5),
key = 'E',
label = 'Open Store',
icon = 'fa-solid fa-store',
range = 2.0,
onInteract = function()
TriggerEvent('store:openMenu')
end
})
ATM Machine
exports['ngd-ui']:AddInteraction({
id = 'atm_main_1',
coords = vector3(-386.7, 6046.0, 31.5),
key = 'E',
label = 'Use ATM',
icon = 'fa-solid fa-credit-card',
color = '~b~',
range = 1.5,
onInteract = function()
TriggerEvent('bank:openATM')
end
})
Police Evidence Locker
exports['ngd-ui']:AddInteraction({
id = 'pd_evidence',
coords = vector3(475.0, -995.0, 26.3),
icon = 'fa-solid fa-box-archive',
range = 2.0,
options = {
{
key = 'E',
label = 'View Evidence',
job = 'police',
onInteract = function()
-- Open evidence UI
end
},
{
key = 'G',
label = 'Submit Evidence',
job = 'police',
color = '~y~',
onInteract = function()
-- Submit evidence
end
}
}
})
Parking Zone Sign
exports['ngd-ui']:AddTextMarker(
'parking_downtown',
vector3(215.0, -810.0, 30.0),
'~b~Public Parking~w~\n$5 per hour',
12.0,
'fa-solid fa-square-parking'
)
Notes
- Interactions use
Wait(0)when player is in range for precise key detection - Out of range, threads use smart sleep (100ms-1000ms) based on distance
- Text scale automatically adjusts based on distance (0.7-1.0)
- All loops automatically stop when no elements are registered
Notification System (Click to Expand)
Notification System
Overview
A clean, modern notification system for FiveM that supports icons, sounds, positions, themes, and server-side triggering. Offers two interfaces ΓÇö standard Notify and advanced Notify with icon support.
Features
- Simple syntax ΓÇö one-line usage
- Themed notifications ΓÇö success, error, warning, info, default
- Position control ΓÇö choose where your notifications display
- Progress bar toggle ΓÇö show or hide the bar
- Icon support ΓÇö FontAwesome icons
- Sound toggle
Parameters
Notify
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
title | string | Yes | - | Main text heading |
message | string | No | '' | Secondary text line |
time | number | Yes | 5000 | Duration in ms |
type | string | No | 'default' | success | error | warning | info | default |
position | string | No | 'center-right' | See position list below |
hideprogressbar | boolean | No | false | Hides progress bar |
sound | boolean | No | true | Plays notification sound |
Usage
Notify (Standard)
exports['ngd-ui']:Notify(
title, -- string (required)
message, -- string (optional)
time, -- number in ms (required)
type, -- string (optional)
position, -- string (optional)
hideprogressbar, -- boolean (optional)
sound -- boolean (optional)
)
NotifyAdvanced (With Icon Support)
exports['ngd-ui']:NotifyAdvanced({
title = "",
message = "",
time = 5000,
type = "default",
icon = "", -- FontAwesome icon name
position = "",
hideProgressBar = false,
sound = true
})
Examples
Basic Notification
exports['ngd-ui']:Notify("Success!", "You did the thing", 5000, "success")
Error Notification
exports['ngd-ui']:Notify("Error", "Something went wrong", 5000, "error")
Custom Position
exports['ngd-ui']:Notify("Warning", "Low fuel detected", 5000, "warning", "top-center")
Without Progress Bar
exports['ngd-ui']:Notify("Note", "Progress bar disabled", 5000, "info", "top-right", true)
No Sound
exports['ngd-ui']:Notify("Shhh...", "Sound disabled for this notification", 5000, "info", nil, nil, false)
Advanced Notification Examples
Custom Icon Notification
exports['ngd-ui']:NotifyAdvanced({
title = "Vehicle Stored",
message = "Your vehicle has been stored in the garage",
time = 5000,
type = "success",
icon = "car",
position = "top-right"
})
Server-Side Usage
Trigger a Client Notification from Server
TriggerClientEvent('ngd-ui:Notify', source, "Job Complete!", "You earned $500", 5000, "success")
NotifyAdvanced
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
title | string | Yes | - | Main text heading |
message | string | No | '' | Secondary text line |
time | number | Yes | 5000 | Duration in ms |
type | string | No | 'default' | success | error | warning | info | default |
icon | string | No | nil | FontAwesome icon name |
position | string | No | 'center-right' | See position list |
hideProgressBar | boolean | No | false | Hides progress bar |
sound | boolean | No | true | Plays sound |
Returns: none
Position Options
top-right
top-left
top-center
bottom-right
bottom-left
bottom-center
center-right (default)
above-center-right
Notification Types
| Type | Color/Style |
|---|---|
success | Green highlight |
error | Red highlight |
warning | Yellow highlight |
info | Blue highlight |
default | Neutral style |
Example Implementation
Item Pickup
AddEventHandler('items:pickup', function(label)
exports['ngd-ui']:Notify("Picked Up", "You collected: " .. label, 3000, "success")
end)
Fuel Warning
if fuel <= 5 then
exports['ngd-ui']:Notify("Fuel Low", "Find a gas station!", 5000, "warning", "bottom-center")
end
Crafting Complete
exports['ngd-ui']:NotifyAdvanced({
title = "Crafting Complete",
message = "Your item is ready to use!",
type = "success",
icon = "hammer",
sound = true
})
Simple Shops (Click to Expand)
Shop UI System
Overview
A flexible NUI-based shop interface for FiveM that supports dynamic shop data, custom server events, and automatic item image paths. Intended for clean, modern shop implementations using a single data format.
Features
- Config-based shops ΓÇô reusable, structured shop definitions
- Inline shops ΓÇô create shops directly from code
- Custom server events ΓÇô handle purchases in any resource
- Image auto-resolution ΓÇô automatic full
nui://path building - Slot sorting ΓÇô automatic sort by slot ordering
- Simple exports ΓÇô
OpenShopandCloseShop
Exports
OpenShop
exports['ngd-ui']:OpenShop(data)
data should be a shop table containing:
{
name = "Shop Name",
imagePath = "path/to/images/",
serverEvent = "myresource:Server:Purchase",
items = {
{ name = "water", label = "Water", price = 5 },
...
}
}
CloseShop
exports['ngd-ui']:CloseShop()
Closes the currently open shop and releases UI focus.
Shop Data Format
Structure
local shop = {
name = "My Shop",
imagePath = "nui://ox_inventory/web/images/",
serverEvent = "myresource:Server:Purchase",
items = {
{ name = "vodka", label = "Vodka", price = 10 },
...
}
}
Open with:
exports['ngd-ui']:OpenShop(shop)
Item Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Item database name |
label | string | No | auto | Display label in UI |
price | number | No | 0 | Price per item |
count | number | No | nil | Optional stock control |
image | string | No | auto | Custom image path |
slot | number | No | auto | Display ordering |
info | table | No | nil | Extra purchase info |
type | string | No | nil | For your own logic |
Image Handling
The UI will automatically:
- Normalize image paths
- Append missing prefixes (
nui://) - Append missing file extensions if needed
- Build fallback images using item names
Example fallback:
imagePath .. "water.png"
Server Event Behavior
When a shop purchase occurs, the client sends:
local purchaseData = {
shopId = data.shopId,
items = data.items,
total = data.total
}
If a custom serverEvent is defined
TriggerServerEvent("myresource:Server:Purchase", purchaseData)
If no serverEvent is defined
The shop system defaults to:
TriggerServerEvent("ngd-ui:Server:ShopPurchase", purchaseData)
Inline Example
exports['ngd-ui']:OpenShop({
name = "Snack Bar",
serverEvent = "my_snacks:Server:Purchase",
items = {
{ name = "water", label = "Water Bottle", price = 5 },
{ name = "sandwich", label = "Sandwich", price = 25 }
}
})
Config Example
Config = Config or {}
Config.AlcoholStore = {
name = "Alcohol Store",
imagePath = "nui://ngd-vu/web/images/",
serverEvent = "ngd-vu:Server:StorePurchases",
items = {
{ name = "vodka", label = "Vodka", price = 10 },
{ name = "whiskey", label = "Whiskey", price = 15 }
}
}
exports['ngd-ui']:OpenShop(Config.AlcoholStore)
Closing the Shop
exports['ngd-ui']:CloseShop()
This gets called automatically when the shop items are purchased or the shop gets closed out. This is just useful for your other resources to potentially close the shop menu. (Maybe if a player dies while in a shop?)
Progress Bars (Click to Expand)
Progress Bar System
Overview
A flexible progress bar system for ngd-ui that is compatible with common progressbar-style exports.
Supports linear and circular progress bars, animations, props, control disabling, cancellation, and both synchronous and callback-based usage.
Features
- Drop-in compatible with progressbar-style data and callbacks
- Two styles ΓÇô standard bar and circular progress
- Cancelable ΓÇô X or BACKSPACE (configurable via
canCancel) - Control locking ΓÇô movement, vehicle, mouse, and combat
- Animations & props ΓÇô play an animation and attach one or two props
- Synchronous or async ΓÇô return boolean or use a callback
- Dead checks ΓÇô optional
useWhileDeadprotection - Helpers ΓÇô cancel & state check exports
Exports
exports['ngd-ui']:Progress(data, cb?) -- linear bar
exports['ngd-ui']:ProgressCircle(data, cb?) -- circular bar
exports['ngd-ui']:CancelProgress() -- force-cancel active progress
exports['ngd-ui']:IsDoingProgress() -- returns boolean
-- Optional direct sync access (internal helpers)
exports['ngd-ui']:ProgressSync(data)
exports['ngd-ui']:ProgressCircleSync(data)
cb?= optional callback
Basic Usage
1. Simple linear bar (callback style)
exports['ngd-ui']:Progress({
label = "Lockpicking...",
duration = 5000, -- ms
canCancel = true,
controlDisables = {
disableMovement = true,
disableCarMovement = true,
disableMouse = false,
disableCombat = true
}
}, function(cancelled)
if not cancelled then
print("Success!")
else
print("Cancelled")
end
end)
2. Simple linear bar (sync / blocking)
local success = exports['ngd-ui']:Progress({
label = "Searching...",
duration = 3000
})
if success then
print("Search complete")
else
print("Search cancelled or failed")
end
3. Circular progress bar
exports['ngd-ui']:ProgressCircle({
label = "Scanning Area...",
duration = 7000,
canCancel = true
}, function(cancelled)
if not cancelled then
print("Scan finished")
end
end)
Data Format
The system accepts one unified data table and will internally normalise common progressbar fields.
Top-level fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
label | string | No | "Loading..." | Text shown in the progress UI |
name | string | No | used if label is nil | Alternative label (progressbar-style) |
duration | number | Yes | - | Duration in milliseconds |
canCancel | boolean | No | false | Whether player can cancel with X/BACKSPACE |
useWhileDead | boolean | No | nil | If false and ped is dead, progress is cancelled immediately |
disable | table | No | derived | Explicit control disable table (see below) |
controlDisables | table | No | - | Common progressbar-style control flags (mapped to disable) |
anim | table | No | derived | Animation definition (see below) |
animation | table | No | - | Progressbar-style animation table (mapped to anim) |
prop | table | No | nil | Prop to attach (see props) |
propTwo | table | No | nil | Second prop to attach |
Control Disables
You may use either disable (native format) or controlDisables (progressbar-style).
disable format
disable = {
disableMovement = true,
disableMouse = false,
disableCar = true,
disableCombat = true
}
controlDisables (mapped automatically)
controlDisables = {
disableMovement = true,
disableCarMovement = true,
disableMouse = false,
disableCombat = true
}
Mapped internally to:
disable.disableCar=disableCarMovementordisableCar
Animations
You can play an animation during the progress bar.
Native anim format
anim = {
dict = "amb@world_human_hammering@male@base",
anim = "base",
flag = 49 -- optional
}
Progressbar-style animation (mapped automatically)
animation = {
animDict = "amb@world_human_bum_wash@male@low@idle_a",
anim = "idle_a",
flag = 49, -- or
flags = 49
}
If both are supplied,
animtakes priority.
Animations are started before the bar and stopped automatically when it completes or is cancelled.
Props
You can optionally attach one or two props to the ped during progress.
Prop fields
Each prop / propTwo may contain:
| Field | Type | Required | Description |
|---|---|---|---|
model | string/int | Yes | Model name or hash |
bone | number | No | Ped bone index (default: 60309 hand) |
pos | vector3 | No | Offset position relative to bone |
rot | vector3 | No | Rotation relative to bone |
coords | table | No | { x, y, z } alternative to pos |
rotation | table | No | { x, y, z } alternative to rot |
Example:
prop = {
model = "prop_tool_hammer",
bone = 57005,
pos = vector3(0.1, 0.02, -0.02),
rot = vector3(90.0, 0.0, 0.0)
}
coords/rotationare automatically converted intovector3if provided instead ofpos/rot.
Props are deleted automatically after completion or cancellation.
Cancellation
If canCancel = true, the player can cancel using:
- X key (
INPUT_VEH_DUCK, control 73) - BACKSPACE key (control 177)
Internally, the system:
- Sends
cancelProgress/cancelProgressCircleto NUI - Resolves the promise with
{ completed = false, cancelled = true } - Sets
isDoingProgressback tofalse
For callback-based usage, the callback receives:
function(cancelled)
if cancelled then
-- user cancelled or failed
else
-- success
end
end
For synchronous usage, Progress / ProgressCircle return:
true→ completedfalse→ cancelled or failed
CancelProgress Export
exports['ngd-ui']:CancelProgress()
Force-cancel whichever progress (bar or circle) is active.
Safe to call even if no progress is running.
Typical use:
if exports['ngd-ui']:IsDoingProgress() then
exports['ngd-ui']:CancelProgress()
end
IsDoingProgress Export
local active = exports['ngd-ui']:IsDoingProgress()
if active then
print("Progress in progress...")
end
Returns true if a progress bar or circle is currently running, otherwise false.
Notes & Best Practices
- Always set
durationΓÇô progress without a duration is rejected and logged as an error. - Use callbacks for non-blocking flows ΓÇô when running in threads that shouldnΓÇÖt block gameplay logic.
- Use
useWhileDead = falsewhen the action shouldnΓÇÖt be possible while dead. - Avoid double starts ΓÇô if
Progressis called while another is active, it returnsfalseand does nothing. - Keep labels short ΓÇô long labels may wrap or clip depending on UI design.
PED Dialog (Click to Expand)
Dialog / PED Interaction System
Overview
A lightweight dialog system for ngd-ui that lets you open an interactive conversation UI with any PED or object.
It supports titles, icons, descriptions, tags, and a list of clickable choices that can trigger client events, server events, commands, or Lua functions.
When opened, a cinematic camera focuses on the target PED for a more immersive interaction.
Features
- Cinematic camera focused on the interacting PED
- Custom dialog content ΓÇô title, icon, description, tags
- Multi-choice interactions per dialog
- Supported action types:
- client events
- server events
- commands
- custom Lua functions
- Dynamic dialog updates without closing the UI
- Automatic focus management between game + UI
Exports
TalkToNPC
exports['ngd-ui']:TalkToNPC(entity, dialog)
Opens the dialog UI for a given PED or entity.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
entity | number | Yes | Entity handle (usually a PED/object) |
dialog | table | Yes | Dialog configuration (structure below) |
UpdateDialog
exports['ngd-ui']:UpdateDialog(dialog)
Updates the currently open dialog contents.
Useful for multi-step interactions, branching dialogs, and dynamic text.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
dialog | table | Yes | New dialog structure to display |
If no dialog is currently open, nothing happens.
Dialog Structure
A dialog is a Lua table:
local dialog = {
title = "Character Name",
icon = "user",
description = "Some dialog text here.",
choices = { /* choice list */ },
tags = { "NPC", "Quest" }
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | Header label in dialog |
icon | string | No | FontAwesome icon name |
description | string | No | Body text |
choices | table[] | Yes | Action list |
tags | string[] | No | Optional info labels |
Choice Structure
Each entry in dialog.choices is a clickable option:
{
title = "Redeem Ticket",
shouldClose = false,
shouldHide = false,
clientEvent = "myresource:Client:Redeem",
serverEvent = "myresource:Server:Redeem",
command = "me waves",
func = function(args) end,
args = { some = "data" }
}
Choice Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
title | string | Yes | - | UI text for button |
shouldClose | boolean | No | false | Close dialog after click |
shouldHide | boolean | No | false | Hide UI during function execution |
clientEvent | string | No | nil | Client event to trigger |
serverEvent | string | No | nil | Server event to trigger |
command | string | No | nil | Command string to run |
func | function | No | nil | Custom Lua function |
args | any/table | No | nil | Optional data for events/function |
Action Order
When a choice is clicked, ngd-ui does:
-
Calls
SetPedTalk(CurrentNPC)(if present in your project). -
Reads
CurrentDialog.choices[index]. -
If
choice.shouldClose == true, closes the dialog & camera. -
If
choice.clientEventis set:TriggerEvent(choice.clientEvent, choice.args) -
If
choice.serverEventis set:TriggerServerEvent(choice.serverEvent, choice.args) -
If
choice.commandis set:ExecuteCommand(choice.command) -
If
choice.funcis set:- If
choice.shouldHideis true, the dialog is hidden first. choice.func(args)is executed.- If
choice.shouldHideis true, the dialog is shown again afterwards.
- If
Camera Behavior
When TalkToNPC is called:
CurrentNPCis stored.- A camera is placed slightly in front of the NPC.
- A scripted camera is created and activated:
- Focused on the NPC
- Slightly above and facing them
- NUI focus is enabled.
When the dialog is closed (e.g. via shouldClose = true):
- Scripted camera is destroyed.
- Script cam rendering stops.
- NUI focus is released.
- Internal dialog/NPC references are cleared.
Basic Usage Example
Simple vendor dialog
local function OpenVendorDialog(ped)
exports['ngd-ui']:TalkToNPC(ped, {
title = "Ticket Vendor",
icon = "ticket",
description = "Welcome! What would you like to do?",
tags = { "Service", "Vendor" },
choices = {
{
title = "Redeem Ticket",
shouldClose = false,
clientEvent = "myresource:Client:RedeemTicket",
args = { type = "standard" }
},
{
title = "Ask a Question",
shouldClose = false,
command = "me asks a question"
},
{
title = "Goodbye",
shouldClose = true
}
}
})
end
You can hook this into a target system or interaction:
AddEventHandler("myresource:OpenVendor", function(ped)
OpenVendorDialog(ped)
end)
Real-World Example
Test PED dialog from ngd-ui
local function BuildIntroDialog(ped)
local serverId = GetPlayerServerId(PlayerId())
local choices = {}
-- Option 1: Who are you?
choices[#choices + 1] = {
title = "Who are you?",
shouldClose = false,
func = function()
exports['ngd-ui']:UpdateDialog({
title = "About Me",
icon = "user",
description = "I'm just a test NPC used to demonstrate the ngd-ui dialog system.",
tags = { "ngd-ui is cool!" },
choices = {
{
title = "Back",
shouldClose = false,
func = function()
exports['ngd-ui']:UpdateDialog(BuildIntroDialog(ped))
end
},
{
title = "Goodbye",
shouldClose = true,
func = function()
CreateTestPedText()
end
}
}
})
end
}
-- Option 2: What is this UI?
choices[#choices + 1] = {
title = "What is this UI?",
shouldClose = false,
func = function()
exports['ngd-ui']:UpdateDialog({
title = "ngd-ui Dialog",
icon = "info-circle",
description = "This is a demo conversation showing how dialogs can update without closing.",
tags = { "Dialog Update Example" },
choices = {
{
title = "Back",
shouldClose = false,
func = function()
exports['ngd-ui']:UpdateDialog(BuildIntroDialog(ped))
end
},
{
title = "Goodbye",
shouldClose = true,
func = function()
CreateTestPedText()
end
}
}
})
end
}
-- Option 3: Goodbye (main menu)
choices[#choices + 1] = {
title = "Goodbye",
shouldClose = true,
func = function()
CreateTestPedText()
end
}
return {
title = "Test NPC",
icon = "user",
description = "Hi there! Choose an option below to see dialog updates in action.",
tags = { "TAG Example", "I am just an NPC :(", "Live Variables. Server ID: " .. serverId },
choices = choices
}
end
Triggered with:
exports['ngd-ui']:TalkToNPC(testPed, BuildIntroDialog(testPed))
Notes & Best Practices
- Always provide a
titleand at least onechoice. - Use
UpdateDialogfor multi-step flows instead of closing and reopening. - Use
shouldHidewhen you temporarily need to hide the dialog to show another UI. - Prefer server events for game-changing actions (items/money) and client events for local visuals.
- Keep descriptions and choice titles concise for readability.
Test Commands (Click to Expand)
Test Commands
Enable test commands by setting Config.TestCommands = true in your configuration.
Camera System
| Command | Description |
|---|---|
/testcameras | Opens a test camera system with 3 cameras. Use arrow keys to switch, backspace to exit. |
Flipbook
| Command | Description |
|---|---|
/testflipbook | Opens a test flipbook menu. Use arrow keys or buttons to flip pages, ESC to close. |
Menu
| Command | Description |
|---|---|
/testmenu | Opens a basic context menu with 3 options (button, server event, checkbox). |
Input Dialog
| Command | Description |
|---|---|
/testinput | Opens a basic input dialog with 2 fields (name and age). |
/testinputfull | Opens a dialog showcasing all input types (text, password, number, date, select, checkbox). |
Help Text
| Command | Description |
|---|---|
/testhelptext | Shows vertical help text at bottom center for 5 seconds. |
/testhelptexth | Shows horizontal help text at bottom center for 5 seconds. |
3D Text & Interactions
| Command | Description |
|---|---|
/testinteract | Creates a single interaction point 2m ahead. Press E when in range. |
/testmulti | Creates a multi-option interaction 2m ahead. Press E or G when in range. |
/testmarker | Creates an information text marker 3m ahead. |
/cleartests | Removes all test interactions and markers. |
Notification System
| Command | Description |
|---|---|
/testnotify | Shows a standard notification |
/testnotifyall | Shows all of the notifications. |
/testnotifyicon | Shows an 'advanced' notification with FA icon. |
Simple Shops
| Command | Description |
|---|---|
/testshop | Opens a shop. |
Progress Bars
| Command | Description |
|---|---|
/testprogress | Runs a test progress bar. |
/testpcircle | Runs a circle test progress bar. |
/testpprop | Runs a progress bar with a prop. |
PED Dialog
| Command | Description | Requires |
|---------|-------------|
| /testdialog | This opens the dialog for the test ped found at coords: 116.36, -1088.41, 28.23 | Config.TestPedInteractions = true
Debug Commands
| Command | Description | Requires |
|---|---|---|
/drawtextdebug | Shows debug info for all active 3D text elements, markers, and interactions. | Config.ThreeDTextDebug = true |
Usage Example
-- Enable in your config file
Config.TestCommands = true
Config.ThreeDTextDebug = true
-- In-game
Use the / commands listed above to show examples of each UI element.
Configuration Notes
- Editable Files
Please review the editable files in theclientandserverfolder and enter in the correct exports for your servers configuration.
Do you still need help? Open a ticket in our Discord