DrawMarker, help text and lib.showTextUI without lag in FiveM
Draw markers and show 'Press E' prompts in FiveM without a heavy loop: DrawMarker only when near, help text natives, lib.showTextUI and ox_lib points for zones.
You draw a marker, walk up to it and it flickers, or it never shows, or your script sits at 0.30 ms in resmon doing nothing. Markers and "Press E" prompts look simple, but they are the classic source of heavy loops. This article shows how to draw a marker correctly, how to show a prompt, and how to stop paying for it when the player is far away.
DrawMarker has to run every frame
A marker is drawn for one frame each time you call DrawMarker. To keep it on screen you call it again every frame, in a loop with Wait(0):
local coords = vec3(441.2, -981.9, 30.7)
CreateThread(function()
while true do
DrawMarker(
1, -- type: cylinder
coords.x, coords.y, coords.z - 1.0, -- position (on the ground)
0.0, 0.0, 0.0, -- direction
0.0, 0.0, 0.0, -- rotation
1.5, 1.5, 0.5, -- scale
50, 150, 255, 120, -- red, green, blue, alpha
false, false, 2, false, nil, nil, false
)
Wait(0)
end
end)That works, but it runs every frame for the whole session, even when the player is across the map. Fix that next.
Only draw when the player is near
Measure the distance and sleep longer when the player is far. Only the near state needs Wait(0):
local coords = vec3(441.2, -981.9, 30.7)
CreateThread(function()
while true do
local sleep = 1000
local pedCoords = GetEntityCoords(PlayerPedId())
local distance = #(pedCoords - coords)
if distance < 15.0 then
sleep = 0
DrawMarker(1, coords.x, coords.y, coords.z - 1.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 0.5,
50, 150, 255, 120, false, false, 2, false, nil, nil, false)
if distance < 1.5 then
-- show the prompt here (next section)
end
end
Wait(sleep)
end
end)Far away, the loop wakes once a second and does one subtraction. Near the marker it runs per frame, only while it needs to. Why this matters, and how to read it in resmon, is in resmon high ms: how to optimize.
Tip:
#(a - b)is the length of a vector difference, the distance. It needsvec3values, whichGetEntityCoordsalready returns.
Marker types
The first argument is the marker type, a number. A few that servers use a lot:
| Type | Looks like |
|---|---|
1 |
A cylinder |
2 |
A chevron arrow (rotate it 180 degrees on X to point down) |
23 |
A flat ring on the ground |
25 |
A flat ring on the ground, thinner |
The complete list of types is on the FiveM documentation site, under game references, markers. The scale arguments change the size, and the last colour value is the alpha (transparency). Place a ground marker at z - 1.0 so it sits on the floor, not floating at the player's waist.
Help text: the built-in prompt
The game has a help message at the top left of the screen. You define a label, then display it every frame while the player is in range:
AddTextEntry('MY_SCRIPT_HELP', 'Press ~INPUT_CONTEXT~ to open the garage')
local function showHelp()
BeginTextCommandDisplayHelp('MY_SCRIPT_HELP')
EndTextCommandDisplayHelp(0, false, true, -1)
end~INPUT_CONTEXT~ is replaced by the key the player uses for the context action, which is E by default. Call showHelp() inside the distance < 1.5 branch above, then check the key:
if distance < 1.5 then
showHelp()
if IsControlJustReleased(0, 38) then
print('opened')
end
endRegister the label once at the top of the file, not inside the loop.
lib.showTextUI and lib.hideTextUI
With ox_lib you can show a styled prompt, and you call it once when the player enters, not every frame:
lib.showTextUI('[E] Open the garage', {
position = 'right-center',
icon = 'warehouse',
})
-- when the player leaves:
lib.hideTextUI()lib.isTextUIOpen() tells you if one is already on screen. It needs shared_script '@ox_lib/init.lua' in your manifest (see the ox_lib menu guide). The text is not bound to a key: you still check the key yourself, or use a keybind.
ox_lib points: no distance loop at all
Writing the distance loop by hand for each zone adds up. lib.points does it for you: ox_lib checks the player's distance to all points together, and only runs your code near them:
local point = lib.points.new({
coords = vec3(441.2, -981.9, 30.7),
distance = 15.0,
})
function point:onEnter()
lib.showTextUI('[E] Open the garage')
end
function point:onExit()
lib.hideTextUI()
end
function point:nearby()
DrawMarker(1, self.coords.x, self.coords.y, self.coords.z - 1.0,
0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 0.5,
50, 150, 255, 120, false, false, 2, false, nil, nil, false)
if self.currentDistance < 1.5 and IsControlJustReleased(0, 38) then
print('opened')
end
endHow it works:
onEnterruns once when the player comes withindistance.onExitruns once when they leave.nearbyruns every frame while they are insidedistance, and not at all otherwise. That is whereDrawMarkergoes.self.currentDistanceis the current distance to the point.
You can create hundreds of points and only the ones the player is near cost anything. Remove a point you no longer need with point:remove().
Which to use
- One or two zones: the distance loop with a sleep is fine.
- Many zones, or a script that creates zones from config: use
lib.points. - Interactions on objects and peds: a target is better than a marker. See ox_target: how to add targets.
Checklist
| Symptom | Fix |
|---|---|
| Marker flickers or shows for one frame | Call DrawMarker every frame in a Wait(0) loop |
| Script costs resmon time when idle | Sleep 500 to 1000 ms when far away, Wait(0) only when near |
| Marker floats in the air | Draw it at z - 1.0 |
| Prompt text never shows | Define it with AddTextEntry, then display it every frame |
lib.showTextUI stays on screen |
Call lib.hideTextUI() on exit |
| Many zones are slow | Use lib.points.new with onEnter, onExit and nearby |
Quick answers
Why does my marker disappear after one frame?
DrawMarker has to be called every frame, in a loop with Wait(0). Call it once and it shows for a single frame.
Why does my script use so much resmon time?
A Wait(0) loop that measures distance to every marker runs each frame all the time. Sleep longer when the player is far away, or use ox_lib points so the loop only runs near the zone.
Which is better, help text or lib.showTextUI?
Help text is built into the game and needs no resource. lib.showTextUI is a styled prompt from ox_lib and is easy to show and hide from code. Pick one style and keep it for your whole server.
Scripts that skip this problem
Advanced BoostingTablet-driven vehicle boosting: contracts from class D to S+, crews and a live queue.View script →
Shop CreatorBuild a shop in under a minute — owners, employees, vaults and robberies included.View script →
Quest CreatorA visual editor for quests and NPC dialogues, built node by node in game.View script →