7. Clothing and tattoo resources
Config.Appearance answers four separate questions, and the defaults answer all
four correctly on a normal server:
driver / resource |
Who dresses the character |
publish / tattooSync |
Where the appearance is written |
tattooResource / tattooKey |
Who owns the ink |
tattooCreator |
Whether the creator offers a TATTOOS step |
driver
Section titled “driver”What the character creator drives the ped with.
| Value | Behaviour |
|---|---|
"auto" |
skinchanger if it is running, the built-in driver otherwise. What you want |
"skinchanger" |
Force the ESX resource. Falls back to "native" with a warning |
"native" |
Always drive the ped directly. No dependency; works on every framework |
resource
Section titled “resource”Which clothing resource owns the ped once the character is in the world — and therefore who has to be handed the character when it is made.
illenium-appearance and qb-clothing keep their appearance in playerskins, which
publish writes directly. The rest keep it in tables of their own, so the
character is handed to them through their own API as it spawns.
"auto" detects it (what you want). "none" hands the character to nothing. Or
name one to settle it on a server running two:
| Value | Resource |
|---|---|
"rcore" |
rcore_clothing |
"bl" |
bl_appearance |
"illenium" |
illenium-appearance |
"fivem-appearance" |
fivem-appearance |
"tgiann" |
tgiann-clothing |
"crm" |
crm-appearance |
"qbclothing" |
qb-clothing |
"skinchanger" |
skinchanger / esx_skin |
custom — a clothing resource not on that list
Section titled “custom — a clothing resource not on that list”Describe it here in the same shape and it is used exactly like a built-in one, and
probed first. Everything except resource is optional; a missing export is
skipped, not guessed at.
Start with
readPedandsaveSelf. If your resource can read an appearance off a ped and save one, that pair is all you need and it is the most reliable option here.applyandencodeare for a resource whose data shape you know: getting that wrong either errors inside their setter or writes a character that is subtly wrong until a clothing shop saves it.
| Field | Notes |
|---|---|
resource |
Required. The resource folder name |
store |
Where it keeps an appearance: "self" (its own tables — the usual answer and the default), "illenium", "qbclothing" (the two playerskins shapes), "skinchanger" (ESX’s users.skin) |
paintFirst |
true to paint the ped with this resource’s driver instead of sending yours a blob. Set it whenever you are unsure of the data shape |
readPed |
Client export, called as (ped), returning that resource’s own appearance shape |
saveSelf |
Client export that persists what readPed returned |
saveTakes |
"blob" when saveSelf wants that value (default), or "none" when it saves what it can already see |
apply |
Client export, called as (ped, appearance) |
applySelf |
Client export for the local player, called as (appearance) |
applyEvent |
Client event raised instead, when it has no export |
encode |
The shape those three want: "illenium" (default), "qbclothing", "skin" (flat skinchanger table) or "bl" |
tattoos |
Client export, called as (ped, zonesTable), filling its worn-tattoo cache. Without it, the first clothing shop saves an empty tattoo list over the ink |
save |
Client event raised once the ped is dressed, for a resource that saves what it can see |
reapply |
Client events it fires when it repaints the ped, as a list. Each is a cue to put the character back on top |
decorations |
Client event asking it to redraw its own decorations |
serverSave |
Server export, called as (charKey, appearance) |
serverGet |
Server export, called as (charKey) |
serverSaveTattoos |
Server export, (charKey, tattoos), only when serverSave does not carry decorations itself |
-- the read-back waycustom = { resource = "my_clothing", paintFirst = true, readPed = "GetPedAppearance", saveSelf = "SaveAppearance",},
-- when you know the shapecustom = { resource = "my_clothing", store = "self", encode = "illenium", apply = "setPedAppearance", tattoos = "setPedTattoos", save = "my_clothing:saveSkin", reapply = { "my_clothing:skinReloaded" },},A list of these tables handles several resources.
publish
Section titled “publish”Should a character created here also be written into playerskins, so clothes
shops and barbers know what it looks like?
QBCore and Qbox only — ESX keeps the appearance in users.skin, which is
already the shape every ESX shop reads.
| Value | Behaviour |
|---|---|
"auto" |
illenium format when illenium/fivem-appearance is running, qb-clothing format when qb-clothing is, nothing when neither |
"illenium" |
Force the illenium / fivem-appearance shape |
"qbclothing" |
Force the qb-clothing shape |
"always" |
Write something even if nothing recognised is running (illenium shape) |
"never" |
Keep the appearance to ourselves |
The two playerskins shapes are not interchangeable — qb-clothing indexes
data['face'].item on load and errors outright on an illenium-shaped row. Leave
this on "auto" unless you know better.
On QB/Qbox, publishing is only half the job. See “QBCore and Qbox: turn off the other creator” in README.md before reporting clothing or tattoos as not saving.
tattooSync
Section titled “tattooSync”Who owns a character’s tattoos once the character exists.
There are two copies: this resource’s own (the selection line-up has to draw a character nobody is logged in as) and the clothing resource’s, which is what the world reads and a tattoo shop writes. They agree at creation and then drift.
The client hands the worn-tattoo list to the clothing resource on every spawn, which is what stops a shop deleting the ink. This setting is about the two stored copies:
| Value | Behaviour |
|---|---|
"auto" |
Ink in the clothing resource’s row wins, since a tattoo shop is the only thing that writes it — and a row with no ink at all is repaired from here. Repairs touch the tattoos only; the clothes in the row are left alone. What you want |
"creator" |
This resource’s copy always wins and is republished on every login. Tattoo shops stop sticking |
"off" |
Never touch the clothing resource’s row after creation |
Ignored on qb-clothing, which has nowhere to keep a decoration, and on an ESX
server whose users.skin is a skinchanger table.
tattooResource
Section titled “tattooResource”Which dedicated tattoo resource owns a character’s ink. These take ownership of ped decorations — they clear the ped and redraw from their own store — so ink written into the clothing resource’s record is ink nothing reads. Detect one and this resource stops writing there, asks that resource to redraw instead, and tells it when the player changes character.
"auto" detects it (what you want). "none" means the clothing resource keeps
the ink. Or name one:
| Value | Resource |
|---|---|
"rcore" |
rcore_tattoos |
"vms" |
vms_tattooshop |
"crm" |
crm-tattoos |
"qbtattooshop" |
qb-tattooshop |
"esxtattooshop" |
esx_tattooshop |
rcore_tattoos with illenium-appearance: set
Config.RCoreTattoosCompatibility = truein illenium’s ownshared/config.lua. Without it both manage decorations, which is what “my tattoos flicker” is. This resource reads that flag at boot and says so in the console.
tattooCustom — a tattoo resource not on that list
Section titled “tattooCustom — a tattoo resource not on that list”Same idea as custom, and much smaller: nothing here ever builds a tattoo list, so
there is no data format to get right. Every field is a name to call.
| Field | Notes |
|---|---|
resource |
Required. The resource folder name |
owns |
true when it clears and redraws ped decorations itself. Set it if in any doubt — it is what stops this resource painting over yours |
identity |
"character" when its store is keyed per character, "account" when per licence. Default "unknown", treated as "account" |
reassert |
Client event that redraws the player’s ink. The important one — called after every repaint that would have wiped it |
reassertExport |
Client export doing the same, used first when both exist |
reassertKeep |
true when reassert takes a “do not clear first” boolean. Always sent as false |
switched |
A server event fired once a character is live, asking it to load that character’s ink. This is what stops character two wearing character one’s tattoos |
paintPed |
Client event, (ped, list, noClear), drawing a list onto any ped. Only useful with read |
paintPedExport |
Client export, (ped, list), for the same |
read |
Server event, (charKey, cb), handing back that resource’s list for one character. Paired with paintPed it puts each character’s real ink on their line-up ped |
readExport |
Server export, (charKey), returning the same |
The list read hands back is never inspected — it goes straight to paintPed, so
the two only have to agree with each other.
tattooCustom = { resource = "my_tattoos", owns = true, identity = "character", reassertExport = "reapply", switched = "my_tattoos:reload",},tattooKey
Section titled “tattooKey”Which key your tattoo resource files a character’s ink under. Only read when one is running, and only to draw the selection line-up.
| Value | Behaviour |
|---|---|
"auto" |
The character key — char2:licence on ESX, a citizenid elsewhere. Correct for any tattoo resource whose own multicharacter step has been done. What you want |
"account" |
The account identifier. Correct only where that step has not been done |
"off" |
Do not read it. The line-up draws from this resource’s own copy |
tattooCreator
Section titled “tattooCreator”Should the creator offer its own TATTOOS step?
| Value | Behaviour |
|---|---|
"auto" |
Only when no tattoo resource owns the ink. What you want |
"on" |
Always — see the warning below |
"off" |
Never |
On "on" with a tattoo resource running, ink chosen in the creator is drawn once
and then removed by that resource’s first repaint, and its shop cannot see it — so
the player cannot take it off there either.
