cc_lib.TaskUI is the on-screen task list that every CC Scripts heist uses to show its objectives. Lists are owned server-side: state lives on the server, viewers (players) subscribe via Show, and updates broadcast to every viewer.
Create only allocates the list and starts its master timer. Players don’t see anything until Show adds them as viewers.
Concepts
Server-owned state
Every list and every objective lives on the server. Clients only receive deltas. On respawn the client requests a full re-sync automatically.
One active task
The list renders the first non-
complete objective as the active task. Counter chips and timer chips are only visible on the active task — they’re hidden on pending/complete/failed tasks even if their underlying value is non-null.Per-task chips
Each task can carry a counter (
{ current, total }) and/or a timer ({ timeLeft }). Both render as small chips next to the task text. Counters and timers are independent — a task can have one, both, or neither.Boundaries are caller-defined
Expiry callbacks fire but don’t auto-fail the task. Status, counter, and timer are all orthogonal — what they mean for the heist’s flow is up to you.
Lifecycle
Create accepts:
Objective shape
status is rarely set on the initial list — it defaults to pending and the renderer promotes the first pending one to active automatically.
Master timer
The list-level countdown drawn in the header.
The master timer ticks at 1 Hz on the server. When it hits 0 the
onTimerEnd callback fires once and the timer stops — the list itself remains until you Destroy it.
Task status
'complete' fires onTaskComplete(listId, taskId). Setting 'complete' on the last remaining objective also triggers onComplete once.
Counter chip
A small numeric badge next to a task. Useful for “hack 4 computers” or “grab 6 bags” objectives.current <= 0, regardless of total. Pair with SetStatus(id, taskId, 'complete') to advance to the next task.
Per-task timer chip
AMM:SS countdown badge next to a task. The chip styling matches the counter chip — neutral background, no traffic-light coloring — so timers and counters sit side by side cleanly.
A per-task timer is only visible while its task is the active one, the same way the counter chip is gated. The server ticks it regardless, so start the timer at the moment the task becomes active if you want the player to see the full countdown.
API
0 or a negative number to SetTaskTimer is treated as a clear and behaves like ClearTaskTimer. Calling SetTaskTimer while a timer is already running atomically replaces it — the previous ticker thread exits via a generation token.
Freezing
A running timer can be paused without clearing it. While frozen, the chip stays in place at its current value, turns red, and slowly flashes — a visual cue that the countdown is on hold (e.g. the player triggered a checkpoint, started a sub-objective, or hit a forgiving state).false. Setting the same frozen state twice in a row is a no-op (no extra broadcast).
You can also start a timer in the frozen state by passing timer = { timeLeft = 25, frozen = true } to Create or AddTask — useful when the chip should appear immediately but only start counting once an in-world trigger fires.
Expiry behavior
When the chip ticks down to0:
- The chip disappears (broadcast as
timer = nil). onTaskTimerEnd(listId, taskId)fires once on the server.- The task’s
statusis not auto-changed. Decide what expiry means in the callback.
Worked example: time-pressured vault
A vault objective where the player has 25 seconds from the moment the task becomes active. Late = fail.SetTaskTimer is called, ticks down at 1 Hz, and vanishes either on ClearTaskTimer or on its own expiry (which also fires onTaskTimerEnd).
Dynamic objectives
AddTask appends a new objective at runtime — useful for bonus/side objectives that only appear if the player triggers them. The new objective can carry an initial counter and/or timer.
RemoveTask — once added, a task is part of the list until the list is destroyed. Mark it complete or failed to neutralize it.
API reference
List
Tasks
Counter chip
Master timer
Per-task timer
Every function above is also reachable via
exports.cc_lib:TaskUI_<Name>(...) — for example exports.cc_lib:TaskUI_SetTaskTimer(id, taskId, 25). Prefer the GetLib() form for readability; use the export form when you need to invoke from a context where holding a reference to cc.TaskUI is awkward.
Player keybind
The TaskUI registers+taskui_toggle (default key K) on every client — pressing it collapses/expands every list that player can see. The keybind is registered automatically by cc_lib; you don’t need to wire anything up.