ATY Scripts Logo
ATY Scripts/Docs/Clothing/Integrations

Integrations

Integrations

Everything another resource needs to work with ATY Clothing: exports, menu types and category keys, events, and the qb-clothing, esx_skin and skinchanger events it answers. Exports are called as exports['aty_clothing']:Name(...).

Client exports

Export Returns What it does
OpenCustomMenu(menuType, categories, title, shopId) — Opens a menu with your own category list
OpenWardrobeMenu(title) — Saved outfits only
OpenClothingShop(title, shopId) — A clothing shop with Apparel
OpenBarberShop(title, shopId) — A barber with hair, overlays and the face
OpenTattooShop(title, shopId) — A tattoo parlour
CloseMenu(restoreSkin) — Closes the menu
IsMenuOpen() boolean Whether the menu is open
ResetPedAppearance() boolean Discards unsaved changes
GetPedSkinData() table or nil The player's current skin
ApplySkinData(skinData) — Applies a skin to the player's ped
GetNearbyInteraction() table or nil The shop the player is standing at

OpenCustomMenu

Parameter Default Notes
menuType "creator" creator, clothing, market, barber or tattoo — see Menu types
categories The type's default list Category keys, "category:part" entries or pre-v3 keys
title "Character Customization" Header text. The creator always shows its own heading
shopId "custom_api" Handed to menuOpened. Prices and shop balances ignore it — the server works out the shop from where the player stands
-- A barber that also does facial features
exports['aty_clothing']:OpenCustomMenu("barber", { "hair", "overlays", "faceAdjust" }, "Downtown Barber", "barber_downtown")

-- A jewellery counter: one Apparel shelf
exports['aty_clothing']:OpenCustomMenu("market", { "apparel:handWrist" }, "Vangelico", "jewellery_1")

Calling any open export while a menu is already open does nothing.

Shop shortcuts

Export Type Categories Default title
OpenWardrobeMenu(title) clothing wardrobe Wardrobe
OpenClothingShop(title, shopId) clothing apparel Clothing Store
OpenBarberShop(title, shopId) barber hair, overlays, faceAdjust, faceBody Barber Shop
OpenTattooShop(title, shopId) tattoo tattoos Tattoo Studio

CloseMenu and ResetPedAppearance

CloseMenu(true) puts the model and look back to how they were when the menu opened. CloseMenu(false) closes and leaves the ped as it is, previewed pieces included. Nothing is saved either way — /refreshskin or a reconnect brings back the saved look.

ResetPedAppearance() puts back the look the menu opened with and reloads the saved skin. It returns false when there is nothing to go back to. Use it while the menu is open: the ped is frozen again three seconds later.

GetPedSkinData and ApplySkinData

GetPedSkinData() returns the skin table plus two things the menu uses: maxValues (the highest valid value of each key for this ped) and tattoo_<zone>_overlay keys. Face and heritage values come from the character's saved data when the framework holds it, otherwise from the ped.

ApplySkinData(skinData) applies a skin to the current model — it never switches model — and redraws tattoos when the table has tattoos. To switch model as well, use setPedSkin below or the server export LoadPlayerSkin.

GetNearbyInteraction

local here = exports['aty_clothing']:GetNearbyInteraction()
-- { active = true, kind = "shop", shopType = "clothing", shopId = 3,
--   title = "Clothing Shop", coords = vector3(...) }

kind is "shop" or "jobshop"; nil when the player is not at a shop. Wardrobes are announced only through the nearInteraction event. Neither is tracked with Config.DisplayMethod = "target", where the target resource handles proximity.

Lower-level client exports

Export Returns What it does
OpenClothingMenu(menuType, shopData) — What the open exports call. shopData = { title, allowedCategories, shopId }
CloseClothingMenu(restoreSkin) — Same as CloseMenu
ResetPed() boolean Same as ResetPedAppearance
getPedSkin(ped) table or nil GetPedSkinData for any ped
setPedSkin(ped, skin, changeModel) boolean Applies a full skin; switches model unless changeModel is false
getMaxValues(ped) table or nil Highest valid value of each key for that ped
getPedClothingOnly(ped) table Clothing and prop keys only — what the wardrobe stores
setPedClothingOnly(ped, clothing) boolean Applies clothing and prop keys; face, hair and tattoos stay
loadPlayerClothing(skinData, ped) — Applies a skin to a ped (the player's by default) without switching model
setPedComponent(data) boolean Applies one key, e.g. { name = "torso_1", value = 4 }, to the player's ped. Used by the menu

ResetCameraFocus, RotatePed, RotatePedMouse, SmoothFocusCamera, FocusOnPoint, FocusAnchor, GetCameraState and StartHotspotTracking drive the menu's preview camera and only have an effect while the menu is open.

Server exports

Export Returns What it does
OpenClothingMenu(source, menuType, shopData) — Opens a menu on that player
CloseClothingMenu(source, restoreSkin) — Closes it and restores the look — see below
LoadPlayerSkin(source) boolean Applies the saved skin to the player's ped
GetPlayerSkin(source, cb) — cb(skinData, model) from the database
SavePlayerSkin(source, skinData) boolean Replaces the saved skin
GetPlayerOutfits(source, cb) — cb(outfits) from the wardrobe

OpenClothingMenu takes the same menuType (default "creator") and the same shopData fields as the client export: title, allowedCategories, shopId.

Call `CloseClothingMenu` with `restoreSkin = true`. The menu then closes about a second later and the ped goes back to how it looked when the menu opened. With `false` or no second argument the menu stays open. To close without restoring, use the client export `CloseMenu(false)`.

LoadPlayerSkin reads the active playerskins row (QBCore) or users.skin (ESX) and applies it on the client, switching model when needed. It returns false when the player has no loaded character; the database read happens after it returns.

exports['aty_clothing']:GetPlayerSkin(source, function(skinData, model)
    if not skinData then return end -- nothing saved
    print(model, json.encode(skinData))
end)

SavePlayerSkin replaces the stored skin — on QBCore it becomes the active playerskins row for its model, on ESX it overwrites users.skin. The model comes from model, then ped, then sex. It returns true once the write is queued, not when it has finished, and it does not touch the ped: call LoadPlayerSkin to show the result.

exports['aty_clothing']:GetPlayerOutfits(source, function(outfits)
    for _, outfit in ipairs(outfits) do
        local clothes = json.decode(outfit.skin) -- clothing and prop keys
        print(outfit.outfitId, outfit.outfitname, outfit.model)
    end
end)

Each row is a player_outfits record: id, citizenid, outfitname, model, skin (JSON), outfitId and created_at.

Menu types

Type Default categories Checkout
creator pedSelector, faceBody, faceAdjust, overlays, hair, apparel, tattoos Save Character — free unless the player is within 30 m of a shop
clothing wardrobe, apparel, hair, overlays Purchase
market apparel Purchase
barber hair, overlays Purchase
tattoo tattoos Purchase

The defaults apply when an export or /skin passes no list. Shops placed in config.lua use Config.ShopCategories for their shopType. A purchase charges only for changed clothing slots — see Prices.

Category keys and parts

"category:part" offers one group of a category. Several parts of the same category add up, and a bare "category" in the same list wins over any narrowing.

Key Contains Parts
pedSelector Model list; dropped when Config.PedSelector.Enabled = false —
faceBody Sex, character presets, heritage, skin tone, eye colour sex, presets, heritage, skin, eyecolor
faceAdjust Face shape nose, brow, cheeks, eyes, lips, jaw, chin, neck
overlays Skin and makeup overlays blemishes, ageing, makeup, blush, complexion, sundamage, lipstick, moles, bodyblemishes, addbodyblemishes
hair Hair and its colour, eyebrows, beard, chest hair hairs, eyebrows, beard, chest
apparel Five shelves of clothing and accessories A shelf or a group — see below
tattoos Six zones tattooHead, tattooTorso, tattooLeftArm, tattooRightArm, tattooLeftLeg, tattooRightLeg
wardrobe Saved outfits —
Apparel shelf Groups on it
outfits outfitsCasual, outfitsWork, outfitsActivity
clothing torso, tshirt, decals, arms, pants, shoes
upperBody chains, bproof, bags
handWrist watches, bracelets
head helmet, glasses, ears, mask

A Config.Slots menu is the group slot_<key> (for example slot_gloves) on the shelf its section names.

{ "hair:beard" }                                      -- beard trimmer
{ "apparel:handWrist", "apparel:head" }               -- accessories counter
{ "tattoos:tattooLeftArm", "tattoos:tattooRightArm" } -- arm work only

Pre-v3 keys

Keys from before v3 still work, in config and in exports:

Old key Opens
dna faceBody, faceAdjust
face faceAdjust
hairs hair, overlays
clothes, accessories apparel
tattoo tattoos
headTattoo tattoos:tattooHead
bodyTattoo tattoos:tattooTorso
armsTattoo tattoos:tattooLeftArm, tattoos:tattooRightArm
legsTattoo tattoos:tattooLeftLeg, tattoos:tattooRightLeg

The old tattoo tabs keep their exact zones, so a parlour set up to sell only head tattoos does not start selling leg tattoos.

Events and hooks

Local client events, for AddEventHandler:

Event Arguments When
aty_clothing:client:menuOpened menuType, shopData The menu opens
aty_clothing:client:menuClosed menuType The menu starts closing
aty_clothing:client:nearInteraction data The player enters or leaves a shop or wardrobe

nearInteraction sends { active = false } on leaving. On entering, data.kind is "shop", "jobshop", "wardrobe" or "jobwardrobe"; shops add shopType and shopId, wardrobes wardrobeId, and both carry title and coords. It fires on changes only, and not with Config.DisplayMethod = "target".

After a creator save is stored, the server also sends aty_clothing:client:characterSaved with the saved skin. It is a network event: register it with RegisterNetEvent to listen.

Without writing a resource, the same moments are reachable from config.lua. A hook that errors is caught and printed, and cannot break the menu:

Config.Hooks = {
    OnMenuOpen = function(menuType, shopData) --[[ e.g. hide your HUD ]] end,
    OnMenuClose = function(menuType) --[[ e.g. show it again ]] end,
}

Compatibility with other clothing resources

ATY Clothing answers the events below. It does not stand in for another resource's exports (the manifest provides none), so code that calls another clothing resource's exports has to move to the exports on this page. Events that are not listed, such as skinchanger:getSkin or qb-clothing:client:openMenu, are not handled.

qb-clothing

Active while Config.QBClothingEvents.Enabled = true. Only Enabled is read; the Events list beside it changes nothing.

Event Side What happens
qb-clothes:client:CreateFirstCharacter Client Sets the freemode model for the character's gender and opens the creator
qb-clothing:client:loadPlayerClothing (data, ped) Client Applies a skin table to a ped — multicharacter previews
qb-clothes:loadSkin (_, model, data) Client Sets the model (a hash) and applies the skin (JSON)
qb-clothing:saveSkin (model, skin) Server Saves the skin (JSON) as the active playerskins row. QBCore only
qb-clothes:loadPlayerSkin, qb-clothing:loadPlayerSkin Server Loads the saved skin onto the player. QBCore only
qb-clothes:saveOutfit (name, model, skinData) Server Passed to the wardrobe's own save
qb-clothing:server:removeOutfit (name, outfitId) Server Passed to the wardrobe's own delete
qb-clothing:server:getOutfits Server callback Returns the player's outfits

esx_skin and skinchanger

Active with Config.Framework = "esx".

Event What happens
skinchanger:loadSkin (skin, cb) Applies the skin, then calls cb
esx_skin:openSaveableMenu Sets the freemode model for the player's sex and opens the creator. It does not call the save callback it is given
esx:playerLoaded (playerData, isNew, skin) Applies skin for a returning character. With Config.Multicharacter = false it loads the saved skin itself

When the creator saves on ESX, the client fires skinchanger:loadSkin and esx_skin:characterSaved for freemode models. With Config.TriggerPlayerLoadedOnCreation = true the framework's player-loaded events fire as well, on QBCore and ESX; the server-side one only once per connection.

Examples

Multicharacter: a new character

-- Client
local creating = false

-- Your multicharacter has just created a character
RegisterNetEvent('my_multicharacter:client:newCharacter', function(gender)
    local model = gender == 1 and `mp_f_freemode_01` or `mp_m_freemode_01`
    RequestModel(model)
    while not HasModelLoaded(model) do Wait(0) end
    SetPlayerModel(PlayerId(), model)
    SetModelAsNoLongerNeeded(model)

    creating = true
    exports['aty_clothing']:OpenCustomMenu("creator", {
        "faceBody", "faceAdjust", "overlays", "hair", "apparel", "tattoos",
    })
end)

-- Continue once the save has reached the database
RegisterNetEvent('aty_clothing:client:characterSaved', function(savedSkin)
    if not creating then return end
    creating = false
    -- spawn the player, show your HUD, ...
end)

The menu closes on its own right after characterSaved. menuClosed fires too, but also when the player leaves without saving. A QBCore multicharacter that already triggers qb-clothes:client:CreateFirstCharacter needs no change.

House or motel wardrobe

-- Client: inside your closet interaction
if nearCloset and IsControlJustPressed(0, 38) then -- E
    exports['aty_clothing']:OpenWardrobeMenu("House Wardrobe")
end

Admin edit

-- Server
RegisterCommand('editlook', function(source, args)
    local target = tonumber(args[1])
    if not target or not GetPlayerName(target) then return end

    exports['aty_clothing']:OpenClothingMenu(target, "creator", {
        allowedCategories = { "faceBody", "faceAdjust", "overlays", "hair", "apparel", "tattoos" },
    })
end, true) -- restricted: needs the command.editlook ACE

creator is used so the change is saved without charging the player (unless they stand within 30 m of a shop). /skin [id] creator does the same without any code.

Your own prompt

-- config.lua: Config.DisplayMethod = "none"
AddEventHandler('aty_clothing:client:nearInteraction', function(data)
    if data.active then
        exports['my_prompt']:show(('[E] %s'):format(data.title or 'Clothing'))
    else
        exports['my_prompt']:hide()
    end
end)

With "none" only the built-in prompt is hidden: the zones and the E key still open the shop or wardrobe.

Setting Default Effect
Config.UseScreenFade true The screen fades out (400 ms) while the ped and camera are set up and back in (600 ms), on opening and on closing
Config.HideMinimap true The minimap is hidden while the menu is open, and shown again on close only if it was visible before
Config.Camera.FocusOnCategory false true: picking a category moves the camera to that part of the body. Clicking a marker on the character always does

While the menu is open the ped is frozen, invincible and holds a still idle pose, so ambient animations and head turns do not move it. Freezing and invincibility end when the menu closes. If the resource stops while a menu is open, the minimap, focus, freeze and pose are all restored, so a restart never leaves a player stuck.

ATY Scripts LogoATY SCRIPTS

Crafting highly optimized FiveM scripts for QBCore & ESX. Maximum performance, precision code, zero lag.

Join Community

Partner

Official partners with Tebex. Secure checkout and Cfx.re Keymaster integration.

Legal

Not affiliated with Rockstar Games, Cfx.re, FiveM, or Take-Two Interactive. Purchases bound by Tebex Terms of Service.

© 2026 ATY SCRIPTS. All rights reserved.