Advanced classic clothing V1.4 - Layered/4K+ texture rendering for classic clothing (R6 and R15)!

EDIT: ACC can now be found on Github, it took me an embarrassingly long time and removed old references e.g. Spritesheet > spritemaps
acc
temp.s7dh9o
[ModeSeven is a publicly avaliable font developed by Andrew Bulhak]

Advanced Classic Clothing
firefox_a55O0PbdHv 1.4 firefox_aA0bo677dv


What's new in V1.4 'Death of Classic clothing' - 17.3.2026
  • FINALLY fixed the sharp texture edges for R6 blocky rigs.

  • This (in part) thanks to gleb_zolotar in the ROBLOX toolbox (i searched up uv mapped r6) where ACC is not needed, You heard me right, Someone UV mapped Blocky R6 which means ACC does not do the UV mapping itself.

    • Blocky R6 is now fully supported by ACC.
  • Added FakeR6, which was responsible for removing those sharp edges

  • REMOVED support for all R6 meshed rigs (because they don’t work!) This also means that there are no more sharp borders for Blocky R6. If you want those back, Use V1.31

    • Attempting to use ACC and Meshed rigs would cause a warning and no clothing is applied for that body part.
  • Added ACCRigPartCFrameR6() (spritemap) which is for use with R6, Contains a table of CFrames which allows customisability of FakeR6 position and rotation.

  • Added tableTexture which is a table containing names of the properties for the Texture class, mainly for autocomplete

  • Moved Readme to _README_ because the readme is now too long

NOTE: When using R6+ACC, You cannot change the UV offsets of the texture which means no animated classic clothing for R6.

Whats new in V1.31 - 3.3.2026

This is a minor update to 1.3, Dedicated spritemaps for other meshed rigs are still experimental and WIP.

What's new in V1.3 - 7.2.2026
  • Changed “spritesheet” to “spritemap”, the modulescript which applies the clothing onto the character’s body.
  • Spritemaps are now stored in their own locations.
  • (EXPERIMENTAL) Added dedicated spritemap profiles for Robloxian 2.0 and Man Rig
  • Added function getObjectId() which returns the object’s memory location as a string. Used for future use only
  • Added function getSpritemaps() which returns a clone of the spritemaps in the _SPRITEMAP table
  • For the optional_spritemap parameter for the new() constructor, You can either pass the modulescript instance (spritemap script) or pass on the name of the spritemap.
  • Moderate code adjustments
What's new in V1.2 - 10.10.2025
  • The size and position of the sprites now change when the body proportion changes. Before, Changing the body proportions e.g. Height, Width would result to the clothing becoming off.
    • Look at the below example comparing both behaviours of ACC 1.2 (current) and 1.1 (previous) when changing body proportions
      licecap_52
  • Added the method “ChangeTexturePropertyFromBodyPartName()” which changes any property of a Texture instance from the body part name
  • Added IMAGE_SIZE global in the spritesheet modulescript where you can now specify your own image sprite size.
  • Updated spritesheet_applicator
  • Updated SpritesheetR15
What's new in V1.1 - 23.9.2025

I have now fixed the issue on R15 rigs where the clothing detail (on arms and legs) just disappear in the joints portion of the body part.

  • Added method getClothingTexturesFromBodyPartName(bodyPartName) which returns all clothing textures from the given body part name
  • Added spritesheet data jointsNegateOffsetR15 which allows the clothing textures to not stretch over R15 body joints
Older Releases

advanced_classic_clothing_1.31.rbxm (14.5 KB)
advanced_classic_clothing_1.3.rbxm (14.1 KB)
advanced_classic_clothing_1.2.rbxm (12.4 KB)
advanced_classic_clothing_1.1.rbxm (10.5 KB)
advanced_classic_clothing_1.0.rbxm (8.5 KB)

NOTE: After the ACC “ban” incident, I have hosted the latest version of ACC’s source code on Github. so you know, if it ACTUALLY gets removed in the future.

About ACC:
Advanced Classic Clothing is my first Open-source project which reimplement how classic clothing is wrapped around a standard humanoid rig. And with that I present Advanced classic clothing!

This modulescript brings in some QOL improvements for 2D classic clothing which can be used in game where flexible character creation is implemented. This eliminates the need to re-upload the same piece of clothing with minor changes. This makes the old 2D classic clothing infinitely customizable and more expressive in my opinion.

Now I wrote this entirely from scratch in around 4 days which means there are lots of bugs in issues listed under Known issues which I suggest you read first


Features include:

  • Support for high resolution textures (standard Shirt and Pants instance already support HQ clothing) (see post 4)
  • Allow for classic clothing to layer on top of each other (with Zindex support)
  • Overlap over the dreaded modesty layer for R15 rigs, (an unintentional feature)
  • ANIMATE clothing by using OffsetStudsU and OffsetStudsV
  • Ability to create custom profiles for different clothing e.g. 2D shoes, gloves, belts, etc
  • Literally anything that the standard Texture property offers, excluding MaterialVariant

Potential uses of ACC

  • Any roleplay/LARP game which offers customizable uniform [spoiler](look at me!) shout ER:LC[/spoiler]
  • Programmable differences to minor parts of clothes/objects within clothes e.g. Colour, Transparency
  • Avatar clothing customization menu/Dress-up games
  • Retain classic clothing after the humanoid is deleted (e.g. for a Statue or a permanent ragdoll)

BASIC USAGE - Get started

Step 1
First you need to aquire Advanced Classic Clothing
Now, to use advanced classic clothing, you need to require it.

--[[
Type: Script/LocalScript
RunContext: Legacy/Client/Server
]]
local advanced_classic_clothing = require(path.to.advanced_classic_clothing)

Step 2a - Add Shirt
To apply a clothing to a character model, you now need to create a new object:

  • The first parameter is the name of the shirt, It can be anything you like.
  • Second is the image Id of the shirt
  • Third is a valid R6 or R15 character model
  • and Finally the type of clothing. Defaults is “shirt” or “pants”. It is not case sensitive.
local shirt_id= "rbxassetid://119117418244968" -- Has to be an ImageID, not a clothing ID!!
local character = path.to.your.character
local new_shirt = advanced_classic_clothing.new("My_Shirt",shirt_id,character,"shirt")

Now the script detects and uses the correct spritemap data for the specific humanoid and applies each face of the clothing image to the correct side of the bodyparts.

Now you should get this:

or
From now on I will continue with the R15 rig. Steps for blocky R6 is the same.


Step 2b - Add Pants

Now we want to add in the pants. You simply do advanced_classic_clothing.new() again except you change the image Id to a pants image and set the clothingType to “pants”

local pants_id = "rbxassetid://77995515363451"
local new_pants = advanced_classic_clothing.new("My_Pants",pants_id,character,"pants")

Now you should get this:


Step 3 - Change ZIndex
Now you see the straps are overlapping over the jacket. Normal firefighting gear has the straps under the jacket. We can fix this by using the ChangeZIndex method stored in the advanced_classic_clothing object.

new_shirt:ChangeZIndex(1)
new_pants:ChangeZIndex(0)

--[[
above code is functionally the same as:
new_shirt:ChangeTextureProperty("ZIndex",1)
new_pants:ChangeTextureProperty("ZIndex",0)
]]

Now the shirt is on top of the textures for the pants torso, resulting to this:


Step 4 - Change clothing properties
Finally, we want to change the property of the texture. There is a method which takes in the name of the property which is part of the Texture class and allows us to change the value of it.

You can change the pants transparency to 0.75 using this:

new_pants:ChangeTextureProperty(new_pants.Texture.Transparency,0.75)


Step 5 - Deleting the object

To delete the advanced_classic_clothing object but retain the clothing textures on the character you use:

new_shirt:DestroyMethods()

Doing so means that you can no longer change Texture properties or the ZIndex.

To remove the object and all the clothing textures:

new_shirt:Destroy()

--[[
This method uses the spritesheet_applicator's DestroyAllInstances()
method to remove any created sprites..
]]

And that’s it! You have basically mastered the arts of adding advanced classic clothing!

Final code
local advanced_classic_clothing = require( game:GetService("ReplicatedStorage"):WaitForChild("advanced_classic_clothing"))

local shirt_id= "rbxassetid://119117418244968"
local character = script.Parent
local new_shirt = advanced_classic_clothing.new("My_Shirt",shirt_id,character,"shirt")

local pants_id = "rbxassetid://77995515363451"
local new_pants = advanced_classic_clothing.new("My_Pants",pants_id,character,"pants")

new_shirt:ChangeZIndex(1)
new_pants:ChangeZIndex(0)

new_pants:ChangeTextureProperty("Transparency",0.75)

new_shirt:Destroy()
ADVANCED - Create your own spritemap and Animate 2D clothing

If you want to create your own spritemap modulescript then see this post I made detailing more information about it.

I have taken inspiration from this guide from the ROBLOX Docs which allows me to animate clothing and make some interesting effects.

I have created this cloud texture using PaintDotNet and uploaded it as an image with the same resolution and aspect ratio as a clothing template. I then binded the movement to OffsetStudsU to create this effect:
licecap_51

Now you can create your own animated retroslop

Code
local advanced_classic_clothing = require( game:GetService("ReplicatedStorage"):WaitForChild("advanced_classic_clothing"))

local shirt_id= "rbxassetid://113746328831574"
local character = script.Parent
local new_shirt = advanced_classic_clothing.new("My_Shirt",shirt_id,character,"shirt")

local pants_id = "rbxassetid://113746328831574"
local new_pants = advanced_classic_clothing.new("My_Pants",pants_id,character,"pants")

new_shirt:ChangeTextureProperty("ZIndex",1)

new_shirt:ChangeZIndex(1)
new_pants:ChangeZIndex(0)

local runservice = game:GetService("RunService")

local colour = Color3.new(0.666667, 1, 1)
new_shirt:ChangeTextureProperty("Color3",colour) -- light blue
new_pants:ChangeTextureProperty("Color3",colour)

function animate(deltatime,clothing_assets,studsPerTick)
	local real = (1/60) / deltatime
	for _,textures in clothing_assets do
		if textures:IsA("Texture") then
			textures.OffsetStudsU += (studsPerTick * real)
		end
	end
end

local shirt_assets = new_shirt:getAllClothingTextures()
local pants_assets = new_pants:getAllClothingTextures()

runservice.Heartbeat:Connect(function(dt)
	animate(dt,shirt_assets,0.01)
	animate(dt,pants_assets,-0.01)
end)

How it works

This takes a standard classic clothing template and uses Texture instances to recreate each side of a body part with the applied clothing.

I used my spritesheet modulescript which converts bitmap pixels into Roblox studs and applies its offsets and sizes to a texture accordingly. (It does this by taking the 2D size of an object and the resolution of the target spritesheet image)

The main script reads a table containing the name of the bodypart where it then contains information on how and where to apply the faces of a 2D clothing asset to that bodypart.

API Methods
Method/Constructor Name Method Description
new(name : string,imageId,humanoidModel : Humanoid,clothingType : string,optional_spriteSheetdata : string) : advanced_clothing_object Creates a new advanced_classic_clothing object (optional_spriteSheetdata is only needed if you want to force another spritesheet)
ChangeTextureProperty(property : string,value : any) : nil Changes the texture property using its name and applies it with the specified value
ChangeZIndex(zindex : number) : nil Change the ZIndex value for all the texture instances
getClothingType() : string Returns the clothing type parsed in new()
getAllClothingTextures() : {} Returns a cloned table containing all the Textures that make up the clothing
[V1.1] getClothingTexturesFromBodyPartName(bodyPartName : string) : {} Returns all clothing textures (if any) from the given body part name
[V1.2] ChangeTexturePropertyFromBodyPartName(bodyPartName : string,property : string, value : any) : nil Apply the specified property and value of textures specified in bodyPartName
[V1.3] getSpriteMaps() : {} Returns a clone of the spritemap table stored in _SPRITEMAP
DestroyMethods() : nil Destroys the advanced_classic_clothing object but keeps the textures (effectively making it read-only)
Destroy() : nil Same as DestroyMethods but removes all clothing textures
Example explanation

In the example I used my firefight (fire fighter) outfit I have saved on ROBLOX, mainly because I have the original .pdn files that made up those clothing assets.

The pants and shirt images are split into different layers. From the base clothing background to the sowlines and even to small details e.g. the radio and uniform nameplate.

Then the images are converted into black and white with some of the layers requiring a higher contrast or brightness, without losing some of the details. Brighter areas of the image allow different colours to be applied while the darker details have no effect in the change of colour

Each of those layers get their own advanced_classic_clothing object where from there contains methods to modify all it’s Texture properties, from the image colour, transparency and even the ZIndex.

Known issues
  1. (R15) Some of the textures are rotated incorrectly
    e.g. Feet treads are rotated heel first
  • I can’t really find a fix for this, you might just rotate the problem bottom hands and feet faces up-side-down using an image editor.
  1. (R6 + R15) Clothing with alpha has sharper borders
  • This is not really an issue, rather an unintentional feature (but I still feel the need to mention it), If you have a clothing asset that has transparent areas, you might find them to have a border around non-transparent parts of the image, It is just how the image resampler works when stretching an image that is not it’s native size. Bet they go well with the highlight property and create some anime-like borders.
  1. Clothing appears darker than usual
  • This is purely a lighting issue, it is noticeable on certain devices and on the highest quality level in the settings. Unfortunately there is no fix for this issue.
  1. R6 meshed rigs do not work with ACC
  • R6 Meshed rigs has been depreciated on V1.4 onwards and no longer work with ACC.
  1. (R6) Cannot change U/V offsets
  • For some reason ROBLOX meshes overrides custom UV offsets for Textures on R6.
Disadvantages

The biggest issue was writing down spritesheet profiles for the different rig types. R6 is easy to manage, however R15 took 350 lines of code and one entire night to complete. Thankfully, for both R6 and R15 I have written a default rig profile for you to read and make changes to.

There is also the issue with potentially spamming a bunch of textures into a small area. print(6 * 14) --84+ possible texture instances in r15!!!!The majority of us may not feel the performance impact[spoiler] (even with a computer from 2011)[/spoiler] but those who have low end devices may feel the performance impact this may present (though do correct me on that)

Image gallery

Black and white layars which contains components of the shirt
(Bug) Bottoms of hands and feet are rotated the wrong way
(Bug) Why you shouldn’t use ACC with R6 and MeshParts.

Standard shirt instance (left) and Advanced Classic Clothing (right). Notice how the details around sowlines and the reflectors are more sharper. Honestly gives out some Borderlands vibes to it.


Remarks
Other useful/related resources:

*Because of ROBLOX’s excellent support for R6, this is only limited to the default (blocky) rig, and even that has some slight issues, especially on the versions pre 1.4. Don’t worry, R15 is no better.


Proposed project name change
The current name for this project is “Advanced Classic Clothing”. I’ve been debating whether to change the name to “B2C” (Better 2D clothing), mainly because “advanced Classic Clothing” doesn’t really roll-off the tongue. imo B2C sounds cooler too.


tnelogo noai-docs noai-programming clothing opensource modulescript classic

61 Likes

Dont know why nobody is commenting, but this is amazing. Thank you.

6 Likes

yes i am replying to myself, I don’t want the original post to look much longer

Understanding the spritesheet moduelscripts


The “spritesheet modulescripts” are scripts read by ACC containing information on how to place each sprite image to a side of each bodypart An R6 and R15 modulescript comes bundled by default

Below shows an example on how the clothing texture should be applied to the UpperTorso with 6 key/value pairs containing the NormalId, Sprite start point and size of the sprite.

Creating custom 2D clothing

You can create new profiles for different types of clothing. For example, Shoes, Gloves or belts.
Under the spritesheet.clothing() constructor, each key contains a table of the name of the body parts which links with the sprite info listed in the spritesheet.spritesheet() constructor (image above)

By default, shirt and pants are present since that is what most people are going to use for 2D clothing.

If you want to add a specific body part to create custom 2D clothing, create a new key, call it whatever you want and list your body parts so that Advanced Classic Clothing can construct images on the body parts. For example, to only add shoes, you can list LeftFoot and RightFoot as a table inside a key/value pair.


Now to use your custom clothing type, Add the name of your custom clothing in advanced_classic_clothing.new() boxed in red
image

Adding a new spritesheet modulescript

If you hate yorself and modified on a copy of any of the spritesheet modulescript, or even made one from scratch, you may find that ACC would not use your custom modulescript.

The main advanced_classic_clothing script contains a table called _spritesheetdata. You add the name of your script as the key and the value as the location of the modulescript.
image

Finally, add the name of the script as the final paramater, optiona_spritesheetdata
image

(optional) set the _debug value to TRUE if the script is not working properly.

2 Likes

Advanced Classic Clothing - Tests with high quality clothing! (2K/4K+)

Now we may all know that a standard shirt and pants texture is usually at the resolution of 585x559. I was wrong when I stated:

But it turns out in game, the engine appears to not render the image past that resolution, no matter what resolution scale you have applied. In my defense, it image (using the standard classic clothing instances) did render in its full resolution in Studio which is how I justified the above claim.


I have upscaled the current clothing on my avatar by 4 times (effectively 2304x2236 or 2k) since I do not want to find (if any) a hi-res ROBLOX clothing texture and the test image is rbxassetid://77678054427074

Comparison between default resolution and upscaled image using Shirt instance

This text will be hidden


Both are using the standard Shirt instance with the only diffence is the resolution is higher than the other, and there is literally no difference: There is still the blurred lines where the sow lines/reflectors are.

On 11/12/25 DMY, ROBLOX announced 4K texture streaming and texture rendering [beta] which aims to reduce load times and the memory footprint for certain devices (and add support for hi-res textures). From the post, Classic clothing is not supported for high res images. However, the Texture instance (which this project heavily uses) does,

Upscaled clothing image on Shirt instance VS Advanced Classic Clothing

Apart from the brightness difference (which appears to be a lighting rendering issue), the immediate detail on the sow lines and reflectors on the edges are way sharper as a result of the image being downscaled rather than upscaled.


When do I need high res clothing textures anyway?

The biggest reason (imo) is for pixel-based graphics. I would love to use pixelated scaling on Texture instances. It is possible in ImageLabels (Guis) but not for the base image classes that the Texture (and others) are based around on. Try to use pixelated clothing e.g. a Minecraft skin on a Roblox avatar and see blurred pixel edges on the character.
The only way I can achieve sharper pixels is by upscaling the image, (which brings performance issues) but because the image needs to be downscaled on the humanoid rig body, the image would result in less blurred detail.

Now I can see the justified reason why, who on earth wants to upload a 4K version of the Teal shirt? Another reason is that clothing templates (generic jackets, hoodies that artists apply their own designs) are all at 585x559 anyway, making hi-res clothing designs pointless. I had to upscale my existing designs using PaintDotNet to show demonstrations, as an example.

However, if you’re someone who wants hi-res clothing for your game, Dont worry, ACC has always supported it.

NOTE: If you want to try this yourself, You need to enable 4K texture streaming in the Beta features tab of Studio. As of writing, it is not yet available on deployed game servers and clients. (12/12/25)

3 Likes

This is really interesting, would this be compatible with the Dogu15 mesh deformation rig?

1 Like

Yes it is!


It appears to have the exact construction as standard R15. I even tried bending the joints and apply different body proportions while the game is running to make sure ACC works fine.

For the spritemap I just used the default blocky/generic rig for the clothing and there seems to have no issues. Also good to know that other open-sourced rigs/projects do work (because I haven’t bothered testing them anyway)

Holy shit thanks for the spritesheet modules :folded_hands:

and the resource as a whole… I don’t know how I have not come across this sooner!

The answer is in the post under How it works

1 Like

I’m running into an issue with Dogu15 and ACC, where there is a misallignment of the shirt on the lowerarm and upperarm. Is there any fix for this? Thanks in advance.

Same issue, gonna try realligning and get back to you if i figure anything out

Intel and @jonmxI, I released V1.31 which adds a special spritemap for DoguR15, It turns out that both the arms and legs have some overlapping issues because DoguR15 don’t have those joints that the standard R15 rig has.

To use the spritemap (or any other spritemap) add this custom parameter:

local shirt = acc.new("Shirt","rbxasset://Shirt.png",script.Parent,"shirt",acc:getSpriteMaps().R15_dogu15)
local pants = acc.new("pants","rbxasset://Pants.png",script.Parent,"pants",acc:getSpriteMaps().R15_dogu15)
Result

Section of code changed
-- SpritemapR15_dogu15, Line 356
spritesheet.jointsNegateOffsetR15 = function()
	return {
		["LeftUpperArm"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
		},
		["LeftLowerArm"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
		},
		["RightUpperArm"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
		},
		["RightLowerArm"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
		},
		["LeftUpperLeg"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
			
		},
		["LeftLowerLeg"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
		},
		["RightUpperLeg"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds

		},
		["RightLowerLeg"] = {
			["offset"] = {0,0,0,0},
			["appliesToNormalId"] = sides_normalIds
		}
	}
	
end

For others, just clone the SpritemapR15 module script and edit the values in JointsNegateOffsetR15()

1 Like

This is a neat way to go about creating layered and high res clothing, but doesn’t uploading an image over 1024x (even with 8k support) cause crazy compression?

I (was) working on another way to try to solve this problem, involving a custom UV mapped mesh (to circumvent the “crazy compression” I noticed) and a SurfaceAppearance set to Transparency mode. I was already drafting a topic to share it with the public, but I’m losing interest, especially with the age check after 3/18 measure :frowning:.

I’m posting to ask if anyone would like to see what I have and refine the resource - especially if you have chops for UV mapping and such, which I definitely don’t.. It’s awesome to see that there’s interest for something like this, though :grin:.

I have no idea about the crazy compression thing, It’s possible that ROBLOX uses JPEG (if not WEBP) compression on their images for asset delivery (don’t quote me on that), if they do, the compression is barely noticable. For years you can always upload an image at any resolution only if you can keep the file size down. Keep in mind 4K texture rendering and streaming is still in beta, and I only seen them mention 4K and not 8K. (i ctrl+f 8k and nothing showed up)

I showed in post 4 in detail where I tried an upscaled classic clothing on the standard Shirt and Pants instance where I showed that both the original and upscaled images appeared the same, maybe it had something to do with that? especially when ROBLOX put out themselves that Classic clothing does not support high res textures.

Besides, 4k is lots for classic clothing, it is equivilent to a streamer buying a 8K Sony cinematography camera as a webcam to then downscale it to a tiny little window in the corner.

I kinda don’t either, i am a music composer and programmer, not a master at texture and graphic design but gamedev requires the knoledge of UV mapping so I get to learn while I was making this resource. Maybe PBR classic clothing next???:thinking:???

PS: I do like seeing resources that you made, it helps me and others achieve what they need to do

This will actually end up solving one of the main limitations that I had going into this with my method, I had to rearrange the UVs to fit into a 1024x cube in order to stop the compression from happening (upscaling a template 2x would be over this size limit). Theoretically, the modern version of this would be like actually upscaling the current template to a 4k resolution (8x what we have right now at the size of like 585x559). It’d end up going over what we consider 4k which is 4096x, and then this “compression” or downscaling, whatever it is, gets applied there, causing a loss in quality.

In any case, there are some downsides with SurfaceAppearance even if you’re using a reasonable resolution. You end up getting image noise where random red, green, and blue spots start appearing all over the texture. You also get this weird “dithering” effect above a certain graphics level, it’d be nice if we could toggle this eventually? There are a bunch of others as well, of course..

As far as I know, the reason why this happens is that all the textures from the character are compressed into a texture sheet, and R6 has a really small one, it’s not been resized this whole time (probably not the easiest to do but it’s probably not happening). You can see this texture sheet stuff in action if you try saving a character as a 3D model or if you add a lot of accessories to your character, because they’re all stored on one image. That’s how I understand it, at least.

Agreed, I’d be upset if someone uploaded 4k clothing, especially if they’re not trying to optimize the UV map size by making their own. I don’t really know much about optimization, but one 4k texture is going to end up being a lot of memory, even if streamed out.. ://

And yeah, fair enough. I ended up being hung up on re-mapping the default R15 rig. I was drafting the devforum post and among PBRs, I was also thinking that custom rigged models for things like a trench coat or train skirt could be done. So many possibilities, they just all require a lot of setup so I don’t see them being realized anytime soon.

I’m not sure how against-the-rules this is, but if you’re interested and in the OSS community discord server or another, I’d send you the stuff I’ve gotten so far.

Side note, Blackhawk Rescue Mission 5 has an HD 2D layered clothing setup, but they don’t seem to have any of the issues I ran into with my method, no idea what they’re doing, and haven’t asked yet either.

The large amount of setup required to have clothing using SurfaceAppearance is exactly the main reason why I chose not to use it, It seemed extremely daunting to set up and that is even before I create a custom texture map. Textures on the other hand, has been around for a long time, not yet depreciated and has support for what I was after: ZIndex, Transparency, Colour and U/V offsets.

But then I cant use PBR because it requires SurfaceAppearance and Textures don’t support it :mad:

For all those weird graphical issues with Surface apperances seems to be ROBLOX’s poopoo way of optimisation, Sure the texture streaming beta would resolve some of the issues you (and I) had previously, and there cannot be perfect timing for such a beta to release.

Then, you get that one odd player with a 7+ year old Android, or a Celeron N2807 based computer, or those competitive players who play ROBLOX at graphics 1, Texture streaming is not supported and now they complain that their clothing looking like Escape from Lavender island.. Not quite but you get the point.

I believe Blackhawk uses something similar (if not identical) to what I implemented, considering that it uses Blocky for everything so they don’t need to worry about adding support for additional rigs or PBR. They’re part of a studio so I bet their implementation is much better than mine. (I made ACC V1 in only four days)

spoilers dont work

My discord is only for mutuals, Don’t go and find me elsewhere, just fire a devforum DM before the unlucky 18.

:cross_mark: ACC Banned?- Or is it

This morning I recieved a message stating that Advanced Classic Clothing has been removed from distribution aka a Content Distribution Disabled where i “misued Roblox systems”, which means that you cannot get or use ACC off the creator store… Or so I thought

You can still get and use the module into Studio. Not the previous 1.3 version but the latest V1.4 version. Even weirder, I recieved the message the EXACT minute I updated to the new V1.4 version.

All I did is create a new modulescript named r6Fix which creates a fake R6 rig just for Advanced Classic Clothing and moved the readme into a new modulescript _README_. I guess the section in r6Fix containing asset IDs for the meshParts set off the moderation systems, I never used AssetService, just Instance.new("SpecialMesh") for better compatibility in Client sided use.

Another could just be a Platform bug, since I checked and I can still purchase ACC on an alt, and import it into Studio with no problems at all, considering that it claims that I “misuesd Roblox systems” within 60 seconds after uploading.

I have to wait and see, maybe ROBLOX was just broken that day and it didn’t mean to send that to me, or it really got removed and it just didn’t apply yet, Only time will tell, I have already appealed with a written reason, no responce yet and let’s see what happens next.

If you still think I did something wrong, and you don’t trust my program, Here is the entire source code for r6Fix

r6Fix (WARNING: 221 Lines)
--[[
The goal for 1.4 was to bring support for meshed R6 rigs. It went so well that that I SCRAPPED IT!!!!
Turns out that some of the ROBLOX R6 meshes has their own UV mapping for Textures, which messes up ACC's own
UP mapping which results to messy rigs. in the devforum, I stated that meshed R6 is entirely unsupported.

Thankfully, better blocky R6 support is added in, which uses some community-sourced MeshParts with fully
functional UV mapping which means ACC is not needed at all! ACC is now used to manage Texture objects, change
texture properties, transparency and stuff like that.

From V1.4 onwards, the SpritemapR6_Blocky spritemap is entirely removed.
]]

local runservice = game:GetService("RunService")

local _R6_UNIFIED = false -- controlled by a setting where ACC would use one rig for both client and server.

function getRunInfo(isClient)
	if _R6_UNIFIED == true then
		return ""
	end
	isClient = isClient or runservice:IsClient()
	if isClient then
		return "Client"
	else
		return "Server"
	end
end


-- i went to the toolbox, searched up "r6 blocky mesh" and found these meshes from @gleb_zototar. These
-- are actually intended for R6 poses, it is completely UV mapped which means that there is no need for ACC to do the spritemapping.
local BlockyRig = {
	["LeftArm"] = "rbxassetid://82557091159947",
	["RightArm"] = "rbxassetid://131826949635623",
	["LeftLeg"] = "rbxassetid://109302786609504",
	["RightLeg"] = "rbxassetid://93063343924594",
	["Torso"] = "rbxassetid://76316612146587"
}

local r6_parts = {
	"LeftArm",
	"RightArm",
	"LeftLeg",
	"RightLeg",
	"Torso"
}

local r6_partNames = {
	["LeftArm"] = "Left Arm",
	["RightArm"] = "Right Arm",
	["LeftLeg"] = "Left Leg",
	["RightLeg"] = "Right Leg",
	["Torso"] = "Torso"
}

function createFakePart(fakePartName : string, meshId : string,character : Model, fakePartsFolder : Folder,fakeRigAlignment)
	local realPart = character:FindFirstChild(r6_partNames[fakePartName])
	local realName = r6_partNames[fakePartName]
	if not realPart then -- classic brickbattling may result to character losing their limbs
		warn("Cannot find part " .. r6_partNames[fakePartName])
		return
	else
		local fakePart = Instance.new("Part",fakePartsFolder)
		fakePart.Name = r6_partNames[fakePartName]
		fakePart.Size = realPart.Size
		fakePart.CanCollide = false
		fakePart.Transparency = realPart.Transparency
		realPart.Transparency = 1
		
		local specialMesh = Instance.new("SpecialMesh",fakePart)
		specialMesh.MeshId = meshId

		local attachment0, attachment1 = Instance.new("Attachment",realPart),Instance.new("Attachment",fakePart)
		attachment0.Name = "fakePartAttachment0"
		attachment1.Name = "fakePartAttachment1"
		
		local alignment = fakeRigAlignment[realName] or CFrame.new(0,0,0)
		
		local rigidConstraint = Instance.new("RigidConstraint",fakePart)
		rigidConstraint.Attachment0 = attachment0
		rigidConstraint.Attachment1 = attachment1
		
		rigidConstraint.Attachment0.CFrame = alignment
		
		return fakePart
	end
end

-- threshold 0  = Absolutely no R6 meshes, higher = lower detection threshold.
function containsMeshedRigs(character : Model,threshold : number)
	threshold = threshold or 0
	local found = table.clone(r6_partNames)
	local count = 0
	for _,characterMesh in pairs(character:GetChildren()) do
		if characterMesh:IsA("CharacterMesh") then
			local meshId = characterMesh.MeshId
			if meshId then
				local isAdornee = found[characterMesh.BodyPart.Name]
				if isAdornee then
					found[characterMesh.BodyPart.Name] = nil
					count +=1
				end
			end
		end
	end
	if count <= threshold then
		return false
	end
	return true
end

function queryCharacterMesh(character : Model,fakePartsFolder : Folder,fakeRigAlignment)
	local found = table.clone(r6_parts)

	for _,characterMesh in pairs(character:GetChildren()) do
		if characterMesh:IsA("CharacterMesh") then
			local meshId = characterMesh.MeshContent
			local bodyPartAdornee = characterMesh.BodyPart
			
			local duplicate = table.find(found,bodyPartAdornee.Name)
			
			if (meshId and bodyPartAdornee) and not(bodyPartAdornee == Enum.BodyPart.Head) and duplicate then
				warn("ACC WARNING: Found unsupported meshed rig for body part " .. bodyPartAdornee.Name)
				table.remove(found,duplicate)
			end
		end
	end
	
	for _,bodyPartName in found do
		local meshId = BlockyRig[bodyPartName]
		local fakePart = createFakePart(bodyPartName,meshId,character,fakePartsFolder,fakeRigAlignment)
	end
end

function BuildR6FakeParts(humanoid : Humanoid,fakeRigAlignment)
	local character = humanoid.Parent
	local fakePartsFolder = Instance.new("Folder",character)
	fakePartsFolder.Name = "FakeR6" .. getRunInfo()
	queryCharacterMesh(character,fakePartsFolder,fakeRigAlignment)
	return fakePartsFolder
end

function FindFakeRig(humanoid : Humanoid)
	local character = humanoid.Parent
	return character:FindFirstChild("FakeR6" .. getRunInfo())
end

function containsTextures(humanoid : Humanoid)
	local fakeRig = FindFakeRig(humanoid)
	local found = false
	if fakeRig then
		for _,partName in r6_partNames do
			local target = fakeRig:FindFirstChild(partName)
			if target and target:IsA("BasePart") then
				if found == false and target:FindFirstChildWhichIsA("Texture") then
					found = true
				end
			end
		end
	end
	return found
end

function DestroyFakeR6(humanoid : Humanoid)
	local fakeRig = FindFakeRig(humanoid)
	for _,partName in r6_partNames do
		local fakeBodyPartFound = fakeRig:FindFirstChild(partName)
		local realBodyPartFound = humanoid.Parent:FindFirstChild(partName)
		if fakeBodyPartFound and realBodyPartFound then
			realBodyPartFound.Transparency = fakeBodyPartFound.Transparency
			realBodyPartFound.Color = fakeBodyPartFound.Color
		end
		if fakeBodyPartFound then
			fakeBodyPartFound:Destroy()
		end
	end
	fakeRig:Destroy()
end

function setUnified(unified)
	if _R6_UNIFIED == false then
		_R6_UNIFIED = unified
	end
end

local r6Fix = {}
r6Fix.__index = r6Fix
-- Creates a new FakeR6 rig if it is not found, If it is already created (or R6Unified is false) then it returns an already existing rig.
r6Fix.new = function(humanoid : Humanoid,fakeRigAlignment)
	if not(humanoid.RigType == Enum.HumanoidRigType.R6 and humanoid.Parent:IsA("Model")) then
		error("This is not a valid R6 Model")
	end
	local fakePartsFolder = FindFakeRig(humanoid)
	if not fakePartsFolder then
		fakePartsFolder = BuildR6FakeParts(humanoid,fakeRigAlignment)
	end
	return fakePartsFolder
end

--[[
Detects all valid R6 CharacterMesh rigs and returns true if no CharacterMeshes are found within the threashold value.
threshold 0 = All limbs are not meshed and all are the Blocky rig.
threshold 6 = All limbs are meshed rigs.
threshold 2 = If there is only one meshed limb detected, it is not considered a meshed rig.
]]
r6Fix.containsMeshedRigs = containsMeshedRigs

-- Returns the fake rig if found, else returns nil,
r6Fix.FindFakeRig = FindFakeRig

-- Permanently sets unified mode on
r6Fix.setUnified = setUnified

-- Returns true if fake rig still contains texutres (from residual/old ACC instances or recently created ones.)
r6Fix.DoesFakeRigContainsTexutures = containsTextures

-- If exists, destroy the fake R6 rig.
r6Fix.Destroy = DestroyFakeR6

return r6Fix

EDIT: My appeal has been accepted, and the module is apparently back on the marketplace - :partying_face: ?

1 Like

Great module! This is genuinely what i expected Roblox layered clothing to be. Anyways, how do i fix this little line at edges? Since it makes the character look bad.

its either texture mip-mapping (level of detail) or the 2D clothing is one pixel too small/texture is scaled up improperly. Maybe try turning up the Level of detail in Studio or try the same clothing on the normal Shirt instance to see if it goes away
Yes it is annoying which is why I resorted to cover the entire clothing image with the base texture when I am creating my own clothing e.g:

Summary

TheNextElectron Fire Fighter jacket - Roblox

Or just create a border/make the entire background a solid colour:

Summary

Black Military Boots - Roblox

all of the above examples above fixes those annoying lines, aka Texture bleeding

I can’t tell if you are using R6, if it is then it might be distance based level of detail where Roblox would show a low quality version of the same texture in certain graphics settings or distances. The FakeR6 module I used should mitigate this because we all know how bad textures look on Accessories with R6.

2 Likes