Skip to content

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

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

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 readPed and saveSelf. 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. apply and encode are 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 way
custom = {
resource = "my_clothing",
paintFirst = true,
readPed = "GetPedAppearance",
saveSelf = "SaveAppearance",
},
-- when you know the shape
custom = {
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.

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.

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.

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 = true in illenium’s own shared/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",
},

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

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.