Authoring a streamed outfit pack
We'll ship custom clothing — a kind='outfit' cosmetic pack that dresses the
freemode peds with garments your pack streams. This is the guide for the asset and
wiring half; the descriptor fields themselves are in the
pack descriptor reference.
The reference template is cosmetic_pack_vanguard (MIT): the manifest, the two
.meta skeletons, and four placeholder outfits, everything present except the binary
assets. Copy it, rename, and follow along.
Why outfits and not ped models? A custom ped model changes the silhouette and the damage capsule — in a PvP arena that is pay-to-win wearing a cosmetic's clothes. Freemode components leave every player on the same rig. Outfits are the appearance kind built for selling looks without touching hitboxes.
Prerequisites
- A Cfx.re Element Club subscription (Argentum or higher) on the server's license key, for any server above 8 slots. Streaming clothing for the freemode peds is gated by Cfx.re — without the subscription the pack registers, but the collections never mount for connecting players and every equip is refused. Budget it as a running cost of the catalogue, not a one-off.
- A cloth tool — e.g. Durty Cloth Tool — that compiles your source meshes/textures into the GTA formats. You do not hand-write any of the binary files.
1. What the cloth tool must produce
Three kinds of output, per gender (male and female catalogues are entirely separate assets — one set each):
| Output | What it is | Where it goes |
|---|---|---|
.ymt | The compiled CPedVariationInfo — the collection: the index of every drawable/texture the pack adds | stream/ |
.ydd + .ytd | The garment meshes and their texture variants | stream/ |
.meta | The ShopPedApparel catalogue that introduces the DLC pack to the game | resource root, declared in the manifest (next section) |
Ship the tool's .meta output verbatim and only check the names against the template's
skeletons (mp_m_freemode_01_vanguard.meta / mp_f_freemode_01_vanguard.meta). Three
names must agree, and everything hangs off them:
dlcName— your pack's short DLC name, all lowercase (the streamed.ymtfilename derives from it and must be all-lowercase). This is also thedlcNameyourpack.luadescriptor declares.pedName— the freemode ped the catalogue dresses (mp_m_freemode_01ormp_f_freemode_01).fullDlcName— always<pedName>_<dlcName>. This is the collection name the runtime targets, and the prefix of every streamed filename.
2. The manifest wiring — where everyone trips
For a streamed ped pack, dropping models into stream/ is enough — FiveM
auto-streams the folder, no declaration needed. That is not true for add-on
clothing. Freemode clothing only mounts as a variation collection if the game is
told the DLC pack exists, and that introduction is the ShopPedApparel .meta —
which, like every data-driven .meta in FiveM, needs two declarations:
-- fxmanifest.lua
files {
'mp_m_freemode_01_vanguard.meta', -- 1. ship the file to the client
'mp_f_freemode_01_vanguard.meta', -- (it is NOT in stream/, so it is not auto-transferred)
}
data_file 'SHOP_PED_APPAREL_META_FILE' 'mp_m_freemode_01_vanguard.meta' -- 2. parse it
data_file 'SHOP_PED_APPAREL_META_FILE' 'mp_f_freemode_01_vanguard.meta'Forget files{} and the data_file points at nothing; forget the data_file and the
file downloads but the collection never mounts. One data_file line per meta — the
male and female catalogues are separate metas (separate pedName/fullDlcName →
separate collections) even when they ship in one resource. The .ydd/.ytd/.ymt
binaries themselves DO go in stream/ and are auto-streamed — only the .meta needs
declaring.
The rest of the manifest is the standard pack shape — dependencies { 'sdk', 'customization' } and the shared registration scripts (see the template).
3. Filename conventions
Every streamed file is prefixed by the fullDlcName. From the template's
stream/README.md:
stream/
mp_m_freemode_01_vanguard.ymt # the collection (CPedVariationInfo)
# components: <fullDlcName>^<slot>_<NNN>_<u|r>.ydd
# + <fullDlcName>^<slot>_diff_<NNN>_<a-z>_<uni|whi>.ytd
mp_m_freemode_01_vanguard^jbib_000_u.ydd # top, drawable 000
mp_m_freemode_01_vanguard^jbib_diff_000_a_uni.ytd # its texture variant a (= texture 0)
mp_m_freemode_01_vanguard^uppr_000_u.ydd # matching arms — ALWAYS pair with the top
...
# props: note the `_p_` infix and the `p_` slot names; no _u/_r suffix
# <pedName>_p_<dlcName>^<p_slot>_<NNN>.ydd + <pedName>_p_<dlcName>^<p_slot>_diff_<NNN>_<a-z>.ytd
mp_m_freemode_01_p_vanguard^p_head_000.ydd # helmet
mp_m_freemode_01_p_vanguard^p_head_diff_000_a.ytd<slot>is the RAGE short name (head berd hair uppr lowr hand feet teef accs task decl jbib, propsp_head p_eyes p_ears p_lwrist p_rwrist) — the same vocabulary as the descriptor's slot table.<NNN>is the local drawable index — the number your descriptor'spiecesdeclare. It is local to this collection; the runtime applies it with the collection natives, so it never collides with other packs and never shifts on a gamebuild bump. This is the addressing rule — if you take one thing from this guide, take that.- Model suffix
_u= universal texture set,_r= race-variant; the texture suffix (_uni/_whi) must match the model's choice. - Texture letter
a–zmaps totexture = 0–25in the descriptor. - Keep the whole tree lowercase — the
.ymtname must be, and then you can't get it wrong.
4. The descriptor
With the assets named, the descriptor is small. Declare the dlcName once at pack
level — every item derives its collection from it as <base>_<dlcName>, so the one
name that must match the shipped assets is written once instead of repeated per item
(repetition is how it drifts):
local PACK = definePack{
id = 'mypack', apiVersion = 2, kind = 'outfit',
dlcName = 'mypack', -- must equal the .meta dlcName
status = 'locked', sku = '<tebex package id>',
present = { title = 'My Pack', sub = 'Premium', rgb = '132 168 96' },
skins = {
{ id = 'mypack_strike_m', label = 'Strike', base = 'mp_m_freemode_01',
pieces = {
{ slot = 11, drawable = 0 }, -- jbib: the top…
{ slot = 3, drawable = 0 }, -- uppr: …ALWAYS with its arms
{ slot = 4, drawable = 0 }, -- lowr
{ slot = 6, drawable = 0 }, -- feet
{ slot = 0, drawable = 0, prop = true }, -- p_head: helmet
} },
-- one item per gender: the female twin targets base = 'mp_f_freemode_01'
-- and lives in the mp_f_ collection. Keep local indices in lockstep across
-- the two collections — it makes the asset checklist trivial.
},
}Two conventions worth keeping:
- A top (
11/jbib) always ships with its matching arms (3/uppr). The jbib mesh has no arms of its own; without your uppr the player keeps the previous outfit's sleeves — floating hands, arms clipping through the jacket. The validator warns when the pair is broken. - One item per gender.
basefixes the rig and the gender (the locker'scatchip is derived from it — don't set it), so every look is two items, one per freemode ped.
5. Verify with /collections — no guessing
Your descriptor's collection name must be whatever the game actually mounted — and that is not always what you expect. Start the resource with assets in place, spawn in, and run the client command:
/collectionsIt dumps every variation collection mounted on your ped, with per-slot drawable counts
— so both the right name and whether your drawables actually landed are one
command away. Your fullDlcNames must appear there.
Add-on clothing collections only mount on the ped models they target. Run
/collectionswhile wearing a freemode ped (equip an outfit, or the base ped) — on any other model the list will not show your clothing collections, and you would wrongly conclude the pack never streamed. The command prints a note when that is the case.
6. How failures present
Deliberate design: an authoring mistake costs one console read, never a silent wrong-garment.
| Failure | What happens |
|---|---|
Collection not mounted (resource not started, stream/ not downloaded, Element Club lapsed, name typo) | The equip is refused — the player keeps their previous appearance — and the log names the collection that was wanted and every collection that IS mounted (the /collections list). |
A piece's drawable/texture doesn't exist in the collection | The piece is skipped with a warning naming slot/drawable/collection; the rest of the outfit applies and the skipped slot shows the default garment. |
| Top without arms | Validator warning at registration (see above). |
7. Limits (real ones, they bite)
- 128 drawables per component slot per collection is the safe ceiling — at 255 the client crashes. The SDK validator warns at local index ≥ 128: split the catalogue across a second pack/collection instead.
- 26 texture variants per drawable (the
a–zletter). - Everything in
stream/is a first-connect download for every player. Pack weight is a product decision, not a technical afterthought — keep textures sane and ship looks in separate packs when the season grows.
8. Ship it
- Git LFS for the binaries — never commit them raw:
git lfs track "resources/[packs]/*/stream/**". - Thumbnails: an outfit id is not a ped, so there is no stock render — upload a
studio shot to your assets CDN at
<rfx_assets_url>/outfits/<id>.webp, or set the item'simage. See thumbnails. - Selling it:
status='locked'+skuputs it on the shelf exactly like any other pack — see Selling VIP & packs. Note the Element Club prerequisite above: for a paid outfit pack it is a hard dependency, not a convenience.
Where to go next
- Pack descriptor — every field, and the validation rules in full.
- Cosmetics SDK overview — the registry model shared by all three pack kinds.