Tutorial 2026-04-19

Creating Custom Clothing Add-ons for FiveM

OntelMonke

OntelMonke

Admin & Developer at Agency Scripts

Understanding GTA V's Clothing System

GTA V uses a component-based clothing system where each piece of clothing is a "drawable" within a specific component slot. There are 12 component slots on a ped, ranging from head (component 0) through shoes (component 6) to bags and accessories. Each component slot can hold multiple drawables, and each drawable can have multiple texture variations. For example, component 11 (tops) might have drawable 15 (a leather jacket) with textures 0 through 3 representing black, brown, red, and white color variants. Understanding this hierarchy of components, drawables, and textures is essential before you can create custom clothing because every piece you add must slot into this existing structure. The multiplayer (MP) ped model adds another layer with its own drawable mapping that differs from single-player characters, and FiveM servers exclusively use the MP freemode models.

Resource Structure and Streaming

Custom clothing in FiveM works through the streaming system. You create a resource that tells the game to load additional drawable and texture files alongside the base game assets. The resource structure follows strict naming conventions that the game engine uses to identify which ped model, component, and drawable index each file belongs to. Getting the folder structure wrong is the most common cause of clothing not appearing in-game. Your resource needs a fxmanifest.lua that declares the streaming files, and the actual clothing data goes into a stream directory with the correct subfolder hierarchy.

-- fxmanifest.lua for a clothing addon
fx_version 'cerulean'
game 'gta5'

-- The resource name matters: it determines load priority
-- Prefix with zzz_ to ensure it loads after base game assets
this_is_a_map 'yes'
lua54 'yes'

-- All streaming assets inside /stream/ are auto-detected
-- No need to list individual files

The stream folder follows a precise hierarchy. For MP freemode male clothing, files go into stream/mp_m_freemode_01_mp_m_[dlcname]/. For female, replace mp_m with mp_f. Inside that folder, you place the YDD (drawable dictionary), YTD (texture dictionary), and YMT (metadata) files. The naming convention encodes which component and drawable index each file represents. A file named mp_m_freemode_01_mp_m_mypack_jbib_000_u.ydd is drawable 0 for component 11 (jbib = jacket/tops) on the male freemode ped from the DLC pack "mypack".

-- Folder structure example
stream/
  mp_m_freemode_01_mp_m_mypack/
    mp_m_freemode_01_mp_m_mypack.ymt          -- metadata file
    mp_m_freemode_01_mp_m_mypack_jbib_000_u.ydd   -- tops drawable 0
    mp_m_freemode_01_mp_m_mypack_jbib_diff_000_a_uni.ytd  -- texture for tops 0
    mp_m_freemode_01_mp_m_mypack_jbib_001_u.ydd   -- tops drawable 1
    mp_m_freemode_01_mp_m_mypack_jbib_diff_001_a_uni.ytd  -- texture for tops 1
    mp_m_freemode_01_mp_m_mypack_lowr_000_u.ydd   -- pants drawable 0
    mp_m_freemode_01_mp_m_mypack_lowr_diff_000_a_uni.ytd  -- texture for pants 0

Component IDs and Naming Conventions

Each clothing component has a specific abbreviation used in file naming. Memorizing these is critical because a single typo means the game cannot find your asset. The component map is: head (component 0, no clothing), berd (1, masks), hair (2), uppr (3, arms/gloves), lowr (4, pants/legs), hand (5, bags/parachutes), feet (6, shoes), teef (7, accessories like chains), accs (8, undershirts/body accessories), task (9, body armor), decl (10, decals/badges), and jbib (11, tops/jackets). Props use a different system: p_head (hats), p_eyes (glasses), p_ears (earrings), and p_lwrist/p_rwrist (watches/bracelets).

-- Component ID reference for scripting
local ComponentNames = {
    [0]  = 'head',   -- Face (not clothing)
    [1]  = 'berd',   -- Masks
    [2]  = 'hair',   -- Hair styles
    [3]  = 'uppr',   -- Arms / Gloves
    [4]  = 'lowr',   -- Pants / Legs
    [5]  = 'hand',   -- Bags / Parachutes
    [6]  = 'feet',   -- Shoes
    [7]  = 'teef',   -- Accessories (chains, ties)
    [8]  = 'accs',   -- Undershirts
    [9]  = 'task',   -- Body Armor
    [10] = 'decl',   -- Decals / Badges
    [11] = 'jbib',   -- Tops / Jackets
}

-- Get total drawables for a component (useful for clothing menus)
local function GetMaxDrawables(ped, componentId)
    return GetNumberOfPedDrawableVariations(ped, componentId)
end

-- Get texture count for a specific drawable
local function GetMaxTextures(ped, componentId, drawableId)
    return GetNumberOfPedTextureVariations(ped, componentId, drawableId)
end

-- Apply clothing to ped
local function SetClothing(ped, componentId, drawableId, textureId)
    SetPedComponentVariation(ped, componentId, drawableId, textureId, 0)
end

Understanding YMT Files

The YMT (Ped Metadata) file is the glue that holds a clothing pack together. It is an XML-based file that tells the game engine how many drawables exist in each component, how many textures each drawable has, what audio to play when the clothing moves, and various rendering properties. Without a correctly configured YMT, the game will not recognize your drawables even if the YDD and YTD files are perfectly crafted. The YMT must list every single drawable and texture combination in your pack. A single missing entry means that item will be invisible. Editing YMT files by hand is error-prone, which is why most creators use tools like CodeWalker or dedicated YMT generators that build the file automatically from your asset folder contents.

<!-- Simplified YMT structure (XML representation) -->
<CPedVariationInfo>
  <availComp>
    <!-- Bitfield indicating which components have data -->
    <Item value="2048" />  <!-- Only jbib (component 11) -->
  </availComp>
  <compInfos>
    <Item> <!-- Component 11 (jbib / tops) -->
      <drawblDict>
        <Item>  <!-- Drawable 0 -->
          <numAlternatives value="0" />
          <numTexVariations value="3" />  <!-- 3 color variants -->
          <clothData>
            <ownsCloth value="false" />
          </clothData>
        </Item>
        <Item>  <!-- Drawable 1 -->
          <numAlternatives value="0" />
          <numTexVariations value="2" />  <!-- 2 color variants -->
          <clothData>
            <ownsCloth value="false" />
          </clothData>
        </Item>
      </drawblDict>
    </Item>
  </compInfos>
</CPedVariationInfo>

Texture Variations and Quality

Each drawable can have multiple texture variations, which represent different colors or patterns of the same clothing model. The base texture file uses the naming pattern [pack]_[component]_diff_[drawableIndex]_[textureIndex]_uni.ytd. Textures should be created in powers of two (512x512, 1024x1024, 2048x2048) for optimal GPU compatibility. Higher resolution textures look better but consume more VRAM, which is a limited resource especially on servers where players are loading dozens of custom clothing packs simultaneously. A practical guideline is to use 1024x1024 for most clothing items and reserve 2048x2048 for items with fine details like embroidered logos or intricate patterns. Each YTD file can contain multiple texture layers including diffuse (color), normal (surface detail), and specular (shininess) maps, though most FiveM clothing packs only use the diffuse layer to keep file sizes manageable.

Building a Clothing Menu Script

Once your streaming resource is working, you need a way for players to browse and apply the clothing. A clothing menu script iterates through all available drawables per component and lets players preview them on their character in real time. The core logic uses GetNumberOfPedDrawableVariations to determine how many drawables exist for each component, then SetPedComponentVariation to apply the selected one. Wrap this in an ox_lib or NUI menu for a polished user experience. The tricky part is handling first-person previews and camera angles so players can see what they are trying on without awkward clipping or zoom issues.

-- client/clothing_menu.lua
local function OpenClothingMenu()
    local ped = PlayerPedId()
    local components = {}

    for compId = 0, 11 do
        local maxDrawables = GetNumberOfPedDrawableVariations(ped, compId)
        if maxDrawables > 0 then
            local currentDrawable = GetPedDrawableVariation(ped, compId)
            local currentTexture = GetPedTextureVariation(ped, compId)
            local maxTextures = GetNumberOfPedTextureVariations(ped, compId, currentDrawable)

            table.insert(components, {
                id = compId,
                label = ComponentNames[compId] or ('Component ' .. compId),
                drawable = currentDrawable,
                texture = currentTexture,
                maxDrawable = maxDrawables - 1,
                maxTexture = maxTextures - 1,
            })
        end
    end

    -- Build menu options
    local options = {}
    for _, comp in ipairs(components) do
        options[#options + 1] = {
            title = comp.label,
            description = ('Drawable: %d/%d | Texture: %d/%d'):format(
                comp.drawable, comp.maxDrawable, comp.texture, comp.maxTexture),
            onSelect = function()
                OpenComponentEditor(comp.id)
            end
        }
    end

    lib.registerContext({ id = 'clothing_menu', title = 'Wardrobe', options = options })
    lib.showContext('clothing_menu')
end

local function OpenComponentEditor(componentId)
    local ped = PlayerPedId()
    local maxDraw = GetNumberOfPedDrawableVariations(ped, componentId) - 1

    -- Interactive drawable browser with live preview
    local input = lib.inputDialog('Select Clothing', {
        { type = 'slider', label = 'Style', min = 0, max = maxDraw, default = GetPedDrawableVariation(ped, componentId) },
    })

    if input then
        local drawableId = input[1]
        local maxTex = GetNumberOfPedTextureVariations(ped, componentId, drawableId) - 1
        SetPedComponentVariation(ped, componentId, drawableId, 0, 0)

        if maxTex > 0 then
            local texInput = lib.inputDialog('Select Color', {
                { type = 'slider', label = 'Variant', min = 0, max = maxTex, default = 0 },
            })
            if texInput then
                SetPedComponentVariation(ped, componentId, drawableId, texInput[1], 0)
            end
        end
    end
end

Common Issues and Troubleshooting

The most frequent problem is clothing appearing as invisible or as the wrong item. This almost always traces back to an incorrect YMT file that does not properly declare the drawable count or texture count. Verify that your YMT lists the exact number of drawables and textures that exist in your stream folder. Another common issue is the resource loading order: if your clothing pack loads before the base game assets, the drawable indices can collide and overwrite vanilla clothing. Prefix your resource name with zzz_ to ensure it loads last. Texture blurriness usually indicates the YTD is using too low a resolution or the mipmaps are not generated correctly. Always generate mipmaps when exporting your YTD files in CodeWalker. Finally, if clothing shows on male models but not female or vice versa, double check that you have separate folders for mp_m_freemode_01 and mp_f_freemode_01 with properly gendered mesh files, since male and female ped models have different skeleton rigs and require separate geometry.

Optimizing for Server Performance

Custom clothing packs are one of the largest contributors to server download size and client VRAM usage. A single poorly optimized pack with 100 high-resolution items can add gigabytes to your server's download requirement. To keep things manageable, compress your YTD textures using DXT5 or BC7 format, which provides good visual quality at a fraction of the raw file size. Limit each pack to a reasonable number of items, typically 20 to 50 pieces, and split larger collections across multiple resources that can be loaded independently. Consider offering a "lite" version of popular packs with 512x512 textures for players on lower-end hardware. On the scripting side, avoid repeatedly calling SetPedComponentVariation in a loop because each call triggers a model update. Batch clothing changes by collecting all component updates and applying them in sequence within a single frame to minimize visual popping and rendering overhead.

Share this article

Ready to upgrade your server?

Check out our premium FiveM scripts in the Agency Scripts store or join our Discord community for support and updates.