Claude-skill-registry 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.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/avatar-ugc" ~/.claude/skills/majiayu000-claude-skill-registry-avatar-ugc && rm -rf "$T"
manifest:
skills/data/avatar-ugc/SKILL.mdsource content
Avatar & UGC Customization
Quick Reference Links
Official Documentation:
- Character Appearance - Overview of avatar customization
- HumanoidDescription API - Core avatar properties
- Shirt API - Classic shirt clothing
- Pants API - Classic pants clothing
- ShirtGraphic API - T-shirts
- Accessory API - Accessories/hats
- InsertService API - Loading assets
- AvatarEditorService API - Avatar editor support
Wiki References:
- User-generated content (Wiki) - UGC overview
- Accessory (Wiki) - Accessory system
- Clothing (Wiki) - Clothing system
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 |
|---|---|---|
| number | Shirt asset ID |
| number | Pants asset ID |
| number | T-shirt asset ID |
| number | Face asset ID |
| number | Head mesh asset ID |
| number | Torso mesh asset ID |
, | number | Arm mesh asset IDs |
, | number | Leg mesh asset IDs |
| string | Comma-separated hat asset IDs |
| string | Comma-separated hair asset IDs |
| string | Comma-separated face accessory IDs |
| string | Comma-separated neck accessory IDs |
| string | Comma-separated shoulder accessory IDs |
| string | Comma-separated front accessory IDs |
| string | Comma-separated back accessory IDs |
| string | Comma-separated waist accessory IDs |
Creating HumanoidDescription
-- 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
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
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
-- 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
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
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
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
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
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
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
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
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
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)
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 |
|---|---|
| Hats, helmets |
| Hair styles |
| Glasses, masks |
| Necklaces, scarves |
| Shoulder pads |
| Front accessories |
| Backpacks, wings |
| Belts, tails |
| Layered t-shirts |
| Layered shirts |
| Layered pants |
| Layered jackets |
| Layered sweaters |
| Layered shorts |
| Left shoe |
| Right shoe |
| 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
only works with assets accessible to the experience creatorInsertService:LoadAsset()- 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
- Always wrap asset loading in
for error handlingpcall() - Cache HumanoidDescriptions when making multiple changes
- Use
to preserve existing appearance when making partial changesGetAppliedDescription() - 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