Agent skill

avatar-ugc

Programmatically apply UGC (User-Generated Content) to characters including clothing, accessories, and avatar customization. Use when dressing NPCs, building avatar editors, or creating character customization systems.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/avatar-ugc

SKILL.md

Avatar & UGC Customization

Quick Reference Links

Official Documentation:

Wiki References:


Two Approaches to Avatar Customization

1. HumanoidDescription (Recommended)

Best for: Comprehensive avatar changes, player characters, loading from asset IDs

2. Direct Clothing Instances

Best for: NPCs, simple clothing changes, runtime modifications


HumanoidDescription Approach

Key Properties

Property Type Description
Shirt number Shirt asset ID
Pants number Pants asset ID
GraphicTShirt number T-shirt asset ID
Face number Face asset ID
Head number Head mesh asset ID
Torso number Torso mesh asset ID
LeftArm, RightArm number Arm mesh asset IDs
LeftLeg, RightLeg number Leg mesh asset IDs
HatAccessory string Comma-separated hat asset IDs
HairAccessory string Comma-separated hair asset IDs
FaceAccessory string Comma-separated face accessory IDs
NeckAccessory string Comma-separated neck accessory IDs
ShouldersAccessory string Comma-separated shoulder accessory IDs
FrontAccessory string Comma-separated front accessory IDs
BackAccessory string Comma-separated back accessory IDs
WaistAccessory string Comma-separated waist accessory IDs

Creating HumanoidDescription

lua
-- Method 1: Create new empty description
local humanoidDescription = Instance.new("HumanoidDescription")

-- Method 2: Get from existing character
local function getDescriptionFromCharacter(character)
    local humanoid = character:FindFirstChildOfClass("Humanoid")
    if humanoid then
        return humanoid:GetAppliedDescription()
    end
    return nil
end

-- Method 3: Get from player's avatar
local Players = game:GetService("Players")
local function getDescriptionFromUserId(userId)
    local success, description = pcall(function()
        return Players:GetHumanoidDescriptionFromUserId(userId)
    end)
    return success and description or nil
end

-- Method 4: Get from outfit ID
local function getDescriptionFromOutfit(outfitId)
    local success, description = pcall(function()
        return Players:GetHumanoidDescriptionFromOutfitId(outfitId)
    end)
    return success and description or nil
end

Modifying HumanoidDescription

lua
local function customizeDescription(humanoidDescription)
    -- Set clothing (use asset IDs, not content URLs)
    humanoidDescription.Shirt = 6536023867        -- Shirt asset ID
    humanoidDescription.Pants = 6536027646        -- Pants asset ID
    humanoidDescription.GraphicTShirt = 1711661   -- T-shirt asset ID

    -- Set accessories (comma-separated strings for multiple)
    humanoidDescription.HatAccessory = "2551510151,2535600138"
    humanoidDescription.HairAccessory = "4819740796"
    humanoidDescription.FaceAccessory = ""
    humanoidDescription.BackAccessory = "4447084948"

    -- Set body parts
    humanoidDescription.Face = 86487700
    humanoidDescription.Head = 0  -- 0 = default

    -- Set body colors
    humanoidDescription.HeadColor = Color3.fromRGB(234, 184, 146)
    humanoidDescription.TorsoColor = Color3.fromRGB(234, 184, 146)
    humanoidDescription.LeftArmColor = Color3.fromRGB(234, 184, 146)
    humanoidDescription.RightArmColor = Color3.fromRGB(234, 184, 146)
    humanoidDescription.LeftLegColor = Color3.fromRGB(234, 184, 146)
    humanoidDescription.RightLegColor = Color3.fromRGB(234, 184, 146)

    -- Set scale
    humanoidDescription.HeightScale = 1.0
    humanoidDescription.WidthScale = 1.0
    humanoidDescription.HeadScale = 1.0
    humanoidDescription.BodyTypeScale = 0.0  -- 0 = blocky, 1 = realistic
    humanoidDescription.ProportionScale = 0.0

    return humanoidDescription
end

Setting Multiple Accessories with SetAccessories

lua
local function setMultipleAccessories(humanoidDescription)
    local accessories = {
        {
            Order = 1,
            AssetId = 6984769289,
            AccessoryType = Enum.AccessoryType.Hat
        },
        {
            Order = 2,
            AssetId = 6984767443,
            AccessoryType = Enum.AccessoryType.Hair
        },
        {
            Order = 3,
            AssetId = 4447084948,
            AccessoryType = Enum.AccessoryType.Back
        }
    }

    humanoidDescription:SetAccessories(accessories, false)  -- false = don't include rigid accessories
end

Applying HumanoidDescription

lua
-- Apply to existing character
local function applyToCharacter(character, humanoidDescription)
    local humanoid = character:FindFirstChildOfClass("Humanoid")
    if humanoid then
        humanoid:ApplyDescription(humanoidDescription)
    end
end

-- Apply to NPC
local function dressNPC(npc, shirtId, pantsId, hatIds)
    local humanoid = npc:FindFirstChildOfClass("Humanoid")
    if not humanoid then return end

    local description = humanoid:GetAppliedDescription()
    description.Shirt = shirtId or description.Shirt
    description.Pants = pantsId or description.Pants
    description.HatAccessory = hatIds or description.HatAccessory

    humanoid:ApplyDescription(description)
end

-- Load character with description (for spawning)
local function spawnWithDescription(player, humanoidDescription)
    player:LoadCharacterWithHumanoidDescription(humanoidDescription)
end

Direct Clothing Instances (Classic Method)

Apply Shirt to Character/NPC

lua
local function applyShirt(character, shirtAssetId)
    -- Find or create Shirt instance
    local shirt = character:FindFirstChildOfClass("Shirt")
    if not shirt then
        shirt = Instance.new("Shirt")
        shirt.Parent = character
    end

    -- Set template (use rbxassetid:// format)
    shirt.ShirtTemplate = "rbxassetid://" .. shirtAssetId
end

Apply Pants to Character/NPC

lua
local function applyPants(character, pantsAssetId)
    local pants = character:FindFirstChildOfClass("Pants")
    if not pants then
        pants = Instance.new("Pants")
        pants.Parent = character
    end

    pants.PantsTemplate = "rbxassetid://" .. pantsAssetId
end

Apply T-Shirt to Character/NPC

lua
local function applyTShirt(character, tshirtAssetId)
    local tshirt = character:FindFirstChildOfClass("ShirtGraphic")
    if not tshirt then
        tshirt = Instance.new("ShirtGraphic")
        tshirt.Parent = character
    end

    tshirt.Graphic = "rbxassetid://" .. tshirtAssetId
end

Apply Complete Outfit

lua
local function applyOutfit(character, outfit)
    -- outfit = { shirt = id, pants = id, tshirt = id }

    if outfit.shirt then
        applyShirt(character, outfit.shirt)
    end

    if outfit.pants then
        applyPants(character, outfit.pants)
    end

    if outfit.tshirt then
        applyTShirt(character, outfit.tshirt)
    end
end

-- Usage
applyOutfit(npc, {
    shirt = 6536023867,
    pants = 6536027646,
    tshirt = 1711661
})

Loading Accessories with InsertService

lua
local InsertService = game:GetService("InsertService")

-- IMPORTANT: Can only load assets accessible to experience creator
local function loadAccessory(accessoryAssetId)
    local success, model = pcall(function()
        return InsertService:LoadAsset(accessoryAssetId)
    end)

    if success and model then
        local accessory = model:FindFirstChildOfClass("Accessory")
        if accessory then
            accessory.Parent = nil  -- Remove from model container
            model:Destroy()
            return accessory
        end
        model:Destroy()
    end

    return nil
end

-- Apply loaded accessory to character
local function giveAccessory(character, accessoryAssetId)
    local accessory = loadAccessory(accessoryAssetId)
    if accessory then
        local humanoid = character:FindFirstChildOfClass("Humanoid")
        if humanoid then
            humanoid:AddAccessory(accessory)
        end
    end
end

AvatarEditorService (Catalog Integration)

Get Item Details

lua
local AvatarEditorService = game:GetService("AvatarEditorService")

local function getItemDetails(assetId)
    local success, details = pcall(function()
        return AvatarEditorService:GetItemDetails(assetId, Enum.AvatarItemType.Asset)
    end)

    if success then
        return {
            name = details.Name,
            assetType = details.AssetType,
            price = details.Price,
            isOwned = details.IsOwned,
            isFavorited = details.IsFavorited,
            creatorId = details.CreatorTargetId,
            creatorName = details.CreatorName
        }
    end

    return nil
end

Get Player's Inventory

lua
local function getPlayerInventory(player, assetTypes)
    -- assetTypes = array of Enum.AvatarAssetType
    local success, inventory = pcall(function()
        return AvatarEditorService:GetInventory(assetTypes)
    end)

    if success then
        return inventory:GetCurrentPage()
    end

    return {}
end

-- Example: Get player's hats
local hatTypes = {Enum.AvatarAssetType.Hat}
local playerHats = getPlayerInventory(player, hatTypes)

Get Outfit Details

lua
local function getOutfitDetails(outfitId)
    local success, details = pcall(function()
        return AvatarEditorService:GetOutfitDetails(outfitId)
    end)

    return success and details or nil
end

Complete NPC Dressing System

lua
local Players = game:GetService("Players")

local NPCOutfits = {
    Guard = {
        shirt = 6536023867,
        pants = 6536027646,
        hats = "2551510151",
        bodyColors = {
            head = Color3.fromRGB(234, 184, 146),
            torso = Color3.fromRGB(234, 184, 146)
        }
    },
    Merchant = {
        shirt = 398633610,
        pants = 398635927,
        tshirt = 0,
        hats = "4819740796"
    }
}

local function createDressedNPC(npcModel, outfitName)
    local outfit = NPCOutfits[outfitName]
    if not outfit then return end

    local humanoid = npcModel:FindFirstChildOfClass("Humanoid")
    if not humanoid then return end

    -- Get current description or create new one
    local description = humanoid:GetAppliedDescription()

    -- Apply outfit
    if outfit.shirt then
        description.Shirt = outfit.shirt
    end
    if outfit.pants then
        description.Pants = outfit.pants
    end
    if outfit.tshirt then
        description.GraphicTShirt = outfit.tshirt
    end
    if outfit.hats then
        description.HatAccessory = outfit.hats
    end

    -- Apply body colors
    if outfit.bodyColors then
        if outfit.bodyColors.head then
            description.HeadColor = outfit.bodyColors.head
        end
        if outfit.bodyColors.torso then
            description.TorsoColor = outfit.bodyColors.torso
        end
        -- ... etc for other body parts
    end

    -- Apply the description
    humanoid:ApplyDescription(description)
end

UGC Catalog Search (Server-Side)

lua
local AvatarEditorService = game:GetService("AvatarEditorService")

-- Search catalog for items
local function searchCatalog(keyword, assetType, sortType)
    local searchParams = CatalogSearchParams.new()
    searchParams.SearchKeyword = keyword
    searchParams.AssetTypes = {assetType}
    searchParams.SortType = sortType or Enum.CatalogSortType.Relevance

    local success, results = pcall(function()
        return AvatarEditorService:SearchCatalog(searchParams)
    end)

    if success then
        return results:GetCurrentPage()
    end

    return {}
end

-- Example: Search for hats
local hats = searchCatalog("crown", Enum.AvatarAssetType.Hat)
for _, hat in ipairs(hats) do
    print(hat.Name, hat.Id)
end

AccessoryType Enum Reference

Enum Value Description
Enum.AccessoryType.Hat Hats, helmets
Enum.AccessoryType.Hair Hair styles
Enum.AccessoryType.Face Glasses, masks
Enum.AccessoryType.Neck Necklaces, scarves
Enum.AccessoryType.Shoulder Shoulder pads
Enum.AccessoryType.Front Front accessories
Enum.AccessoryType.Back Backpacks, wings
Enum.AccessoryType.Waist Belts, tails
Enum.AccessoryType.TShirt Layered t-shirts
Enum.AccessoryType.Shirt Layered shirts
Enum.AccessoryType.Pants Layered pants
Enum.AccessoryType.Jacket Layered jackets
Enum.AccessoryType.Sweater Layered sweaters
Enum.AccessoryType.Shorts Layered shorts
Enum.AccessoryType.LeftShoe Left shoe
Enum.AccessoryType.RightShoe Right shoe
Enum.AccessoryType.DressSkirt Dresses/skirts

Important Considerations

Asset ID vs Content ID

  • Asset ID: The numeric ID (e.g., 6536023867)
  • Content ID: The full URL format (e.g., rbxassetid://6536023867)
  • HumanoidDescription properties use Asset IDs (numbers)
  • Shirt/Pants/ShirtGraphic templates use Content IDs (strings)

Security & Permissions

  • InsertService:LoadAsset() only works with assets accessible to the experience creator
  • For UGC items from other creators, use HumanoidDescription with asset IDs instead
  • Player inventory access requires appropriate permissions

Classic vs Layered Clothing

  • Classic Clothing: Shirt, Pants, ShirtGraphic (2D textures)
  • Layered Clothing: 3D clothing that deforms with the avatar body
  • Layered clothing uses AccessoryType values like TShirt, Jacket, Sweater

Best Practices

  1. Always wrap asset loading in pcall() for error handling
  2. Cache HumanoidDescriptions when making multiple changes
  3. Use GetAppliedDescription() to preserve existing appearance when making partial changes
  4. For NPCs, apply description once after all changes rather than multiple times

Checklist for Avatar Customization

  • Determine approach (HumanoidDescription vs Direct Instances)
  • Collect asset IDs for clothing/accessories
  • Handle pcall for all async operations
  • Test with R6 and R15 rigs
  • Consider body colors and scale
  • Verify asset permissions for InsertService usage
  • Cache descriptions for performance

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results