A lightweight, optimized standalone script for rendering 3D interactive text labels in the world. It features a dual-loop automatic culling system for high performance, proximity scaling, and support for "tap" and "hold" interactions with visual progress tracking.
⚙️ Data Structures
Before using the functions, understand the data tables used to configure an interaction point.
The Main Configuration Table
This table defines where the text is and how it behaves.
Property
Type
Default
Description
coords
vector3
Required
The world coordinates where the text should appear.
options
table
Required
A list of interaction options (see below).
distance
float
2.5
The distance at which the UI switches to "Full" mode (interaction enabled).
maxDistance
float
5.0
The max distance at which the text is visible at all.
scale
float
1.0
Scaling factor for the UI element.
arc
boolean
false
Visual flag passed to UI (optional style preference).
The Options Table
The options list contains the specific inputs available to the player. Note: Callbacks are now defined directly inside each option via the action property.
options= { { label="PICK UP", -- The action text displayedkey=38, -- The FiveM Control Index (38 is E)keyName="E", -- (Optional) The visual key name. Falls back to Lib47.Keys if omitted.action=function()-- The function triggered upon interactionprint("Item picked up!")end,isVisible=function()-- (Optional) Determines if the option shows up at allreturntrueend,canInteract=function()-- (Optional) If false, the option is visible but disabled/grayed outreturntrueend }, { label="INSPECT", key=74, -- 74 is HkeyName="H",hold=3, -- (Optional) Seconds button must be held to triggeraction=function()print("Inspected!")end }}
🛠️ API Reference
This script exposes functions and assigns them to the global Lib47 table. It utilizes an automatic slow culling loop (checking within 30.0 units) and a fast interaction loop, meaning you no longer need to check distances manually in your own threads.
1. RegisterTextUi3d (Static Mode)
Best for static, permanent locations (e.g., Shops, Duty points, ATMs). You register it once, and the script's internal culling handles the rest.
Usage: Lib47.RegisterTextUi3d(data)
Returns: string (The Interaction ID, derived from coordinates).
2. ShowTextUi3d (Dynamic/Immediate Mode)
Best for dynamic entities (like dropping an item on the ground). This registers the point temporarily. If you walk away, it will eventually be culled out unless updated.
Usage: Lib47.ShowTextUi3d(data)
Returns: string (Interaction ID).
3. HideTextUi3d & RemoveTextUi3d
Hides or completely removes an interaction point.
Usage: Lib47.HideTextUi3d(id) or Lib47.RemoveTextUi3d(id)
📝 Code Examples
Example A: Static Location (Register Mode)
Use this for permanent locations. Run this code once (e.g., at resource start). You do not need a loop.
Example B: Dynamic State & Conditional Logic
Use the isVisible and canInteract functions to dynamically change how the text behaves based on the player's state (e.g., job, money, or items).
Example C: Using Exports directly
If you do not use the Lib47 global wrapper, you can use the resource exports directly via the Interface wrapper.
CreateThread(function()
local position = vector3(373.59, 328.58, 103.68)
-- Register the point once, the script handles distance and culling automatically
Lib47.RegisterTextUi3d({
coords = position,
distance = 2.5,
maxDistance = 5.0,
options = {
{
label = "PICK UP",
key = 38,
keyName = "E",
action = function()
print("Player picked up item")
end
},
{
label = "INSPECT",
key = 74,
keyName = "H",
hold = 3, -- 3 Second Hold
action = function()
print("Player inspected item")
end
}
},
})
end)
CreateThread(function()
local atmCoords = vector3(100.0, 100.0, 20.0)
Lib47.RegisterTextUi3d({
coords = atmCoords,
distance = 2.0,
options = {
{
label = "USE ATM",
key = 38,
keyName = "E",
isVisible = function()
-- Only show if the player is not in a vehicle
return not IsPedInAnyVehicle(PlayerPedId(), false)
end,
canInteract = function()
-- Visible, but grayed out if the player is dead
return not IsEntityDead(PlayerPedId())
end,
action = function()
print("Accessing ATM...")
end
}
}
})
end)