Nothing inside Weapon Skin Creator knows which framework, inventory or target you run. Each one sits behind a small, unencrypted bridge file, and the right one is picked at start by looking at what is already running.
Layer
Supported
Without it
Framework
es_extended · qb-core · qbx_core
Standalone: players are known by their license and nothing is charged.
Inventory
ox_inventory · qs-inventory
Skins belong to the weapon type, not to one gun.
Target
ox_target · qtarget · qb-target
Shops, the workbench and supply crates use an on-screen prompt and a key.
Prompts
qs-textui
ox_lib text UI and native 3D text.
Progress and HUD
qs-interface
ox_lib progress circle; only the radar is hidden in the studio.
Used only to restore each player's ped after a live addon weapon update.
Database
oxmysql
Required.
Every optional integration degrades silently. A missing resource makes its feature stand down instead of erroring. Shops have no framework job and no society account — their money lives in their own till — so there is no banking integration to set up.
Each framework has a bridge in custom/<framework>/server.lua and client.lua. It decides who a player is, how money moves and who is an admin.
Framework
Player identifier
Admin
Money
ESX
identifier
Group in Config.AdminGroups
Accounts by name: money, bank, black_money…
QBCore / Qbox
citizenid
god or admin permission, or the command ace
money is paid as cash; bank, crypto…
Standalone
license
The command ace
Free — nothing is charged.
To pin a framework, or to support a renamed copy, edit the detection list in config/config.lua. The console confirms the choice at start with Successfully loaded the framework.
Another framework is a new folder, custom/<name>/, with a server and a client bridge copied from the closest one. The client bridge must call SetFrameworkReady() once the character is loaded, and the server bridge OnPlayerLoaded(source).
The inventory tells the script the serial of the gun in hand, so a skin can belong to one exact weapon rather than to every copy of it.
Inventory
Serial read from
ox_inventory
The weapon's metadata.serial
qs-inventory
The weapon's info.serie
Settings → Skin inventory → Equipped per chooses between Automatic (per gun wherever the inventory can tell them apart), Per weapon type and Per weapon item.
Copy client/custom/inventory/standalone.lua to a file named after your inventory, and change its first line so it only runs for that inventory.
Return the serial
GetHeldWeaponSerial(cfg) returns the serial of the gun in hand — 32 characters at most — or nil. ToggleInventoryClothing(state) is called when the studio opens and closes, and must exist even if it does nothing.
Settings → Interaction → Use a target resource moves every interaction onto ox_target, qtarget or qb-target: Skin studio, Skin shop and Management on the NPC, Management on the management point, Invite a customer on the workbench and Collect the delivery on a supply crate.
Without a target, the same actions are prompts drawn next to each point — through qs-textui when it is running, native 3D text otherwise — answered with the keys in Settings → Interaction: E for the studio and G for the skin shop by default.
Notifications are the script's own toasts, styled like the studio. Everything visible that touches another resource lives in custom/client.lua, unencrypted: Notification, DrawText3D, ProgressBar and ToggleHud. To send toasts to your own notification resource, change one function:
lua
-- custom/client.luafunctionNotification(msg, type)-- type: 'info' | 'error' | 'success'if GetResourceState('qs-interface') == 'started'thenreturn exports['qs-interface']:AddNotify(msg, type, 5000)
end
SendReactMessage('notification', { msg = msg, type = type })
end
The game HUD is hidden in the studio, in painter sessions, in the admin panel and in the management menu (Settings → Studio → Hide the HUD). With qs-interface running, its HUD is hidden as well.
Everything players and admins do can be posted to Discord as an embed. Each category has its own URL in server/webhooks.lua; an empty one is simply not sent.
Channel
What goes there
purchase
Skins created and touched up, catalog skins bought, inventory slots bought.
artist
Painter sessions started, and skins applied by a painter.
moderation
Skins waiting for review, approved and rejected.
admin
Shops, the catalog, settings, addon weapons, the pool, skins removed or given in the Players tab, and every shop's staff, money, levels, upgrades and supply orders.
tebex
Store grants and revokes.
trade
Gifts and trades between players.
lua
-- server/webhooks.lua_G['webhook'] = {
purchase = 'https://discord.com/api/webhooks/...',
artist = '',
moderation = '',
admin = 'https://discord.com/api/webhooks/...',
tebex = '',
trade = '',
}
_G['fivemanage'] = {
webhook = '', -- a Fivemanage token, to show skin thumbnails in the embeds
}
Each embed names the player with their server id, identifier, Discord and license — and their IP if Settings → General → IP in Discord logs is on.
Sell catalog skins and extra inventory slots in your Tebex store, delivered in game — even to players who are offline when they pay.
Add the secret
In the Tebex panel, Game Servers → copy the server's Secret key, and put it in server.cfg:
bash
set sv_tebexSecret "your_secret_key"
Turn it on
/weaponskincreator → Settings → Tebex → Tebex. The convar's name is a setting too, if yours differs.
Map the packages
In custom/config.lua, by package name exactly as Tebex has it — case and spaces matter:
lua
Config.Tebex.Packages = {
['Dragon AK (Weapon Skin)'] = { kind = 'skin', catalogId = 1 }, -- a copy of catalog item #1
['+5 Skin Slots'] = { kind = 'slots', amount = 5 }, -- five extra inventory slots
}
A catalog skin can also be linked without editing files: type the package name in its Tebex package field.
Deliver
Either the player redeems their transaction id in the skin inventory (Redeem a purchase) or with /weaponskin_tebex tbx-…, or Tebex runs a game server command on purchase:
bash
weaponskin_tebex_grant {id} {transaction}
Leave Require online off in Tebex: a player who is offline receives the grant on their next login.
Every transaction is checked with Tebex and can only be used once. weaponskin_tebex_revoke <transaction> takes a grant back. A grant that cannot land — a full inventory, a sold-out item — waits instead of being lost.
The accounts players can pay with are Config.MoneyTypes in config/config.lua. Each name is handed straight to the framework bridge — getAccountMoney, removeAccountMoney and addAccountMoney in custom/<framework>/server.lua — so an account your framework already has is one line:
lua
Config.MoneyTypes = {
{ name = 'money', label = 'Cash' },
{ name = 'bank', label = 'Bank' },
{ name = 'black_money', label = 'Dirty money' },
}
A currency your framework does not know — an item, a VIP coin — needs a branch for its name in those three functions. Only listed accounts are offered at checkout and in Settings → Prices; the startup checks warn if the default account is not on the list.
Painter commission is paid into the Commission account (Settings → Shops), and payroll always pays into bank.
Players paste image links in the studio's Link tab. Only the address is stored: every screen that shows the design loads the picture straight from the host, so the host must allow other pages to read its images — imgur, Discord and Fivemanage do. A link is tested when it is pasted and refused there, with an explanation, rather than at checkout.
Setting (Images)
Default
Allow image links
On. Off hides the Link tab.
Allow any host
On. Off accepts only the hosts in Config.Images.AllowedHosts.
Block private networks
On. Refuses localhost, LAN and cloud metadata addresses.
lua
-- custom/config.lua — used when "Allow any host" is off; subdomains match
Config.Images.AllowedHosts = {
'i.imgur.com', 'imgur.com', 'cdn.discordapp.com', 'media.discordapp.net',
'r2.fivemanage.com', 'api.fivemanage.com', 'i.ibb.co', 'raw.githubusercontent.com',
'media4.giphy.com',
}
Font categories are script, gothic, serif, display and clean. Gallery categories are tribal, floral, animals, skulls, geometric, symbols, oldschool, minimal and ornaments. tintable lets players recolour the design, and only works for an SVG drawn with currentColor.
Pick one in Settings → General → Language — it switches for every player at once — or set the default for every Quasar resource with setr qs:locale "es". A text missing from a translation falls back to English. To change wording, edit locales/<code>.json and keep a copy before updating.