Commands#
Tattoo Creator registers a few in-game commands and two diagnostics. The in-game ones respect permissions; the diagnostics exist to explain what the script is seeing. The first three names are settings (Settings → Commands), and a renamed command takes effect after a restart.
Command | Who | Description |
|---|---|---|
| Admins | Opens the admin panel: studios, moderation, players and settings. |
Studio command | Admins | Off by default. Give it a name and it opens the studio anywhere, on your own character. |
| Artists | Invites the nearest player to the tattoo spot of the studio you are standing in — the keybind-friendly alternative to walking onto the spot. |
| Admins | Opens the placement tuning panel: where new designs land and where each quick spot sits. See Usage. |
| Console · admins | One block per studio: open or closed, level, owner, the tattoo spot, staff on shift, till, price level, commission, supplies — and a line listing what is stopping it from working. |
| Anyone, F8 | Walks the whole chain that shows tattoos on this client and ends with what is wrong, or nothing wrong on this client. |
tattoo_shop ends each studio with a line naming exactly what it is missing:
no studio area (nothing will spawn)no tattoo spot placedno owner (nobody can open the management menu)no staff with canTattoonobody clocked in (management menu -> clock in)no management point (falls back to the NPC)no supply point (deliveries cannot be collected)
Client Exports#
For opening the studio from your own scripts and for keeping tattoos on when your own code rebuilds a character.
The studio
exports['qs-tattoo-creator']:OpenStudio(shopId) -- open a studio's tattoo menu for this player
local open = exports['qs-tattoo-creator']:IsStudioOpen()The server still applies every check it would at the NPC: the studio must be open, self service on, and the player close enough.
The player's own tattoos
-- your script just cleared decorations or rebuilt the ped: put the tattoos back now
exports['qs-tattoo-creator']:ReapplyTattoos()
-- what this player is wearing
local tattoos = exports['qs-tattoo-creator']:GetOwnTattoos()Server Exports#
How another resource reads tattoos, manages a studio's staff and money, or runs a tattoo session at a place of its own. Body parts are named head, torso, left_arm, right_arm, left_leg and right_leg.
Tattoos
-- every body part of this player, with the tattoos on it
local zones = exports['qs-tattoo-creator']:GetPlayerTattoos(source)
-- clear one body part (a hospital, a prison intake, a skin graft)
local ok = exports['qs-tattoo-creator']:WipePlayerZone(source, 'left_arm')A wipe takes effect for everyone around the player immediately.
Studios, staff and money
local studios = exports['qs-tattoo-creator']:GetShops()
local staff = exports['qs-tattoo-creator']:GetShopWorkers(shopId)
local works = exports['qs-tattoo-creator']:IsShopWorker(source, shopId) -- shopId optional: any studio
local artist = exports['qs-tattoo-creator']:IsArtist(source) -- allowed to tattoo right now
-- hire straight onto a studio's staff; rankId optional, the lowest rank otherwise
local ok, err = exports['qs-tattoo-creator']:HireShopWorker(shopId, source, rankId)
local balance = exports['qs-tattoo-creator']:GetShopBalance(shopId)
-- move money in or out of a till; a negative amount withdraws, and only if the till holds it
local ok, newBalance = exports['qs-tattoo-creator']:AddShopMoney(shopId, -500, 'Health inspection fine')Every movement made through AddShopMoney appears in the studio's Activity tab as a deposit or an expense.
The catalog
local state = exports['qs-tattoo-creator']:GetPublishState()
-- publish the catalog now. Restarts qs-tattoo-data: empty server only
exports['qs-tattoo-creator']:ForcePublish('maintenance')Running a session at your own place
A beauty salon, a prison or a job script can run a full artist session at a chair of its own — same invitation, same live view, same ink — while keeping its own employment rules and its own money. Your resource decides the artist may work there, and receives the payment:
local result = exports['qs-tattoo-creator']:StartSession(artistSource, customerSource, {
resource = GetCurrentResourceName(), -- must be started: it receives the payment
id = stationId, -- your own id for this chair
label = 'Vanilla Unicorn Salon', -- shown to the customer in the invitation
multiplier = 1, -- price factor: 1 = the standard price list
})
if not result.ok then print(result.error) end
-- called once for each body part that is finished
exports('VenuePayout', function(id, artistSource, customerPid, total, meta)
-- the customer has already paid total. Pay the artist, keep the rest
local artistShare = math.floor(total * 0.30)
return artistShare, total - artistShare
end)
-- the session is over: free your chair
exports('VenueRelease', function(id, artistSource) end)A venue session skips the studio's own checks — staff list, duty, supplies — because your resource has already made those decisions. An optional chair with coords (and optional prop and label) gives the spot the customer is moved to when Move the customer is on. Use IsInSession(source) to refuse a second session for someone already in one.
State Bags and Events#
Name | Kind | What it is |
|---|---|---|
| Player state bag | The body parts a player wears ink on. It changes whenever a tattoo is bought, changed or removed — watch it with |
| Player state bag | true while the player may tattoo — on staff with the right to, and on shift when that is required. |
| Client event | Shows a notification in the tattoo interface's style: |
| Local client event | Fired whenever the client receives the server's settings — on join and after every save. |
About the Errors#
Every refusal is a locale key rather than a sentence — no_supplies, shop_closed, too_far — so the same failure reads in each player's own language. The keys live under errors in locales/*.json, and Common Errors explains the ones you are most likely to meet.



