Skip to main content
TRACK B·BUILD REAL PRODUCTS·Verified June 2026 · Lua 5.4 · ox_lib 3.x
Learning with an AI assistant?
Copies this lesson plus 2026 ground rules (no lua54 'yes', Cfx.re Portal, correct callback signatures) as a ready-to-paste mentor prompt.

Draw on screen: text, 3D text, and markers

Markers and floating text are not objects you place once. They are painted fresh on every single frame, inside a loop that runs at your framerate. That is powerful and it is expensive, so the real skill is not the draw call, it is the distance check that stops you from drawing when nobody is looking. This lesson builds both halves at once.

You'll build
qu_draw: a render-loop resource that drops a marker on the ground and floats a label above it, drawn every frame but only when you are close.
Time
~26 minutes
You need
CreateThread and Wait and natives (so you already know how to read your own coords).
You'll learn
DrawMarker -> DrawText3D (SetDrawOrigin + DrawText) -> why drawing lives in a Wait(0) loop -> the distance gate that makes it cost nothing when far away.
BEFORE YOU START

Build it

Make the resource folder

The server has one folder for this lesson.

Inside your server's resources folder, create this folder:

code
resources/qu_draw

Create the files

Every file named in the manifest exists.

Create this exact file layout. There is no server file. Drawing only happens on the client, because only a client has a screen.

code
resources/qu_draw/
fxmanifest.lua
client.lua

Write fxmanifest.lua

FiveM knows which file to load.

Open fxmanifest.lua and paste this:

code
fx_version 'cerulean'
game 'gta5'

client_script 'client.lua'

Older tutorials add a lua54 'yes' line here. As of June 2025 that setting is deprecated and ignored: Lua 5.4 is now the only Lua runtime, so you leave it out.

Write the DrawText3D helper

You have one reusable function that floats a label at a world point.

Open client.lua and paste this helper at the top of the file. It is the part everyone copies wrong, so type it once and keep it forever:

code
-- Floats a text label at a world coordinate (not a fixed screen spot).
-- SetDrawOrigin anchors the next 2D draw call to a 3D point in the world,
-- so DrawText, which is normally a screen native, ends up over that point.
local function DrawText3D(x, y, z, text)
SetTextScale(0.35, 0.35)
SetTextFont(4)
SetTextColour(255, 255, 255, 215)
SetTextEntry('STRING')
SetTextCentre(true)
AddTextComponentString(text)
SetDrawOrigin(x, y, z, 0)
DrawText(0.0, 0.0)        -- 0,0 means "at the draw origin we just set"
ClearDrawOrigin()         -- always clear, or every later draw call inherits it
end

Write the gated render loop

The marker and label draw every frame, but only when you are near.

Below the helper, paste the render thread. Read the distance check first, because it is the reason this script is cheap:

code
-- The fixed world point we decorate. Near the Legion Square parking lot.
local point = vector3(215.0, -810.0, 30.7)
local DRAW_RADIUS = 20.0   -- only draw when the player is within this many metres

CreateThread(function()
while true do
    local ped = PlayerPedId()
    local pos = GetEntityCoords(ped)
    local dist = #(pos - point)   -- straight-line distance in metres

    if dist < DRAW_RADIUS then
        -- Close enough to see it: draw this frame, so yield only one frame.
        DrawMarker(
            1,                       -- type 1: a vertical cylinder
            point.x, point.y, point.z - 1.0,  -- sink it so the disc sits on the ground
            0.0, 0.0, 0.0,           -- direction (unused for this type)
            0.0, 0.0, 0.0,           -- rotation
            2.0, 2.0, 1.0,           -- scale x, y, z
            0, 200, 120, 120,        -- colour r, g, b, alpha
            false, false, 2,         -- bobbing, faceCamera, rotationOrder
            false, nil, nil, false    -- rotate, textureDict, textureName, drawOnEnts
        )
        DrawText3D(point.x, point.y, point.z + 0.4, 'qu_draw checkpoint')
        Wait(0)                      -- next frame, because we are drawing
    else
        -- Too far to see it: draw nothing and sleep, so this thread costs ~0.
        Wait(500)
    end
end
end)

Start and test it

The marker and label appear, and disappear when you walk away.

Open server.cfg and add this line:

code
ensure qu_draw

Save, then run:

code
restart qu_draw

Join the server. Teleport or walk to the point. With the console open you can run /tp 215 -810 30 if you have a teleport command, or just spawn near Legion Square and head to the parking lot.

There is no console line for this lesson, because drawing happens on your screen, not in a log. The proof is visual: the marker is there when you are close and gone when you are far. That on/off behaviour is the distance gate working, and it is the whole point of the lesson.

txAdmin · Live ConsoleStep inside the radius
> > resmon (in F8, watch qu_draw)
qu_draw 0.08 ms drawing every frame

Keep reading the full lesson

Sign in to start, then unlock every step of this lesson and the full FiveM School with a membership.

Still ahead in this lesson
  • How it works
  • If something went wrong
  • What you can do now
  • Try it yourself

The remainder of Draw on screen: text, 3D text, and markers is available to FiveM School members.