How to do this for a character creation menu?

I’m wanting to achieve something similar to this character creation menu, but not exactly.

I am mainly wanting (1) thing from this menu, and that’s how to add a background to the creation menu, I just want a basic white one really. I have the character clone set up, but that’s just in the actual world, I’d like a basic background behind the character clone so I can go ahead and do the rest.

If you know how to do this or something similar, it would be really appreciated if you could help down below :slight_smile:


in the video, they probably have a image label for the background and then a viewport frame over it for the character

1 Like

Thanks for the response. I’ll go ahead and try this out and let you know if it works. :slight_smile:

Hello, This is fairly easy for me. So lets begin by making a gui. I’ll name it CustomizeCharacterGUI. Now that you have that, lets insert a frame as the background. You can use a image label, like @Ocipa said, if you want it to look nicer. Make another frame for all the skin colors. Now, in ReplicatedStorage, you need to put a remote event called ChangeSkinColor. We do this so all of your changes will be shown on everybody elses screen. Now, make another smaller frame for a color customizer. I’ll name this SkinColorFrame. Now that you have that, you can make a title. Customize that however you want. Now create one button and make its text nothing. Set it’s backgound color3 to the first skin color. Now, this is VERY important. Don’t duplicate it yet. Insert a LocalScript into that button, and type this code.


Now, you can duplicate the buttons. The players skin color will be set to the buttons backgroundcolor3, so be sure to set that! I’ll put a picture here. Make sure your setup looks somewhat like mine.

The picture may be a bit big, I have a 1920x1080 monitor. Anyways, insert a Script, not LocalScript into ServerScriptService. Inside this script, type

		for i,v in pairs(game.Workspace[player.Name]:GetChildren()) do
			if not v:IsA("Pants") then
				if not v:IsA("Shirt") then
					if not v:IsA("ShirtGraphic") then
						if not v:IsA("Humanoid") then
							if not v:IsA("Script") then
								if not v:IsA("LocalScript") then
									if not v:IsA("BodyColors") then
										if not v:IsA("Accessory") then
			v.Color = color

There we go. Now lets make a ViewportFrame, so we can show the player what they now look like. Inside this viewportframe, insert another LocalScript.


local RunService		= game:GetService('RunService')
local UserInputService	= game:GetService("UserInputService")

local instance,newRay	=,
local v2,v3,cf,udim2	=,,,
local insert,random,abs	= table.insert,math.random,math.abs

local Player			= game.Players.LocalPlayer
local Character			= Player.Character or Player.CharacterAdded:Wait()

--Basic setup
local ViewPort			= script.Parent

local Offset			= cf(0,1,-6)

--Create the viewport camera
local Camera		= instance("Camera")
	ViewPort.CurrentCamera	= Camera

local ValidClasses = {
	["MeshPart"] = true; ["Part"] = true; ["Accoutrement"] = true;
	["Pants"] = true; ["Shirt"] = true;
	["Humanoid"] = true;

local function RenderHumanoid(Model, Parent, MainModel)
	local ModelParts = Model:GetDescendants()
	for i=1, #ModelParts do
		local Part		= ModelParts[i]
		if ValidClasses[Part.ClassName] then
			local a			= Part.Archivable
				Part.Archivable	= true
			local RenderClone	= Part:Clone()
				Part.Archivable	= a
			if Part.ClassName == "MeshPart" or Part.ClassName == "Part" then
				PartUpdater = RunService.Heartbeat:Connect(function()
					if Part then
						RenderClone.CFrame = Part.CFrame
			elseif Part:IsA("Accoutrement") then
				PartUpdater = RunService.Heartbeat:Connect(function()
					if Part then
						if RenderClone.Handle then
							RenderClone.Handle.CFrame = Part.Handle.CFrame
			elseif Part.ClassName == "Humanoid" then
				--Disable all states. We only want it for clothing wrapping, not for stupid @$$ performance issues
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.FallingDown,			false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Running,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.RunningNoPhysics,	false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Climbing,			false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.StrafingNoPhysics,	false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Ragdoll,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.GettingUp,			false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Jumping,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Landed,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Flying,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Freefall,			false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Seated,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding,	false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Dead,				false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Swimming,			false)
				RenderClone:SetStateEnabled(Enum.HumanoidStateType.Physics,				false)
			RenderClone.Parent = Parent

--Let the world load before starting

local function Render()
	--Render the character
	local Char = instance("Model")
		Char.Name = ""
		Char.Parent = ViewPort

--Handle changes



CameraUpdater = RunService.Heartbeat:Connect(function()
	if Character.HumanoidRootPart then
		Camera.CFrame =  cf(Character.HumanoidRootPart.CFrame:toWorldSpace(Offset).p, Character.HumanoidRootPart.CFrame.p)

Credits to @boatbomber for this viewport script, I took it since it can render clothes. Well, thats pretty much it. If you want me to make a primary hair chooser I can do that, I’m not that good with Secondary and Primary hair Color, I don’t understand any of that nor do I understand coloring shirts and pants, but I can also do choosing faces.

Download file CharacterCreator.rbxl (29.5 KB)


Instead of running all those checks couldn’t you just do if v:IsA("BasePart") then?

1 Like

Yeah, true. The script is kinda messy.

Cheers, wasn’t expecting a full script but both methods work a charm. Thanks again.

No problem, like I said, I’ll do hair customizer and face customizer if you want.

Sure, that would be nice to see how others would do something like that so I can see if mine is correct afterwards. :slight_smile:

Okay, I’ll start working on it.

1 Like

Final Product: CharacterCreator.rbxl (33.6 KB)


Beautiful stuff, thanks again for this. It can definitely help me out. Would you be cool with me using some of this stuff in my final product?

1 Like

Yes, if you downloaded the final project, heres ANOTHER fixed one, because I forgot to clone the hats so you could only choose them once

CharacterCreator.rbxl (33.6 KB)


Awesome again. Really impressive to see a lot of help like this being shown. Appreciate it a lot. :smiley:

1 Like

Hey, just speaking on this again.

I’ve noticed that there’s a large spike in ping when keeping “Render()” on the heartbeat function.
This results in just all types of lag, and the ping can reach as high as 100+ making the game so unbearable for me.

Is this normal? I’ve noticed it also happens on your version too, maybe it’s just from my end?

Yeah, might want to do a while wait(0.3) do loop. It can happen if your device isn’t the best, and ain’t the best for performance. Erase that and do

while wait(0.3) do

1 Like

Yeah, I expected that would be the case and did some changes the night before. Appreciate the continued support on this, means a lot!

Don’t provide false information. The lag spike has nothing to do with a device being low quality, it is actually your script. Calling RenderHumanoid every heartbeat is extremely inefficient as the function has a for loop. This means every heartbeat, the function loops through the folder again, causing an extreme spike in lag. A lot of things in your script are really inefficient and could be simplified to work without the cost of client memory.

Just realized this thread is really old, my bad.

Lol I don’t feel like reading this but yeah don’t trust any of old worsts code