Skip to content

Progress Bar

Timer progress bar — the timer runs NUI-side without Lua polling. Supports ped animation, attached prop and per-tick callback.

3 min read

One-shot

exports.LastMenu:progress(function(p)
    p:label("Loading data…")
    p:duration(5000)
    p:cancelable(true)   -- show cancel button and allow Escape
    p:confirm(function()
        -- fires when the bar fills naturally (completion)
    end)
    p:cancel(function()
        -- fires when the player cancels (only if cancelable = true)
    end)
end)

Reusable bar

local bar = exports.LastMenu:progress_build(function(p)
    p:label("Manufacturing in progress…")
    p:duration(8000)
    p:cancelable(false)  -- mandatory action; player cannot cancel
    p:confirm(function() giveCraftedItem() end)
end)

bar.open()    -- start
bar.close()   -- interrupt programmatically (does NOT fire confirm or cancel)

Builder methods

MethodArgsDescription
p:label(str)stringText displayed above the bar
p:duration(ms)numberTotal duration in milliseconds
p:cancelable(bool)boolAllow cancel button + Escape (default: false)
p:icon(str)stringLucide icon shown next to the label
p:confirm(cb)function()Called when the bar fills naturally — completion callback
p:cancel(cb)function()Called when the player cancels — cancellation callback
p:cb_tick(cb)function(pct)Called every ~100ms with current percentage 0–100
p:anim(opts)tablePlay a ped animation for the full duration (see below)
p:prop(opts)tableAttach a prop to the player ped for the full duration (see below)

Naming note: p:confirm(cb) is the completion callback (bar fills → done). p:cancel(cb) is called when the player cancels the action. p:cancelable(bool) controls whether cancellation is allowed.


Position

Configurable in User Settings (F12):

PresetLocation
bottom-centerDefault — HUD bar style
top-centerTop of screen
bottom-leftBottom-left corner
bottom-rightBottom-right corner

Side effects

p:icon(str) — label icon

Any Lucide icon shown inline with the label text:

p:label("Repairing engine…")
p:icon("wrench")

p:cb_tick — per-interval progress

Called every ~100ms. Useful for partial rewards, sounds, or server sync:

local halfway = false

p:cb_tick(function(pct)
    if pct >= 50 and not halfway then
        halfway = true
        TriggerServerEvent("craft:halfwayDone")
        PlaySoundFrontend(-1, "CHECKPOINT_NORMAL", "HUD_MINI_GAME_SOUNDSET", true)
    end
end)

p:anim — ped animation

Plays an animation for the full duration. Automatically cleared on complete, cancel, or programmatic close:

p:anim({
    dict  = "amb@world_human_welding@male@base",
    clip  = "base",
    flag  = 1,    -- AnimationFlag: 1 = loop, 49 = loop + upperbody only
})
FieldTypeDescription
dictstringAnimation dictionary name
clipstringClip name inside the dictionary
flagnumberAnimationFlag bitmask (default: 49)

p:prop — attached object

Attaches a prop to the player ped. Automatically detached and deleted on complete, cancel, or programmatic close:

p:prop({
    model  = "prop_tool_torch",
    bone   = 57005,                     -- ped bone index (57005 = right hand)
    offset = vector3(0.12, 0.03, 0.0),
    rot    = vector3(0.0,  0.0,  0.0),
})
FieldTypeDescription
modelstring\|numberModel name or hash
bonenumber\|stringBone index or bone name (resolved via GetEntityBoneIndexByName)
offsetvector3Position offset relative to the bone
rotvector3Rotation offset (Euler angles)

Complete example — Welding

exports.LastMenu:progress(function(p)
    p:label("Welding…")
    p:icon("zap")
    p:duration(8000)
    p:cancelable(true)

    p:anim({
        dict = "amb@world_human_welding@male@base",
        clip = "base",
        flag = 1,
    })

    p:prop({
        model  = "prop_tool_torch",
        bone   = 57005,
        offset = vector3(0.12, 0.03, 0.0),
        rot    = vector3(0.0,  0.0,  0.0),
    })

    p:cb_tick(function(pct)
        if pct % 25 < 1 then
            PlaySoundFrontend(-1, "CHECKPOINT_NORMAL", "HUD_MINI_GAME_SOUNDSET", true)
        end
    end)

    p:confirm(function() giveCraftedItem() end)
    p:cancel(function()  notifyWarn("Welding cancelled.") end)
end)

Behavior

  • While a progress bar is open it owns the stack — other menus cannot open until it finishes or is cancelled.
  • Use cancelable(false) for mandatory actions (crafting, mission interactions). Use cancelable(true) for player-interruptible tasks (lockpicking, hacking).
  • bar.close() interrupts the bar silently — neither p:confirm() nor p:cancel() fires.
  • Both anim and prop side effects are cleaned up automatically regardless of how the bar closes.