local SOURCE = [[ return function(INITIAL_SNAPSHOT, ENGINE_SOURCE) local Players = game:GetService("Players") local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local HttpService = game:GetService("HttpService") local player = Players.LocalPlayer local env = getgenv and getgenv() or _G local key = "LocalAvatarDisguise" if env.LocalAvatarReplicatedIdle then env.LocalAvatarReplicatedIdle:Stop() end if env[key] then env[key]:Stop() end local state = { connections = {}, avatarConnections = {}, hidden = {}, tracks = {}, version = 0, stopped = false, exportCount = 0 } env[key] = state function state:ClearAvatar() for _, c in ipairs(self.avatarConnections) do c:Disconnect() end table.clear(self.avatarConnections) if self.sharedTrack then pcall(function() self.sharedTrack:Stop(0.15) self.sharedTrack:Destroy() end) self.sharedTrack = nil end if self.sharedAnimation then self.sharedAnimation:Destroy() self.sharedAnimation = nil end for _, track in pairs(self.tracks) do pcall(function() track:Stop(0) track:Destroy() end) end table.clear(self.tracks) if self.model then self.model:Destroy() self.model = nil end for object, transparency in pairs(self.hidden) do if object.Parent then pcall(function() object.LocalTransparencyModifier = transparency end) end end table.clear(self.hidden) end function state:Clear() self:ClearAvatar() end function state:Stop() self.stopped = true self.version = self.version + 1 self.selectedSnapshot = nil self:ClearAvatar() for _, c in ipairs(self.connections) do c:Disconnect() end if self.gui then self.gui:Destroy() end if env[key] == self then env[key] = nil end end local function connect(signal, callback, avatar) local c = signal:Connect(callback) table.insert(avatar and state.avatarConnections or state.connections, c) return c end local function create(class, properties, parent) local object = Instance.new(class) for property, value in pairs(properties) do object[property] = value end object.Parent = parent return object end local function corner(object) create("UICorner", {CornerRadius = UDim.new(0, 9)}, object) end local gui = create("ScreenGui", { Name = "LocalAvatarChanger", ResetOnSpawn = false, DisplayOrder = 100, ZIndexBehavior = Enum.ZIndexBehavior.Sibling }, player:WaitForChild("PlayerGui")) state.gui = gui local window = create("Frame", { Size = UDim2.fromOffset(300, 293), Position = UDim2.new(0.5, -150, 0.12, 0), BackgroundColor3 = Color3.fromRGB(24, 25, 32), BorderSizePixel = 0, Active = true }, gui) corner(window) create("UIStroke", {Color = Color3.fromRGB(66, 68, 85)}, window) local title = create("TextLabel", { Size = UDim2.new(1, -52, 0, 42), Position = UDim2.fromOffset(14, 0), BackgroundTransparency = 1, Text = "Avatar Changer + Export", Active = true, Font = Enum.Font.GothamBold, TextSize = 15, TextColor3 = Color3.new(1, 1, 1), TextXAlignment = Enum.TextXAlignment.Left }, window) local close = create("TextButton", { Size = UDim2.fromOffset(32, 32), Position = UDim2.new(1, -38, 0, 5), BackgroundTransparency = 1, Text = "×", Font = Enum.Font.GothamBold, TextSize = 25, TextColor3 = Color3.fromRGB(185, 188, 205) }, window) local input = create("TextBox", { Size = UDim2.new(1, -28, 0, 42), Position = UDim2.fromOffset(14, 49), BackgroundColor3 = Color3.fromRGB(35, 37, 48), BorderSizePixel = 0, Text = INITIAL_SNAPSHOT and INITIAL_SNAPSHOT.Username or "2Sh0rt4y0u", PlaceholderText = "Roblox username", ClearTextOnFocus = false, Font = Enum.Font.Gotham, TextSize = 15, TextColor3 = Color3.new(1, 1, 1) }, window) corner(input) local function button(text, x, y, width, parent) local b = create("TextButton", { Size = UDim2.fromOffset(width or 131, 36), Position = UDim2.fromOffset(x, y), BackgroundColor3 = text == "Apply" and Color3.fromRGB(111, 83, 230) or Color3.fromRGB(47, 49, 63), BorderSizePixel = 0, Text = text, Font = Enum.Font.GothamBold, TextSize = 13, TextColor3 = Color3.new(1, 1, 1) }, parent or window) corner(b) return b end local applyButton = button("Apply", 14, 101) local restoreButton = button("Restore", 155, 101) local saveButton = button("Save script", 14, 146) local copyButton = button("Copy script", 155, 146) local idsButton = button("View all IDs", 14, 191, 272) local status = create("TextLabel", { Size = UDim2.new(1, -28, 0, 52), Position = UDim2.fromOffset(14, 234), BackgroundTransparency = 1, Text = "Apply an avatar to capture its IDs.", TextWrapped = true, Font = Enum.Font.Gotham, TextSize = 12, TextColor3 = Color3.fromRGB(180, 185, 200) }, window) local function setStatus(message, failed) if state.stopped then return end status.Text = message status.TextColor3 = failed and Color3.fromRGB(255, 130, 145) or Color3.fromRGB(180, 185, 200) end local dragging, dragStart, startPosition connect(title.InputBegan, function(event) if event.UserInputType == Enum.UserInputType.Touch or event.UserInputType == Enum.UserInputType.MouseButton1 then dragging, dragStart, startPosition = event, event.Position, window.Position end end) connect(UserInputService.InputChanged, function(event) if dragging and (event == dragging or ( dragging.UserInputType == Enum.UserInputType.MouseButton1 and event.UserInputType == Enum.UserInputType.MouseMovement)) then local delta = event.Position - dragStart window.Position = UDim2.new(startPosition.X.Scale, startPosition.X.Offset + delta.X, startPosition.Y.Scale, startPosition.Y.Offset + delta.Y) end end) connect(UserInputService.InputEnded, function(event) if event == dragging then dragging = nil end end) local preview = create("Frame", { Size = UDim2.new(0.9, 0, 0.8, 0), Position = UDim2.new(0.05, 0, 0.1, 0), BackgroundColor3 = Color3.fromRGB(24, 25, 32), BorderSizePixel = 0, Visible = false, ZIndex = 10 }, gui) corner(preview) local previewTitle = create("TextLabel", { Size = UDim2.new(1, -110, 0, 40), Position = UDim2.fromOffset(14, 0), BackgroundTransparency = 1, Text = "Export", Font = Enum.Font.GothamBold, TextSize = 15, TextColor3 = Color3.new(1, 1, 1), TextXAlignment = Enum.TextXAlignment.Left, ZIndex = 11 }, preview) local previewClose = button("Close", 0, 0, 80, preview) previewClose.Position = UDim2.new(1, -94, 0, 5) previewClose.ZIndex = 11 local previewScroll = create("ScrollingFrame", { Size = UDim2.new(1, -28, 1, -62), Position = UDim2.fromOffset(14, 48), BackgroundColor3 = Color3.fromRGB(15, 17, 23), BorderSizePixel = 0, ScrollBarThickness = 6, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, ZIndex = 11 }, preview) local previewText = create("TextBox", { Size = UDim2.new(1, -14, 0, 100), Position = UDim2.fromOffset(7, 5), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, Text = "", TextEditable = true, ClearTextOnFocus = false, MultiLine = true, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Font = Enum.Font.Code, TextSize = 13, TextColor3 = Color3.fromRGB(215, 220, 235), ZIndex = 12 }, previewScroll) connect(previewClose.Activated, function() preview.Visible = false end) local function showText(name, text) previewTitle.Text, previewText.Text = name, text previewScroll.CanvasPosition = Vector2.zero preview.Visible = true end local properties = { "BackAccessory", "BodyTypeScale", "ClimbAnimation", "DepthScale", "Face", "FaceAccessory", "FallAnimation", "FrontAccessory", "GraphicTShirt", "HairAccessory", "HatAccessory", "Head", "HeadColor", "HeadScale", "HeightScale", "IdleAnimation", "JumpAnimation", "LeftArm", "LeftArmColor", "LeftLeg", "LeftLegColor", "MoodAnimation", "NeckAccessory", "Pants", "ProportionScale", "RightArm", "RightArmColor", "RightLeg", "RightLegColor", "RunAnimation", "Shirt", "ShouldersAccessory", "StaticFacialAnimation", "SwimAnimation", "Torso", "TorsoColor", "UseAvatarSettings", "WaistAccessory", "WalkAnimation", "WidthScale" } local childProperties = { AccessoryDescription = {"AssetId", "AccessoryType", "IsLayered", "Order", "Position", "Rotation", "Scale", "Puffiness"}, BodyPartDescription = {"AssetId", "BodyPart", "Color", "HeadShape"} } local function pack(value) local kind = typeof(value) if kind == "Color3" then return {__type = "Color3", Values = {value.R, value.G, value.B}} elseif kind == "Vector3" then return {__type = "Vector3", Values = {value.X, value.Y, value.Z}} elseif kind == "EnumItem" then return {__type = "EnumItem", Enum = tostring(value.EnumType):gsub("^Enum%.", ""), Name = value.Name} elseif kind == "table" then local result = {} for k, item in pairs(value) do result[k] = pack(item) end return result elseif kind == "string" or kind == "number" or kind == "boolean" then return value end error("Unsupported snapshot value: " .. kind) end local function unpackValue(value) if type(value) ~= "table" then return value end if value.__type == "Color3" then return Color3.new(value.Values[1], value.Values[2], value.Values[3]) end if value.__type == "Vector3" then return Vector3.new(value.Values[1], value.Values[2], value.Values[3]) end if value.__type == "EnumItem" then return Enum[value.Enum][value.Name] end local result = {} for k, item in pairs(value) do result[k] = unpackValue(item) end return result end local function capture(description, username, userId, rigType) local snapshot = { Version = 1, Username = username, UserId = userId, RigType = rigType.Name, CapturedAt = os.date("!%Y-%m-%dT%H:%M:%SZ"), Properties = {}, Children = {}, Accessories = pack(description:GetAccessories(true)), Emotes = pack(description:GetEmotes()), EquippedEmotes = pack(description:GetEquippedEmotes()) } for _, property in ipairs(properties) do local ok, value = pcall(function() return description[property] end) if ok then snapshot.Properties[property] = pack(value) end end for _, child in ipairs(description:GetChildren()) do local list = childProperties[child.ClassName] if list then local record = {ClassName = child.ClassName, Properties = {}} for _, property in ipairs(list) do local ok, value = pcall(function() return child[property] end) if ok then record.Properties[property] = pack(value) end end table.insert(snapshot.Children, record) end end return snapshot end local function restoreDescription(snapshot) assert(snapshot.Version == 1, "Unsupported snapshot version.") local description = Instance.new("HumanoidDescription") for property, value in pairs(snapshot.Properties) do local ok, err = pcall(function() description[property] = unpackValue(value) end) if not ok then warn("Snapshot property " .. property .. ": " .. tostring(err)) end end description:SetAccessories(unpackValue(snapshot.Accessories or {}), true) description:SetEmotes(unpackValue(snapshot.Emotes or {})) description:SetEquippedEmotes(unpackValue(snapshot.EquippedEmotes or {})) local used = {} for _, record in ipairs(snapshot.Children or {}) do local p = record.Properties local selected for _, child in ipairs(description:GetChildren()) do if not used[child] and child.ClassName == record.ClassName then if record.ClassName == "AccessoryDescription" then if child.AssetId == p.AssetId and child.AccessoryType == unpackValue(p.AccessoryType) then selected = child end elseif record.ClassName == "BodyPartDescription" then if child.BodyPart == unpackValue(p.BodyPart) then selected = child end end if selected then break end end end if not selected then selected = Instance.new(record.ClassName) end used[selected] = true for property, value in pairs(p) do local ok, err = pcall(function() selected[property] = unpackValue(value) end) if not ok then warn("Snapshot child " .. property .. ": " .. tostring(err)) end end selected.Parent = description end return description end local defaults = { R15 = {idle = 507766666, walk = 507777826, run = 507767714, jump = 507765000, fall = 507767968, climb = 507765644, swim = 507784897, swimidle = 507785072, sit = 2506281703}, R6 = {idle = 180435571, walk = 180426354, run = 180426354, jump = 125750702, fall = 180436148, climb = 180436334, sit = 178130996} } local animationProperties = {idle = "IdleAnimation", walk = "WalkAnimation", run = "RunAnimation", jump = "JumpAnimation", fall = "FallAnimation", climb = "ClimbAnimation", swim = "SwimAnimation"} local function owningPart(attachment) local parent = attachment and attachment.Parent while parent and not parent:IsA("BasePart") do parent = parent.Parent end return parent end local function attachmentOffset(part, attachment) if attachment.Parent == part then return attachment.CFrame end return part.CFrame:ToObjectSpace(attachment.WorldCFrame) end local function bottomY(frame, size) return frame.Position.Y - (math.abs(frame.RightVector.Y) * size.X + math.abs(frame.UpVector.Y) * size.Y + math.abs(frame.LookVector.Y) * size.Z) * 0.5 end local function loadAvatar(target) if type(target) == "string" then target = target:match("^%s*(.-)%s*$"):gsub("^@", "") if target == "" then setStatus("Enter a Roblox username.", true) return end end state.version = state.version + 1 local version = state.version state.selectedSnapshot = nil state:ClearAvatar() setStatus(type(target) == "table" and "Loading saved avatar..." or "Loading @" .. target .. "...") local model, description local function cancelled() return state.stopped or version ~= state.version end local ok, err = pcall(function() local snapshot, rigType if type(target) == "table" then snapshot = target description = restoreDescription(snapshot) rigType = Enum.HumanoidRigType[snapshot.RigType] else local userId = Players:GetUserIdFromNameAsync(target) description = Players:GetHumanoidDescriptionFromUserIdAsync(userId) rigType = Enum.HumanoidRigType.R15 local infoOk, info = pcall(function() return Players:GetCharacterAppearanceInfoAsync(userId) end) if infoOk and info.playerAvatarType == "R6" then rigType = Enum.HumanoidRigType.R6 end snapshot = capture(description, target, userId, rigType) end if cancelled() then return end local character = player.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") local root = character and character:FindFirstChild("HumanoidRootPart") assert(humanoid and root, "Your character is not ready.") model = Players:CreateHumanoidModelFromDescriptionAsync(description, rigType) if cancelled() or player.Character ~= character then model:Destroy() model = nil return end local visualHumanoid = model:FindFirstChildOfClass("Humanoid") local visualRoot = model:FindFirstChild("HumanoidRootPart") assert(visualHumanoid and visualRoot, "Avatar model is incomplete.") model.Name = "LocalAvatar_" .. snapshot.Username visualHumanoid.EvaluateStateMachine = false visualHumanoid.AutoRotate = false visualHumanoid.RequiresNeck = false visualHumanoid.BreakJointsOnDeath = false visualHumanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None local parts, bodyParts, feet, graph, headParts, accessories, animationIds = {}, {}, {}, {}, {}, {}, {} local animate = model:FindFirstChild("Animate") for name, fallback in pairs(defaults[rigType.Name]) do local property = animationProperties[name] local id = property and description[property] or 0 animationIds[name] = "rbxassetid://" .. tostring(id > 0 and id or fallback) local folder = animate and animate:FindFirstChild(name) local animation = folder and folder:FindFirstChildWhichIsA("Animation", true) if animation and animation.AnimationId ~= "" then animationIds[name] = animation.AnimationId end if snapshot.AnimationIds and snapshot.AnimationIds[name] then animationIds[name] = snapshot.AnimationIds[name] end end for _, object in ipairs(model:GetDescendants()) do if object:IsA("BaseScript") then object:Destroy() elseif object:IsA("BasePart") then object.Anchored, object.CanCollide, object.CanTouch, object.CanQuery = true, false, false, false object.Massless = true table.insert(parts, object) if object.Parent == model then table.insert(bodyParts, object) graph[object] = {} if object.Name == "LeftFoot" or object.Name == "RightFoot" or object.Name == "Left Leg" or object.Name == "Right Leg" then table.insert(feet, object) elseif object.Name == "Head" then headParts[object] = true end end end end visualRoot.Transparency = 1 local function addJoint(a, b, c0, c1, joint) if not graph[a] or not graph[b] then return end local edge = {a = a, b = b, c0 = c0, c1 = c1, joint = joint} table.insert(graph[a], edge) table.insert(graph[b], edge) end for _, joint in ipairs(model:GetDescendants()) do if joint:IsA("Motor6D") then addJoint(joint.Part0, joint.Part1, joint.C0, joint.C1, joint) elseif joint:IsA("AnimationConstraint") then local a, b = owningPart(joint.Attachment0), owningPart(joint.Attachment1) if graph[a] and graph[b] then joint.IsKinematic = true addJoint(a, b, attachmentOffset(a, joint.Attachment0), attachmentOffset(b, joint.Attachment1), joint) end end end local function solve(frame, animated) local poses, queue, index = {[visualRoot] = frame}, {visualRoot}, 1 while index <= #queue do local part = queue[index] index = index + 1 for _, edge in ipairs(graph[part]) do local forward = part == edge.a local other = forward and edge.b or edge.a if not poses[other] then local transform = animated and edge.joint.Transform or CFrame.identity local relative = edge.c0 * transform * edge.c1:Inverse() poses[other] = poses[part] * (forward and relative or relative:Inverse()) table.insert(queue, other) end end end return poses end local neutral = solve(CFrame.identity, false) if rigType == Enum.HumanoidRigType.R15 then local groups = {} for _, part in ipairs(bodyParts) do for _, attachment in ipairs(part:GetChildren()) do if attachment:IsA("Attachment") and attachment.Name:match("RigAttachment$") then groups[attachment.Name] = groups[attachment.Name] or {} table.insert(groups[attachment.Name], attachment) end end end for _ = 1, #bodyParts do local repaired = false for name, group in pairs(groups) do for _, a0 in ipairs(group) do if neutral[a0.Parent] then for _, a1 in ipairs(group) do if a0.Parent ~= a1.Parent and not neutral[a1.Parent] then local motor = Instance.new("Motor6D") motor.Name = name:gsub("RigAttachment$", "") motor.Part0, motor.Part1, motor.C0, motor.C1 = a0.Parent, a1.Parent, a0.CFrame, a1.CFrame motor.Parent = a1.Parent addJoint(motor.Part0, motor.Part1, motor.C0, motor.C1, motor) repaired = true neutral = solve(CFrame.identity, false) end end end end end if not repaired then break end end end for _, part in ipairs(bodyParts) do assert(neutral[part], "Missing rig connection: " .. part.Name) end for _, accessory in ipairs(model:GetChildren()) do if accessory:IsA("Accessory") then local handle = accessory:FindFirstChild("Handle") local targetPart, offset if handle and handle:IsA("BasePart") then for _, attachment in ipairs(handle:GetChildren()) do if attachment:IsA("Attachment") then for _, body in ipairs(bodyParts) do local match = body:FindFirstChild(attachment.Name) if match and match:IsA("Attachment") then targetPart, offset = body, match.CFrame * attachment.CFrame:Inverse() break end end end if targetPart then break end end if not targetPart then local weld = handle:FindFirstChild("AccessoryWeld") if weld and weld:IsA("Weld") then if weld.Part0 == handle and graph[weld.Part1] then targetPart, offset = weld.Part1, weld.C1 * weld.C0:Inverse() elseif weld.Part1 == handle and graph[weld.Part0] then targetPart, offset = weld.Part0, weld.C0 * weld.C1:Inverse() end end end for _, part in ipairs(accessory:GetDescendants()) do if part:IsA("BasePart") then if targetPart then table.insert(accessories, {part = part, target = targetPart, offset = offset * handle.CFrame:ToObjectSpace(part.CFrame)}) if targetPart.Name == "Head" then headParts[part] = true end else part.Transparency = 1 end end end end end end local lowest = math.huge for _, foot in ipairs(feet) do lowest = math.min(lowest, bottomY(neutral[foot], foot.Size)) end local visualHeight = lowest < math.huge and -lowest or visualHumanoid.HipHeight + visualRoot.Size.Y / 2 local originalHeight = humanoid.HipHeight + root.Size.Y / 2 if humanoid.RigType == Enum.HumanoidRigType.R6 then local leg = character:FindFirstChild("Left Leg") originalHeight = originalHeight + (leg and leg.Size.Y or 2) end local baseOffset = visualHeight - originalHeight local rayParams = RaycastParams.new() rayParams.FilterType = Enum.RaycastFilterType.Exclude rayParams.FilterDescendantsInstances = {character, model} rayParams.IgnoreWater, rayParams.RespectCanCollide = true, true local function draw(grounded) local look = root.CFrame.LookVector local direction = Vector3.new(look.X, 0, look.Z) if direction.Magnitude < 0.001 then direction = Vector3.new(0, 0, -1) end local position = root.Position + Vector3.new(0, baseOffset, 0) local poses = solve(CFrame.lookAt(position, position + direction.Unit), true) local correction = 0 if grounded then local hit = workspace:Raycast(root.Position + Vector3.new(0, 1, 0), Vector3.new(0, -(originalHeight + 5), 0), rayParams) if hit then local bottom = math.huge for _, foot in ipairs(feet) do bottom = math.min(bottom, bottomY(poses[foot], foot.Size)) end if bottom < math.huge then correction = hit.Position.Y + 0.025 - bottom end end end local shift = Vector3.new(0, correction, 0) for _, part in ipairs(bodyParts) do part.CFrame = poses[part] + shift end for _, binding in ipairs(accessories) do binding.part.CFrame = poses[binding.target] * binding.offset + shift end end draw(false) model.Parent = workspace state.model = model local animator = visualHumanoid:FindFirstChildOfClass("Animator") if not animator then animator = Instance.new("Animator") animator.Parent = visualHumanoid end for name, id in pairs(animationIds) do local animation = Instance.new("Animation") animation.Name, animation.AnimationId, animation.Parent = name, id, model local trackOk, track = pcall(function() return animator:LoadAnimation(animation) end) if trackOk then track.Looped = name ~= "jump" track.Priority = name == "idle" and Enum.AnimationPriority.Idle or Enum.AnimationPriority.Movement state.tracks[name] = track else warn("Unable to load animation " .. name .. ": " .. tostring(track)) end end local sharedStatus = "Shared idle unavailable" local originalAnimator = humanoid:FindFirstChildOfClass("Animator") if humanoid.RigType ~= visualHumanoid.RigType then sharedStatus = "Shared idle: R6/R15 mismatch" elseif originalAnimator and state.tracks.idle then local animation = Instance.new("Animation") animation.Name, animation.AnimationId, animation.Parent = "AvatarSharedIdle", animationIds.idle, character state.sharedAnimation = animation local sharedOk, track = pcall(function() return originalAnimator:LoadAnimation(animation) end) if sharedOk then track.Looped, track.Priority = true, Enum.AnimationPriority.Action state.sharedTrack, sharedStatus = track, "Shared idle enabled" else animation:Destroy() state.sharedAnimation = nil warn(tostring(track)) end end local currentAnimation local function pauseShared() if state.sharedTrack and state.sharedTrack.IsPlaying then state.sharedTrack:Stop(0.15) end end local function play(name, speed) if not state.tracks[name] then name = "idle" end local track = state.tracks[name] if not track then return end if currentAnimation ~= name then local previous = currentAnimation and state.tracks[currentAnimation] if previous then previous:Stop(0.15) end currentAnimation = name track:Play(0.15) elseif track.Looped and not track.IsPlaying then track:Play(0.15) end track:AdjustSpeed(speed or 1) end local function hide(object) if object:IsA("BasePart") or object:IsA("Decal") then if state.hidden[object] == nil then state.hidden[object] = object.LocalTransparencyModifier end object.LocalTransparencyModifier = 1 end end for _, object in ipairs(character:GetDescendants()) do hide(object) end connect(character.DescendantAdded, hide, true) connect(RunService.PreSimulation, function() for _, part in ipairs(parts) do if part.Parent then part.Anchored, part.CanCollide, part.CanTouch, part.CanQuery = true, false, false, false end end end, true) play("idle") connect(RunService.PreRender, function() if not root.Parent or not model.Parent or player.Character ~= character then pauseShared() return end local movementState = humanoid:GetState() local grounded = humanoid.FloorMaterial ~= Enum.Material.Air and not humanoid.Sit and movementState ~= Enum.HumanoidStateType.Jumping and movementState ~= Enum.HumanoidStateType.Freefall and movementState ~= Enum.HumanoidStateType.Climbing and movementState ~= Enum.HumanoidStateType.Swimming draw(grounded) for object in pairs(state.hidden) do if object.Parent then object.LocalTransparencyModifier = 1 end end local camera, head = workspace.CurrentCamera, character:FindFirstChild("Head") local firstPerson = camera and head and (camera.CFrame.Position - head.Position).Magnitude < 1 for part in pairs(headParts) do part.LocalTransparencyModifier = firstPerson and 1 or 0 end if humanoid.Health <= 0 then pauseShared() for _, track in pairs(state.tracks) do if track.IsPlaying then track:Stop(0.15) end end return end local velocity = root.AssemblyLinearVelocity local speed = Vector3.new(velocity.X, 0, velocity.Z).Magnitude local moving = humanoid.MoveDirection.Magnitude > 0.05 if humanoid.Sit then play("sit") elseif movementState == Enum.HumanoidStateType.Jumping then play("jump") elseif movementState == Enum.HumanoidStateType.Freefall then play("fall") elseif movementState == Enum.HumanoidStateType.Climbing then play("climb", math.clamp(math.abs(velocity.Y) / 5, 0, 3)) elseif movementState == Enum.HumanoidStateType.Swimming then if velocity.Magnitude > 1 then play("swim", math.clamp(velocity.Magnitude / 10, 0.2, 3)) else play("swimidle") end elseif moving and speed > 0.5 then if speed > 10 then play("run", math.clamp(speed / 16, 0.2, 3)) else play("walk", math.clamp(speed / 8, 0.2, 3)) end else play("idle") end local standing = movementState == Enum.HumanoidStateType.Running or movementState == Enum.HumanoidStateType.RunningNoPhysics or movementState == Enum.HumanoidStateType.Landed local localIdle = state.tracks.idle if state.sharedTrack and localIdle and localIdle.IsPlaying and grounded and standing and not humanoid.PlatformStand and not moving and speed < 0.75 and currentAnimation == "idle" then local shared = state.sharedTrack if not shared.IsPlaying then shared:Play(0.2, 1, 1) if shared.Length > 0 then shared.TimePosition = localIdle.TimePosition % shared.Length end end shared:AdjustSpeed(localIdle.Speed) else pauseShared() end end, true) snapshot.AnimationIds = animationIds state.selectedSnapshot = snapshot input.Text = snapshot.Username setStatus("Applied @" .. snapshot.Username .. " • " .. tostring(#snapshot.Accessories) .. " accessories captured\n" .. sharedStatus) end) if description then description:Destroy() end if not ok then if model then model:Destroy() end if not cancelled() then state:ClearAvatar() state.selectedSnapshot = nil setStatus(tostring(err):match("[^\n]+$") or "Loading failed.", true) end warn("Avatar changer: " .. tostring(err)) end end local function longQuote(text) local equals = "" while (text .. "]" .. equals .. "]"):find("]" .. equals .. "]", 1, true) ~= #text + 1 do equals = equals .. "=" end return "[" .. equals .. "[\n" .. text .. "]" .. equals .. "]" end local function exportScript() local snapshot = state.selectedSnapshot if not snapshot then setStatus("Apply an avatar before exporting.", true) return end local json = HttpService:JSONEncode(snapshot) return "local SNAPSHOT_JSON = " .. longQuote(json) .. "\nlocal SOURCE = " .. longQuote(ENGINE_SOURCE) .. "\nlocal compile = assert(loadstring, 'This script requires loadstring.')" .. "\nlocal run = assert(compile(SOURCE))()" .. "\nrun(game:GetService('HttpService'):JSONDecode(SNAPSHOT_JSON), SOURCE)\n" end local function idReport(snapshot) local lines = {"Username: " .. snapshot.Username, "UserId: " .. tostring(snapshot.UserId), "Rig: " .. snapshot.RigType, "Captured: " .. snapshot.CapturedAt, "", "BODY / CLOTHING / ANIMATION IDS"} local idProperties = {"Head", "Torso", "LeftArm", "RightArm", "LeftLeg", "RightLeg", "Face", "Shirt", "Pants", "GraphicTShirt", "IdleAnimation", "WalkAnimation", "RunAnimation", "JumpAnimation", "FallAnimation", "ClimbAnimation", "SwimAnimation", "MoodAnimation"} for _, name in ipairs(idProperties) do table.insert(lines, name .. ": " .. tostring(snapshot.Properties[name] or 0)) end table.insert(lines, "\nACCESSORIES: " .. tostring(#snapshot.Accessories)) for index, entry in ipairs(unpackValue(snapshot.Accessories)) do table.insert(lines, tostring(index) .. ". " .. tostring(entry.AccessoryType) .. " | AssetId: " .. tostring(entry.AssetId) .. " | Layered: " .. tostring(entry.IsLayered) .. " | Order: " .. tostring(entry.Order or 0)) end table.insert(lines, "\nRESOLVED PLAYBACK ANIMATIONS") local names = {} for name in pairs(snapshot.AnimationIds or {}) do table.insert(names, name) end table.sort(names) for _, name in ipairs(names) do table.insert(lines, name .. ": " .. snapshot.AnimationIds[name]) end table.insert(lines, "\nEMOTES") local emotes = unpackValue(snapshot.Emotes or {}) local emoteNames = {} for name in pairs(emotes) do table.insert(emoteNames, name) end table.sort(emoteNames) for _, name in ipairs(emoteNames) do local ids = {} for _, id in ipairs(emotes[name]) do table.insert(ids, tostring(id)) end table.insert(lines, name .. ": " .. table.concat(ids, ", ")) end table.insert(lines, "\nFULL SNAPSHOT JSON\n" .. HttpService:JSONEncode(snapshot)) return table.concat(lines, "\n") end connect(applyButton.Activated, function() task.spawn(loadAvatar, input.Text) end) connect(input.FocusLost, function(enterPressed) if enterPressed then task.spawn(loadAvatar, input.Text) end end) connect(restoreButton.Activated, function() state.version = state.version + 1 state.selectedSnapshot = nil state:ClearAvatar() setStatus("Original appearance and animations restored.") end) connect(close.Activated, function() state:Stop() end) connect(idsButton.Activated, function() if not state.selectedSnapshot then setStatus("Apply an avatar first.", true) return end showText("Avatar IDs", idReport(state.selectedSnapshot)) end) connect(copyButton.Activated, function() local scriptText = exportScript() if not scriptText then return end local clipboard = setclipboard or toclipboard if type(clipboard) == "function" then local ok = pcall(clipboard, scriptText) if ok then setStatus("Complete saved-avatar script copied.") return end end showText("Select and copy this script", scriptText) setStatus("Clipboard unavailable. Copy from the export window.") end) connect(saveButton.Activated, function() local scriptText = exportScript() if not scriptText then return end if type(writefile) ~= "function" then showText("Copy and save as .lua", scriptText) setStatus("File saving unavailable. Export opened for copying.") return end state.exportCount = state.exportCount + 1 local s = state.selectedSnapshot local name = "Avatar_" .. s.Username:gsub("[^%w_]", "_") .. "_" .. tostring(s.UserId) .. "_" .. tostring(os.time()) .. "_" .. tostring(state.exportCount) .. ".lua" local path = name if type(makefolder) == "function" then local exists = type(isfolder) == "function" and isfolder("avatar_exports") if exists or pcall(makefolder, "avatar_exports") then path = "avatar_exports/" .. name end end local ok, err = pcall(writefile, path, scriptText) if not ok and path ~= name then path = name ok, err = pcall(writefile, path, scriptText) end if ok then setStatus("Saved: " .. path) else showText("Copy and save as .lua", scriptText) setStatus("Save failed. Export opened for copying.", true) warn(tostring(err)) end end) connect(player.CharacterAdded, function(character) local snapshot = state.selectedSnapshot state.version = state.version + 1 local version = state.version state:ClearAvatar() if snapshot then task.spawn(function() local humanoid = character:WaitForChild("Humanoid", 15) local root = character:WaitForChild("HumanoidRootPart", 15) if humanoid and root and not state.stopped and state.version == version and player.Character == character then loadAvatar(snapshot) end end) end end) if INITIAL_SNAPSHOT then task.spawn(function() local character = player.Character or player.CharacterAdded:Wait() local humanoid = character:WaitForChild("Humanoid", 15) local root = character:WaitForChild("HumanoidRootPart", 15) if humanoid and root and not state.stopped and state.version == 0 then loadAvatar(INITIAL_SNAPSHOT) end end) end end ]] local compile = assert(loadstring, "This script requires loadstring.") local run = assert(compile(SOURCE))() run(nil, SOURCE)