Commands#
Tutorial Creator registers three in-game commands, two of which also work from the server console with a player id. Every name can be changed in shared/config.lua.
Command | Where | Description |
|---|---|---|
| In game | Plays the live tutorial now, whether or not you have seen it. Typed again while it plays, it stops it. |
| In game | Forgets every tutorial you have watched, so the next spawn plays it again. |
| In game · staff | Opens the creator, or closes it if it is open. |
| Console | Plays a tutorial for that player — the live one if no tutorial id is given — whether or not they have seen it. |
| Console | Forgets that player's progress on one tutorial, or on all of them, and tells them. |
<id> is the player's server id. The tutorial id is shown in the creator under Settings → Tutorial id and in the </> panel; the bundled ones are welcome, spotlight, skyline, anthem, broadcast, noir, neon and dispatch.
custom/client.luaalso ships/tutorialbroadcastas an example of a command bound to one tutorial: it plays Broadcast only if the player has not watched it yet. Copy it for your own, or delete it.
Client Exports#
For starting the tutorial from your own scripts — a multicharacter, a spawn selector, a job, an NPC at the airport. Where an id is optional, leaving it out means the live tutorial. The creator's </> panel prints every line below with the current tutorial's id already filled in.
Starting and stopping
-- Blocks until it ends and returns true if it was completed.
-- Returns false at once if this character has already watched it.
local completed = exports['qs-tutorial']:StartTutorial(id)
-- The same, but plays even if they have watched it.
local completed = exports['qs-tutorial']:ForceTutorial(id)
exports['qs-tutorial']:StopTutorial() -- ends it without counting it as watched
exports['qs-tutorial']:IsPlaying() -- true while it is on screenStartTutorial re-reads the character's progress first, so it is safe to call after every spawn and every character switch.
Progress
exports['qs-tutorial']:ShouldPlay(id) -- true if this character still needs to watch it
exports['qs-tutorial']:HasCompleted(id) -- true if they finished it
exports['qs-tutorial']:GetProgress() -- { [tutorialId] = { step = 3, completed = false }, ... }Spawn and multicharacter
exports['qs-tutorial']:SetSpawnBusy(true) -- a character or spawn screen opened; auto-start waits
exports['qs-tutorial']:SetSpawnBusy(false) -- they picked a location; auto-start may run
exports['qs-tutorial']:IsSpawnBusy()
exports['qs-tutorial']:AwaitIdle() -- blocks while the tutorial is on screenSee Integrations → Character and Spawn Screens for where each call goes.
The creator
exports['qs-tutorial']:OpenCreator() -- same as /tutorialcreator, permission includedServer Exports#
For a server script that decides who sees what — a job hire, an admin panel, a welcome reward.
The live tutorial
exports['qs-tutorial']:GetActiveTutorial() -- the live tutorial's id, or nil
exports['qs-tutorial']:GetTutorials() -- every tutorial, bundled and saved, sorted by name
exports['qs-tutorial']:SetActiveTutorial(id) -- make it live for everyone; true on successSetActiveTutorial does not check that the id exists — pass one from GetTutorials.
Playing it for a player
-- Always plays it. Does not block.
exports['qs-tutorial']:StartTutorial(source, id)
-- Plays it only if they have not watched it: the false at the end respects progress.
TriggerClientEvent('qs-tutorial:client:start', source, id, false)Progress
exports['qs-tutorial']:HasCompleted(source, id) -- read from the database
exports['qs-tutorial']:GetProgress(source) -- { [tutorialId] = { step, completed } }
exports['qs-tutorial']:ResetProgress(source, id) -- leave id out to forget every tutorialEvents#
Event | Side | Fired |
|---|---|---|
| Client | When a tutorial opens. |
| Client | When it closes; |
| Server | Each time a player finishes or skips a tutorial, after the completion is saved — replays included, so keep your own record before handing out a one-time reward. |
| Client, you send it | Starts a tutorial. |
Client event on enter | Client | Your own event name, set per step under Flow. |
Client event when it ends | Client | Your own event name, set in the Settings tab. Only when the tutorial is completed. |
Examples#
Brief a new officer with Dispatch#
Dispatch is built to be fired from a job script. Call this on the server wherever your job script hires somebody into the police:
TriggerClientEvent('qs-tutorial:client:start', source, 'dispatch', true)A starter kit after the tour#
-- server
local rewarded = {}
AddEventHandler('qs-tutorial:server:completed', function(src, id)
if id ~= 'welcome' or rewarded[src] then return end
rewarded[src] = true
-- give the starter money or items with your framework here
end)For a reward that must survive restarts, keep your own record in the database: the event also fires when a player replays the tutorial with /tutorial.



