local Players = game:GetService("Players") local RunService = game:GetService("RunService") local LocalPlayer = Players.LocalPlayer local Camera = workspace.CurrentCamera local SETTINGS = { PurpleBase = Color3.fromRGB(160, 60, 255), PurpleHi = Color3.fromRGB(220, 120, 255), PurpleLo = Color3.fromRGB(90, 30, 180), PulseSpeed = 3, Thickness = 1.5, Transparency = 0.9, CircleEnabled = true, CircleRadius = 2.5, CircleThickness = 1.5, CircleSegments = 64, CircleYOffset = 3, HeadCircleEnabled = true, HeadCircleRadius = 0.6, HeadCircleThickness = 1.5, HeadCircleSegments = 48, HeadCircleYOffset = 0, R15Bones = { { "Head", "UpperTorso" }, { "UpperTorso", "LowerTorso" }, { "LowerTorso", "LeftUpperLeg" }, { "LeftUpperLeg", "LeftLowerLeg" }, { "LeftLowerLeg", "LeftFoot" }, { "LowerTorso", "RightUpperLeg" }, { "RightUpperLeg", "RightLowerLeg" }, { "RightLowerLeg", "RightFoot" }, { "UpperTorso", "LeftUpperArm" }, { "LeftUpperArm", "LeftLowerArm" }, { "LeftLowerArm", "LeftHand" }, { "UpperTorso", "RightUpperArm" }, { "RightUpperArm", "RightLowerArm" }, { "RightLowerArm", "RightHand" }, }, R6Bones = { { "Head", "Torso" }, { "Torso", "Left Arm" }, { "Torso", "Right Arm" }, { "Torso", "Left Leg" }, { "Torso", "Right Leg" }, }, TeamCheck = true, MaxDistance = 3000, HeadOffset = 0.5, } local function resolveRig(humanoid) if not humanoid then return nil end if humanoid.RigType == Enum.HumanoidRigType.R15 then return "R15" end if humanoid.RigType == Enum.HumanoidRigType.R6 then return "R6" end return nil end local function boneList(rig) return rig == "R6" and SETTINGS.R6Bones or SETTINGS.R15Bones end local function makeLine(thickness) local ok, line = pcall(function() return Drawing.new("Line") end) if ok then line.Thickness = thickness or SETTINGS.Thickness line.Transparency = SETTINGS.Transparency line.Visible = false return line end return nil end local function kill(obj) if not obj then return end pcall(function() obj.Visible = false obj:Remove() end) end local function pulseColor(t) local s = (math.sin(t * SETTINGS.PulseSpeed) + 1) * 0.5 local c = SETTINGS.PurpleLo:Lerp(SETTINGS.PurpleHi, s) return c:Lerp(SETTINGS.PurpleBase, 0.35) end local function buildRing(segments, thickness) local lines = {} for _ = 1, segments do local l = makeLine(thickness) if l then table.insert(lines, l) end end return lines end local function drawRing(lines, centerWorld, radius, segments, animColor, thickness, yOffset) local centerPos = centerWorld - Vector3.new(0, yOffset or 0, 0) local _, onC = Camera:WorldToViewportPoint(centerPos) if not onC then for _, line in ipairs(lines) do line.Visible = false end return end local projected = {} for i = 0, segments - 1 do local angle = (i / segments) * math.pi * 2 local worldPoint = centerPos + Vector3.new( math.cos(angle) * radius, 0, math.sin(angle) * radius ) local screenPoint, onP = Camera:WorldToViewportPoint(worldPoint) projected[i + 1] = { x = screenPoint.X, y = screenPoint.Y, onScreen = onP } end for i = 1, segments do local a = projected[i] local b = projected[i % segments + 1] local line = lines[i] if line then if a and b and a.onScreen and b.onScreen then line.From = Vector2.new(a.x, a.y) line.To = Vector2.new(b.x, b.y) line.Color = animColor line.Thickness = thickness line.Transparency = SETTINGS.Transparency line.Visible = true else line.Visible = false end end end end local function drawHeadRing(lines, headPos, animColor, segments, distOk) if not distOk then for _, line in ipairs(lines) do line.Visible = false end return end local pivot = headPos + Vector3.new(0, SETTINGS.HeadCircleYOffset, 0) local r = SETTINGS.HeadCircleRadius local projected = {} for i = 0, segments - 1 do local angle = (i / segments) * math.pi * 2 local offsetWorld = Vector3.new( math.cos(angle) * r, 0, math.sin(angle) * r ) local worldPoint = pivot + offsetWorld local screenPoint, onP = Camera:WorldToViewportPoint(worldPoint) projected[i + 1] = { x = screenPoint.X, y = screenPoint.Y, onScreen = onP } end for i = 1, segments do local a = projected[i] local b = projected[i % segments + 1] local line = lines[i] if line then if a and b and a.onScreen and b.onScreen then line.From = Vector2.new(a.x, a.y) line.To = Vector2.new(b.x, b.y) line.Color = animColor line.Thickness = SETTINGS.HeadCircleThickness line.Transparency = SETTINGS.Transparency line.Visible = true else line.Visible = false end end end end local rigs = setmetatable({}, { __mode = "k" }) local function cleanup(record) if not record then return end for _, entry in pairs(record.bones or {}) do kill(entry.line) end for _, line in ipairs(record.circleLines or {}) do kill(line) end for _, line in ipairs(record.headLines or {}) do kill(line) end end local function buildRecord(char, humanoid) local rig = resolveRig(humanoid) if not rig then return nil end local record = { rig = rig, bones = {} } for _ = 1, #boneList(rig) do table.insert(record.bones, { line = makeLine() }) end if SETTINGS.CircleEnabled then record.circleLines = buildRing(SETTINGS.CircleSegments, SETTINGS.CircleThickness) end if SETTINGS.HeadCircleEnabled then record.headLines = buildRing(SETTINGS.HeadCircleSegments, SETTINGS.HeadCircleThickness) end return record end local function ensureRig(record, char, humanoid) local rig = resolveRig(humanoid) if rig ~= record.rig then cleanup(record) local new = buildRecord(char, humanoid) if new then for k, v in pairs(new) do record[k] = v end end end end local renderConnection local elapsed = 0 local function startRender() if renderConnection then return end renderConnection = RunService.RenderStepped:Connect(function(dt) elapsed = elapsed + dt local animColor = pulseColor(elapsed) local myTeam = LocalPlayer.Team for player, record in pairs(rigs) do local char = player.Character local hum = char and char:FindFirstChildOfClass("Humanoid") local skip = false if not char or not hum or hum.Health <= 0 then skip = true elseif SETTINGS.TeamCheck and myTeam and player.Team == myTeam then skip = true end if skip then for _, entry in pairs(record.bones) do entry.line.Visible = false end if record.circleLines then for _, line in ipairs(record.circleLines) do line.Visible = false end end if record.headLines then for _, line in ipairs(record.headLines) do line.Visible = false end end else ensureRig(record, char, hum) local root = char:FindFirstChild("HumanoidRootPart") local myRoot = LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart") local distOk = true if root and myRoot then distOk = (root.Position - myRoot.Position).Magnitude <= SETTINGS.MaxDistance end local pairs_ = boneList(record.rig) for i, pair in ipairs(pairs_) do local entry = record.bones[i] if entry then local a = char:FindFirstChild(pair[1]) local b = char:FindFirstChild(pair[2]) if a and b and distOk then local pA = a.Position local pB = b.Position local isArm = pair[2] == "Left Arm" or pair[2] == "Right Arm" if isArm then pB = pB + Vector3.new(0, SETTINGS.HeadOffset, 0) end local sA, onA = Camera:WorldToViewportPoint(pA) local sB, onB = Camera:WorldToViewportPoint(pB) local l = entry.line l.Color = animColor l.Thickness = SETTINGS.Thickness l.Transparency = SETTINGS.Transparency l.From = Vector2.new(sA.X, sA.Y) l.To = Vector2.new(sB.X, sB.Y) l.Visible = onA and onB else entry.line.Visible = false end end end if root and record.circleLines then drawRing(record.circleLines, root.Position, SETTINGS.CircleRadius, SETTINGS.CircleSegments, animColor, SETTINGS.CircleThickness, SETTINGS.CircleYOffset) end local head = char:FindFirstChild("Head") if head and record.headLines then drawHeadRing(record.headLines, head.Position, animColor, SETTINGS.HeadCircleSegments, distOk) elseif record.headLines then for _, line in ipairs(record.headLines) do line.Visible = false end end end end end) end local function track(player) if player == LocalPlayer then return end if rigs[player] then return end rigs[player] = { rig = nil, bones = {} } local function attach(char) char = char or player.Character if not char then return end local hum = char:FindFirstChildOfClass("Humanoid") if not hum then task.spawn(function() hum = char:WaitForChild("Humanoid", 5) if hum then local full = buildRecord(char, hum) if full then for k, v in pairs(full) do rigs[player][k] = v end end end end) return end local full = buildRecord(char, hum) if full then for k, v in pairs(full) do rigs[player][k] = v end end end if player.Character then attach(player.Character) end player.CharacterAdded:Connect(attach) end local function untrack(player) local record = rigs[player] if record then cleanup(record) rigs[player] = nil end end for _, player in ipairs(Players:GetPlayers()) do track(player) end Players.PlayerAdded:Connect(track) Players.PlayerRemoving:Connect(untrack) startRender() _G.SkeletonESP_Unload = function() for player, record in pairs(rigs) do cleanup(record) end rigs = {} if renderConnection then renderConnection:Disconnect() renderConnection = nil end end print("[Skeleton ESP] loaded")