Integrations — Clothing Creator | Quasar Store | Quasar Store
Documentation
Integrations
How Clothing Creator works with illenium-appearance, qs-appearance, fivem-appearance, esx_skin and qb-clothing, plus item labels, notifications, Discord logs, image hosts, frameworks and 41 languages.
Clothing Creator touches very little outside itself. Everything framework-specific sits in a small, unencrypted bridge under custom/, and published clothing reaches the rest of your server the way base-game clothing does — as drawables on the freemode ped.
Layer
Supported
Without it
Framework
es_extended · qb-core · qbx_core
Standalone: admins are whoever has the command ace, players are known by their licence.
Appearance menu
Any. Restoring the outfit after a refresh: qs-appearance · illenium-appearance · fivem-appearance · esx_skin
Published pieces are still taken off and put back on around every publish by Clothing Creator itself.
Database
oxmysql
Required.
Library
ox_lib
Required.
Notifications
The studio's own toasts, or any notify resource
The built-in toasts are used.
Logs
Discord webhooks
Nothing is sent. The publish history is still kept in the database.
There is nothing to wire up. Appearance menus — illenium-appearance, qs-appearance, fivem-appearance, esx_skin, qb-clothing, rcore_clothing and the rest — list clothing by counting the drawables a freemode ped has in each slot, and a publish raises that count. A new item simply appears as the next number in its slot, for every player, in whatever menu they already use. Outfits saved by those menus keep working, because a retired item leaves an invisible placeholder behind instead of shifting the numbers after it.
After the clothing refresh of a publish, a player's skin is reloaded through the first of these that is running:
Menus show drawables as numbers. If yours can display labels, Clothing Creator writes the name of every live item into qs-clothing-assets/integrations/labels.json (and a labels.lua returning the same table) on every start and after every publish or retire:
lua
local labels = json.decode(LoadResourceFile('qs-clothing-assets', 'integrations/labels.json'))
-- labels.male.components['11'] → every published top for the male ped-- { { collection = 'qsc_m', localIndex = 0, name = 'Los Santos Customs Tee' }, ... }-- labels.female.props['0'] → every published hat for the female ped
To turn collection + localIndex into the number a menu uses, ask the game: GetPedDrawableGlobalIndexFromCollection(ped, slot, collection, localIndex) for clothing, GetPedPropGlobalIndexFromCollection for props.
Messages are shown as toasts in the studio's own style. To route them through your notify resource instead, edit the Notification function in custom/client.lua:
lua
-- custom/client.luafunctionNotification(msg, type)if GetResourceState('qs-interface') == 'started'thenreturn exports['qs-interface']:AddNotify(msg, type, 5000)
end
SendReactMessage('notification', { msg = msg, type = type })
end
type is info, success or error. Server-side messages arrive through the same function.
Every publish, retire and rebuild is also recorded in the qs_clothing_publishes table — who did it, when, how long it took and whether it worked — whether or not a webhook is set.
With Settings → Images → Allow any host switched off, image links are only accepted from the hosts listed in custom/config.lua. Add your own CDN to the list:
Two things are worth knowing if you run scripts that work with peds or routing buckets:
Routing buckets. While a new declaration is applied live, every player is moved into a private routing bucket (870000 + their server id) — a driver alone in their vehicle takes it along — and goes back to their own bucket as soon as their game has the new clothing, within 30 seconds at most. Avoid using buckets in that range.
Freemode peds. A live declaration needs every game free of freemode models after the refresh. A script that keeps its own freemode ped alive — a character-selection preview, a clone in a menu, a mannequin — keeps that game from taking the change; the publish then reports it and the declaration waits for a restart or an empty server.
Supporting a framework that is not on the list takes one folder and one line:
Copy the closest bridge
Duplicate custom/standalone (or custom/esx / custom/qb) as custom/myframework.
Fill in the functions
server.lua answers who a player is and whether they are an admin; client.lua must call SetFrameworkReady() once the character is loaded.
lua
-- custom/myframework/server.luafunctionframework:getIdentifier(source)end-- the player's unique idfunctionframework:playerIsAdmin(source)end-- true for stafffunctionframework:getUserName(source)end-- first name, last namefunctionframework:getPlayers()end-- every online source-- also: getPlayerFromId, getSourceFromIdentifier, getUserNameFromIdentifier-- and call OnPlayerLoaded(source) when a character loads
Register it
In config/config.lua, map your framework's resource name to the folder name, then restart:
The same table is where a renamed framework resource goes — ['my-esx'] = 'esx' — and types.lua documents every bridge function for your editor's autocomplete.
41 complete translations ship in locales/: Arabic, Bengali, Bulgarian, Catalan, Chinese, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Latvian, Lithuanian, Malay, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swahili, Swedish, Thai, Turkish, Ukrainian, Urdu and Vietnamese. Pick one in Settings → General → Language — it applies to everyone at once, with no restart. To change a text, edit the matching key in locales/<code>.json; the files are left open by Asset Escrow.