How Integrations Work#
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. |
Appearance | qs-appearance · illenium-appearance · fivem-appearance · esx_skin | 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.
Frameworks#
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 | 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.
-- config/config.lua
local frameworks = {
['es_extended'] = 'esx',
['qb-core'] = 'qb',
['qbx_core'] = 'qb',
['my_core'] = 'esx', -- a renamed copy of ESX
}
-- Or skip detection entirely:
-- Config.Framework = 'esx'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).
Inventories and Serials#
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 |
qs-inventory | The weapon's |
Settings → Skin inventory → Equipped per chooses between Automatic (per gun wherever the inventory can tell them apart), Per weapon type and Per weapon item.
Adding an inventory#
Copy the standalone adapter
Copy
client/custom/inventory/standalone.luato 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 — ornil.ToggleInventoryClothing(state)is called when the studio opens and closes, and must exist even if it does nothing.lua -- client/custom/inventory/my-inventory.lua if Config.InventoryResource ~= 'my-inventory' then return end function GetHeldWeaponSerial(cfg) local weapon = exports['my-inventory']:GetCurrentWeapon() return weapon and weapon.serial or nil end function ToggleInventoryClothing(state) endRegister it for detection
Add the resource name to the
inventorieslist inconfig/config.luaand restart.
Targets and Prompts#
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 and the HUD#
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:
-- custom/client.lua
function Notification(msg, type) -- type: 'info' | 'error' | 'success'
if GetResourceState('qs-interface') == 'started' then
return exports['qs-interface']:AddNotify(msg, type, 5000)
end
SendReactMessage('notification', { msg = msg, type = type })
endThe 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.
Discord Logs#
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 |
|---|---|
| Skins created and touched up, catalog skins bought, inventory slots bought. |
| Painter sessions started, and skins applied by a painter. |
| Skins waiting for review, approved and rejected. |
| 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. |
| Store grants and revokes. |
| Gifts and trades between players. |
-- 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.
Tebex#
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.
A Custom Currency#
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:
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.
Image Links#
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 |
Block private networks | On. Refuses localhost, LAN and cloud metadata addresses. |
-- 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',
}Your Own Fonts and Gallery Art#
Both live in custom/. Drop the file in its folder, add a row, and restart the resource:
-- custom/config.lua
-- custom/fonts/MyFont.ttf (.ttf, .otf or .woff2)
Config.FontsCustom = {
{ family = 'My Font', source = 'custom', file = 'MyFont.ttf', weights = { 400 }, category = 'display' },
}
-- custom/gallery/my_logo.svg (.svg or .png, transparent and square)
Config.GalleryCustom = {
{ id = 'my_logo', category = 'symbols', file = 'my_logo.svg', tintable = true, tags = { 'logo' } },
}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.
Languages#
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 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.



