Loading...
Loading...
Roblox UGC and avatar pipeline specialist - Masters Roblox's avatar system, UGC item creation, accessory rigging, texture standards, and the Creator Marketplace submission pipeline
npx skill4agent add sharadchaturveda-coder/agency-agents-codex agency-roblox-avatar-creatorHumanoidDescription.fbx.obj.pngAttachmentHatAttachmentFaceFrontAttachmentLeftShoulderAttachment_InnerCage## Accessory Export Checklist
### Mesh
- [ ] Triangle count: ___ (limit: 4,000 for accessories, 10,000 for bundle parts)
- [ ] Single mesh object: Y/N
- [ ] Single UV channel in [0,1] space: Y/N
- [ ] No overlapping UVs outside [0,1]: Y/N
- [ ] All transforms applied (scale=1, rot=0): Y/N
- [ ] Pivot point at attachment location: Y/N
- [ ] No zero-area faces or non-manifold geometry: Y/N
### Texture
- [ ] Resolution: ___ × ___ (max 1024×1024)
- [ ] Format: PNG
- [ ] UV islands have 2px+ padding: Y/N
- [ ] No copyrighted content: Y/N
- [ ] Transparency handled in alpha channel: Y/N
### Attachment
- [ ] Attachment object present with correct name: ___
- [ ] Tested on: [ ] Classic [ ] R15 Normal [ ] R15 Rthro
- [ ] No clipping through default avatar meshes in any test body type: Y/N
### File
- [ ] Format: FBX (rigged) / OBJ (static)
- [ ] File name follows naming convention: [CreatorName]_[ItemName]_[Type]-- ServerStorage/Modules/AvatarManager.lua
local Players = game:GetService("Players")
local AvatarManager = {}
-- Apply a full costume to a player's avatar
function AvatarManager.applyOutfit(player: Player, outfitData: table): ()
local character = player.Character
if not character then return end
local humanoid = character:FindFirstChildOfClass("Humanoid")
if not humanoid then return end
local description = humanoid:GetAppliedDescription()
-- Apply accessories (by asset ID)
if outfitData.hat then
description.HatAccessory = tostring(outfitData.hat)
end
if outfitData.face then
description.FaceAccessory = tostring(outfitData.face)
end
if outfitData.shirt then
description.Shirt = outfitData.shirt
end
if outfitData.pants then
description.Pants = outfitData.pants
end
-- Body colors
if outfitData.bodyColors then
description.HeadColor = outfitData.bodyColors.head or description.HeadColor
description.TorsoColor = outfitData.bodyColors.torso or description.TorsoColor
end
-- Apply — this method handles character refresh
humanoid:ApplyDescription(description)
end
-- Load a player's saved outfit from DataStore and apply on spawn
function AvatarManager.applyPlayerSavedOutfit(player: Player): ()
local DataManager = require(script.Parent.DataManager)
local data = DataManager.getData(player)
if data and data.outfit then
AvatarManager.applyOutfit(player, data.outfit)
end
end
return AvatarManager## Layered Clothing Rig Requirements
### Outer Mesh
- The clothing visible in-game
- UV mapped, textured to spec
- Rigged to R15 rig bones (matches Roblox's public R15 rig exactly)
- Export name: [ItemName]
### Inner Cage Mesh (_InnerCage)
- Same topology as outer mesh but shrunk inward by ~0.01 units
- Defines how clothing wraps around the avatar body
- NOT textured — cages are invisible in-game
- Export name: [ItemName]_InnerCage
### Outer Cage Mesh (_OuterCage)
- Used to let other layered items stack on top of this item
- Slightly expanded outward from outer mesh
- Export name: [ItemName]_OuterCage
### Bone Weights
- All vertices weighted to the correct R15 bones
- No unweighted vertices (causes mesh tearing at seams)
- Weight transfers: use Roblox's provided reference rig for correct bone names
### Test Requirement
Apply to all provided test bodies in Roblox Studio before submission:
- Young, Classic, Normal, Rthro Narrow, Rthro Broad
- Verify no clipping at extreme animation poses: idle, run, jump, sit## Item Submission Package: [Item Name]
### Metadata
- **Item Name**: [Accurate, searchable, not misleading]
- **Description**: [Clear description of item + what body part it goes on]
- **Category**: [Hat / Face Accessory / Shoulder Accessory / Shirt / Pants / etc.]
- **Price**: [In Robux — research comparable items for market positioning]
- **Limited**: [ ] Yes (requires eligibility) [ ] No
### Asset Files
- [ ] Mesh: [filename].fbx / .obj
- [ ] Texture: [filename].png (max 1024×1024)
- [ ] Icon thumbnail: 420×420 PNG — item shown clearly on neutral background
### Pre-Submission Validation
- [ ] In-Studio test: item renders correctly on all avatar body types
- [ ] In-Studio test: no clipping in idle, walk, run, jump, sit animations
- [ ] Texture: no copyright, brand logos, or inappropriate content
- [ ] Mesh: triangle count within limits
- [ ] All transforms applied in DCC tool
### Moderation Risk Flags (pre-check)
- [ ] Any text on item? (May require text moderation review)
- [ ] Any reference to real-world brands? → REMOVE
- [ ] Any face coverings? (Moderation scrutiny is higher)
- [ ] Any weapon-shaped accessories? → Review Roblox weapon policy first-- Client-side UI for in-game avatar shop
-- ReplicatedStorage/Modules/AvatarShopUI.lua
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")
local AvatarShopUI = {}
-- Prompt player to purchase a UGC item by asset ID
function AvatarShopUI.promptPurchaseItem(assetId: number): ()
local player = Players.LocalPlayer
-- PromptPurchase works for UGC catalog items
MarketplaceService:PromptPurchase(player, assetId)
end
-- Listen for purchase completion — apply item to avatar
MarketplaceService.PromptPurchaseFinished:Connect(
function(player: Player, assetId: number, isPurchased: boolean)
if isPurchased then
-- Fire server to apply and persist the purchase
local Remotes = game.ReplicatedStorage.Remotes
Remotes.ItemPurchased:FireServer(assetId)
end
end
)
return AvatarShopUIHumanoidDescriptionHumanoidDescriptionHumanoidDescription