local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local CoreGui = game:GetService("CoreGui")
local UIS = game:GetService("UserInputService")
local LocalPlayer = Players.LocalPlayer
local Camera = workspace.CurrentCamera
-- =====================
-- CONFIG
-- =====================
local Config = {
Enabled = true,
Boxes = true,
NameTags = true,
HealthBar = true,
Distance = true,
Tracers = true,
TeamCheck = true,
VisibilityCheck = true,
ColorVisible = Color3.fromRGB(180, 200, 255), -- ghost blue
ColorHidden = Color3.fromRGB(80, 80, 120), -- dim ghost
ColorHealthHi = Color3.fromRGB(140, 255, 180), -- pale green
ColorHealthLo = Color3.fromRGB(255, 100, 120), -- pale red
ColorTracer = Color3.fromRGB(160, 180, 255),
ColorBox = Color3.fromRGB(180, 200, 255),
MaxDistance = 1000,
TracerOrigin = "Bottom",
BoxThickness = 1,
TextSize = 13,
}
-- Ghost UI palette
local Ghost = {
bg = Color3.fromRGB(8, 8, 14),
surface = Color3.fromRGB(14, 14, 22),
surfaceHi = Color3.fromRGB(20, 20, 32),
border = Color3.fromRGB(50, 55, 90),
accent = Color3.fromRGB(120, 140, 220),
accentDim = Color3.fromRGB(60, 70, 130),
accentGlow = Color3.fromRGB(160, 180, 255),
textPrimary = Color3.fromRGB(200, 210, 240),
textMuted = Color3.fromRGB(100, 110, 150),
textDim = Color3.fromRGB(60, 65, 100),
onGreen = Color3.fromRGB(80, 200, 140),
onGreenDim = Color3.fromRGB(30, 80, 60),
offGray = Color3.fromRGB(28, 28, 40),
danger = Color3.fromRGB(200, 80, 100),
}
-- =====================
-- ESP STORAGE
-- =====================
local ESPObjects = {}
-- =====================
-- DRAWING HELPERS
-- =====================
local function newDrawing(type, props)
local d = Drawing.new(type)
for k, v in pairs(props) do d[k] = v end
return d
end
local function createESP(player)
if ESPObjects[player] then return end
local obj = {}
obj.BoxLines = {}
for i = 1, 4 do
obj.BoxLines[i] = newDrawing("Line", {
Visible = false,
Color = Config.ColorBox,
Thickness = Config.BoxThickness,
Transparency = 1,
ZIndex = 2,
})
end
-- Corner accents (4 corners x 2 lines = 8)
obj.Corners = {}
for i = 1, 8 do
obj.Corners[i] = newDrawing("Line", {
Visible = false,
Color = Config.ColorBox,
Thickness = 2,
Transparency = 1,
ZIndex = 3,
})
end
obj.NameTag = newDrawing("Text", {
Visible = false,
Color = Ghost.textPrimary,
Size = Config.TextSize,
Center = true,
Outline = true,
OutlineColor = Color3.fromRGB(0, 0, 0),
ZIndex = 4,
})
obj.DistLabel = newDrawing("Text", {
Visible = false,
Color = Ghost.textMuted,
Size = Config.TextSize - 2,
Center = true,
Outline = true,
OutlineColor = Color3.fromRGB(0, 0, 0),
ZIndex = 4,
})
obj.HealthBarBG = newDrawing("Line", {
Visible = false,
Color = Color3.fromRGB(0, 0, 0),
Thickness = 4,
Transparency = 1,
ZIndex = 2,
})
obj.HealthBar = newDrawing("Line", {
Visible = false,
Color = Config.ColorHealthHi,
Thickness = 3,
Transparency = 1,
ZIndex = 3,
})
obj.Tracer = newDrawing("Line", {
Visible = false,
Color = Config.ColorTracer,
Thickness = 1,
Transparency = 0.6,
ZIndex = 1,
})
ESPObjects[player] = obj
end
local function removeESP(player)
local obj = ESPObjects[player]
if not obj then return end
for _, line in pairs(obj.BoxLines) do line:Remove() end
for _, line in pairs(obj.Corners) do line:Remove() end
obj.NameTag:Remove()
obj.DistLabel:Remove()
obj.HealthBarBG:Remove()
obj.HealthBar:Remove()
obj.Tracer:Remove()
ESPObjects[player] = nil
end
local function hideESP(obj)
for _, line in pairs(obj.BoxLines) do line.Visible = false end
for _, line in pairs(obj.Corners) do line.Visible = false end
obj.NameTag.Visible = false
obj.DistLabel.Visible = false
obj.HealthBarBG.Visible = false
obj.HealthBar.Visible = false
obj.Tracer.Visible = false
end
-- =====================
-- VISIBILITY CHECK
-- =====================
local function isVisible(character, rootPart)
if not Config.VisibilityCheck then return true end
local origin = Camera.CFrame.Position
local direction = rootPart.Position - origin
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {character, LocalPlayer.Character}
local result = workspace:Raycast(origin, direction, params)
return result == nil
end
-- =====================
-- TEAM CHECK
-- =====================
local function isSameTeam(player)
if not Config.TeamCheck then return false end
if not LocalPlayer.Team or not player.Team then return false end
return LocalPlayer.Team == player.Team
end
-- =====================
-- HEALTH COLOR
-- =====================
local function healthColor(pct)
return Config.ColorHealthLo:Lerp(Config.ColorHealthHi, pct)
end
-- =====================
-- BOUNDING BOX
-- =====================
local function getCharacterBounds(character)
local parts = {}
for _, p in pairs(character:GetDescendants()) do
if p:IsA("BasePart") then
table.insert(parts, p)
end
end
if #parts == 0 then return nil end
local minX, minY, minZ = math.huge, math.huge, math.huge
local maxX, maxY, maxZ = -math.huge, -math.huge, -math.huge
for _, p in pairs(parts) do
local pos = p.Position
local s = p.Size / 2
minX = math.min(minX, pos.X - s.X)
minY = math.min(minY, pos.Y - s.Y)
minZ = math.min(minZ, pos.Z - s.Z)
maxX = math.max(maxX, pos.X + s.X)
maxY = math.max(maxY, pos.Y + s.Y)
maxZ = math.max(maxZ, pos.Z + s.Z)
end
local corners3D = {
Vector3.new(minX, minY, minZ), Vector3.new(minX, minY, maxZ),
Vector3.new(minX, maxY, minZ), Vector3.new(minX, maxY, maxZ),
Vector3.new(maxX, minY, minZ), Vector3.new(maxX, minY, maxZ),
Vector3.new(maxX, maxY, minZ), Vector3.new(maxX, maxY, maxZ),
}
local screenPoints = {}
for _, corner in pairs(corners3D) do
local sp, onScreen = Camera:WorldToViewportPoint(corner)
if onScreen then
table.insert(screenPoints, Vector2.new(sp.X, sp.Y))
end
end
if #screenPoints < 2 then return nil end
local sMinX, sMinY = math.huge, math.huge
local sMaxX, sMaxY = -math.huge, -math.huge
for _, p in pairs(screenPoints) do
sMinX = math.min(sMinX, p.X)
sMinY = math.min(sMinY, p.Y)
sMaxX = math.max(sMaxX, p.X)
sMaxY = math.max(sMaxY, p.Y)
end
return {
topLeft = Vector2.new(sMinX, sMinY),
topRight = Vector2.new(sMaxX, sMinY),
bottomLeft = Vector2.new(sMinX, sMaxY),
bottomRight = Vector2.new(sMaxX, sMaxY),
width = sMaxX - sMinX,
height = sMaxY - sMinY,
centerX = sMinX + (sMaxX - sMinX) / 2,
}
end
-- =====================
-- CORNER BOX HELPER
-- =====================
local function drawCornerBox(obj, bounds, color)
local tl = bounds.topLeft
local tr = bounds.topRight
local bl = bounds.bottomLeft
local br = bounds.bottomRight
local w = bounds.width * 0.25
local h = bounds.height * 0.25
-- TL
obj.Corners[1].From = tl; obj.Corners[1].To = Vector2.new(tl.X + w, tl.Y)
obj.Corners[2].From = tl; obj.Corners[2].To = Vector2.new(tl.X, tl.Y + h)
-- TR
obj.Corners[3].From = tr; obj.Corners[3].To = Vector2.new(tr.X - w, tr.Y)
obj.Corners[4].From = tr; obj.Corners[4].To = Vector2.new(tr.X, tr.Y + h)
-- BL
obj.Corners[5].From = bl; obj.Corners[5].To = Vector2.new(bl.X + w, bl.Y)
obj.Corners[6].From = bl; obj.Corners[6].To = Vector2.new(bl.X, bl.Y - h)
-- BR
obj.Corners[7].From = br; obj.Corners[7].To = Vector2.new(br.X - w, br.Y)
obj.Corners[8].From = br; obj.Corners[8].To = Vector2.new(br.X, br.Y - h)
for _, c in pairs(obj.Corners) do
c.Color = color
c.Visible = true
end
-- Faint full box behind corners
obj.BoxLines[1].From = tl; obj.BoxLines[1].To = tr
obj.BoxLines[2].From = bl; obj.BoxLines[2].To = br
obj.BoxLines[3].From = tl; obj.BoxLines[3].To = bl
obj.BoxLines[4].From = tr; obj.BoxLines[4].To = br
for _, line in pairs(obj.BoxLines) do
line.Color = Color3.new(color.R * 0.3, color.G * 0.3, color.B * 0.3)
line.Thickness = 1
line.Visible = true
end
end
-- =====================
-- RENDER LOOP
-- =====================
RunService.RenderStepped:Connect(function()
if not Config.Enabled then
for _, obj in pairs(ESPObjects) do hideESP(obj) end
return
end
for player, obj in pairs(ESPObjects) do
if not player or not player.Parent then
removeESP(player)
continue
end
local character = player.Character
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
local rootPart = character and character:FindFirstChild("HumanoidRootPart")
if not character or not humanoid or not rootPart or humanoid.Health <= 0 then
hideESP(obj)
continue
end
if isSameTeam(player) then
hideESP(obj)
continue
end
local myRoot = LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
if not myRoot then hideESP(obj) continue end
local dist = math.floor((rootPart.Position - myRoot.Position).Magnitude)
if dist > Config.MaxDistance then hideESP(obj) continue end
local screenPos, onScreen = Camera:WorldToViewportPoint(rootPart.Position)
if not onScreen then hideESP(obj) continue end
local visible = isVisible(character, rootPart)
local espColor = visible and Config.ColorVisible or Config.ColorHidden
local bounds = getCharacterBounds(character)
local hpPct = math.clamp(humanoid.Health / humanoid.MaxHealth, 0, 1)
local hpColor = healthColor(hpPct)
-- Box
if Config.Boxes and bounds then
drawCornerBox(obj, bounds, espColor)
else
for _, l in pairs(obj.BoxLines) do l.Visible = false end
for _, l in pairs(obj.Corners) do l.Visible = false end
end
-- Name tag
if Config.NameTags and bounds then
obj.NameTag.Text = player.Name
obj.NameTag.Position = Vector2.new(bounds.centerX, bounds.topLeft.Y - 16)
obj.NameTag.Color = visible and Ghost.textPrimary or Ghost.textDim
obj.NameTag.Visible = true
else
obj.NameTag.Visible = false
end
-- Distance
if Config.Distance and bounds then
obj.DistLabel.Text = "[" .. dist .. "m]"
obj.DistLabel.Position = Vector2.new(bounds.centerX, bounds.bottomLeft.Y + 4)
obj.DistLabel.Color = visible and Ghost.textMuted or Ghost.textDim
obj.DistLabel.Visible = true
else
obj.DistLabel.Visible = false
end
-- Health bar
if Config.HealthBar and bounds then
local barX = bounds.topLeft.X - 6
local barTop = bounds.topLeft.Y
local barBot = bounds.bottomLeft.Y
local fillTop = barBot - (barBot - barTop) * hpPct
obj.HealthBarBG.From = Vector2.new(barX, barTop)
obj.HealthBarBG.To = Vector2.new(barX, barBot)
obj.HealthBarBG.Color = Color3.fromRGB(0, 0, 0)
obj.HealthBarBG.Visible = true
obj.HealthBar.From = Vector2.new(barX, fillTop)
obj.HealthBar.To = Vector2.new(barX, barBot)
obj.HealthBar.Color = hpColor
obj.HealthBar.Visible = true
else
obj.HealthBarBG.Visible = false
obj.HealthBar.Visible = false
end
-- Tracer
if Config.Tracers then
local vp = Camera.ViewportSize
local origin = Vector2.new(vp.X / 2, vp.Y)
if Config.TracerOrigin == "Mouse" then
local mp = UIS:GetMouseLocation()
origin = Vector2.new(mp.X, mp.Y)
end
obj.Tracer.From = origin
obj.Tracer.To = Vector2.new(screenPos.X, screenPos.Y)
obj.Tracer.Color = espColor
obj.Tracer.Transparency = visible and 0.5 or 0.8
obj.Tracer.Visible = true
else
obj.Tracer.Visible = false
end
end
end)
-- =====================
-- PLAYER MANAGEMENT
-- =====================
local function onPlayerAdded(player)
if player == LocalPlayer then return end
createESP(player)
end
local function onPlayerRemoving(player)
removeESP(player)
end
for _, p in pairs(Players:GetPlayers()) do onPlayerAdded(p) end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
-- =====================
-- GHOST MENU UI
-- =====================
local ScreenGui = Instance.new("ScreenGui")
ScreenGui.Name = "GhostMenu"
ScreenGui.Parent = CoreGui
ScreenGui.ResetOnSpawn = false
ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
-- Invisible anchor — menu appears to float
local MainFrame = Instance.new("Frame")
MainFrame.Parent = ScreenGui
MainFrame.BackgroundColor3 = Ghost.bg
MainFrame.BackgroundTransparency = 0.08
MainFrame.Position = UDim2.new(0, 20, 0.5, -230)
MainFrame.Size = UDim2.new(0, 215, 0, 420)
MainFrame.Active = true
MainFrame.Draggable = true
MainFrame.BorderSizePixel = 0
local MFC = Instance.new("UICorner"); MFC.CornerRadius = UDim.new(0, 10); MFC.Parent = MainFrame
-- Subtle border stroke
local BorderStroke = Instance.new("UIStroke")
BorderStroke.Thickness = 1
BorderStroke.Color = Ghost.border
BorderStroke.Transparency = 0.4
BorderStroke.Parent = MainFrame
-- Faint inner glow line at top
local GlowBar = Instance.new("Frame")
GlowBar.Parent = MainFrame
GlowBar.BackgroundColor3 = Ghost.accent
GlowBar.BackgroundTransparency = 0.7
GlowBar.BorderSizePixel = 0
GlowBar.Position = UDim2.new(0.1, 0, 0, 0)
GlowBar.Size = UDim2.new(0.8, 0, 0, 1)
-- Animated glow bar
spawn(function()
local t = 0
while MainFrame and MainFrame.Parent do
t += 0.05
local alpha = 0.4 + math.sin(t) * 0.3
GlowBar.BackgroundTransparency = alpha
task.wait(0.05)
end
end)
-- Top bar
local TopBar = Instance.new("Frame")
TopBar.Parent = MainFrame
TopBar.BackgroundTransparency = 1
TopBar.Size = UDim2.new(1, 0, 0, 36)
TopBar.BorderSizePixel = 0
-- Ghost icon + title
local TitleLbl = Instance.new("TextLabel")
TitleLbl.Parent = TopBar
TitleLbl.BackgroundTransparency = 1
TitleLbl.Position = UDim2.new(0, 12, 0, 0)
TitleLbl.Size = UDim2.new(1, -80, 1, 0)
TitleLbl.Font = Enum.Font.GothamBold
TitleLbl.Text = "👻 Ghost Menu"
TitleLbl.TextColor3 = Ghost.accentGlow
TitleLbl.TextSize = 13
TitleLbl.TextXAlignment = Enum.TextXAlignment.Left
TitleLbl.TextTransparency = 0.1
-- Subtitle
local SubLbl = Instance.new("TextLabel")
SubLbl.Parent = TopBar
SubLbl.BackgroundTransparency = 1
SubLbl.Position = UDim2.new(0, 12, 0, 18)
SubLbl.Size = UDim2.new(1, -80, 0, 14)
SubLbl.Font = Enum.Font.Gotham
SubLbl.Text = "Advanced ESP"
SubLbl.TextColor3 = Ghost.textDim
SubLbl.TextSize = 10
SubLbl.TextXAlignment = Enum.TextXAlignment.Left
-- Divider
local Divider = Instance.new("Frame")
Divider.Parent = MainFrame
Divider.BackgroundColor3 = Ghost.border
Divider.BackgroundTransparency = 0.6
Divider.BorderSizePixel = 0
Divider.Position = UDim2.new(0, 10, 0, 36)
Divider.Size = UDim2.new(1, -20, 0, 1)
-- Top buttons
local function makeTopBtn(text, posX, color)
local b = Instance.new("TextButton")
b.Parent = TopBar
b.BackgroundColor3 = color or Ghost.surfaceHi
b.BackgroundTransparency = 0.2
b.Position = UDim2.new(1, posX, 0, 7)
b.Size = UDim2.new(0, 20, 0, 20)
b.Font = Enum.Font.GothamBold
b.Text = text
b.TextColor3 = Ghost.textMuted
b.TextSize = 11
b.BorderSizePixel = 0
local c = Instance.new("UICorner"); c.CornerRadius = UDim.new(0, 4); c.Parent = b
local s = Instance.new("UIStroke"); s.Thickness = 1; s.Color = Ghost.border; s.Transparency = 0.5; s.Parent = b
return b
end
local MinBtn = makeTopBtn("—", -48, Ghost.surfaceHi)
local CloseBtn = makeTopBtn("×", -24, Ghost.danger)
CloseBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
-- Scroll
local Scroll = Instance.new("ScrollingFrame")
Scroll.Parent = MainFrame
Scroll.Position = UDim2.new(0, 0, 0, 40)
Scroll.Size = UDim2.new(1, 0, 1, -40)
Scroll.BackgroundTransparency = 1
Scroll.BorderSizePixel = 0
Scroll.ScrollBarThickness = 2
Scroll.ScrollBarImageColor3 = Ghost.accentDim
Scroll.CanvasSize = UDim2.new(0, 0, 0, 0)
Scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y
Scroll.ClipsDescendants = true
local ScrollLayout = Instance.new("UIListLayout")
ScrollLayout.Parent = Scroll
ScrollLayout.SortOrder = Enum.SortOrder.LayoutOrder
ScrollLayout.Padding = UDim.new(0, 3)
local ScrollPad = Instance.new("UIPadding")
ScrollPad.Parent = Scroll
ScrollPad.PaddingTop = UDim.new(0, 8)
ScrollPad.PaddingLeft = UDim.new(0, 10)
ScrollPad.PaddingRight = UDim.new(0, 10)
ScrollPad.PaddingBottom = UDim.new(0, 10)
-- Section label
local function makeSectionLabel(text, order)
local wrapper = Instance.new("Frame")
wrapper.Parent = Scroll
wrapper.BackgroundTransparency = 1
wrapper.Size = UDim2.new(1, 0, 0, 22)
wrapper.LayoutOrder = order
local l = Instance.new("TextLabel")
l.Parent = wrapper
l.BackgroundTransparency = 1
l.Size = UDim2.new(1, 0, 1, 0)
l.Font = Enum.Font.GothamBold
l.Text = text
l.TextColor3 = Ghost.accentDim
l.TextSize = 10
l.TextXAlignment = Enum.TextXAlignment.Left
l.TextTransparency = 0.2
local line = Instance.new("Frame")
line.Parent = wrapper
line.BackgroundColor3 = Ghost.accentDim
line.BackgroundTransparency = 0.7
line.BorderSizePixel = 0
line.Position = UDim2.new(0, 0, 1, -1)
line.Size = UDim2.new(1, 0, 0, 1)
end
-- Toggle row
local function makeToggleRow(label, order, currentVal, callback)
local row = Instance.new("Frame")
row.Parent = Scroll
row.BackgroundColor3 = Ghost.surface
row.BackgroundTransparency = 0.3
row.Size = UDim2.new(1, 0, 0, 30)
row.BorderSizePixel = 0
row.LayoutOrder = order
local RC = Instance.new("UICorner"); RC.CornerRadius = UDim.new(0, 6); RC.Parent = row
local RS = Instance.new("UIStroke"); RS.Thickness = 1; RS.Color = Ghost.border; RS.Transparency = 0.7; RS.Parent = row
local lbl = Instance.new("TextLabel")
lbl.Parent = row
lbl.BackgroundTransparency = 1
lbl.Position = UDim2.new(0, 10, 0, 0)
lbl.Size = UDim2.new(1, -60, 1, 0)
lbl.Font = Enum.Font.Gotham
lbl.Text = label
lbl.TextColor3 = Ghost.textPrimary
lbl.TextSize = 12
lbl.TextXAlignment = Enum.TextXAlignment.Left
lbl.TextTransparency = 0.1
-- Pill toggle
local pill = Instance.new("Frame")
pill.Parent = row
pill.Position = UDim2.new(1, -46, 0.5, -9)
pill.Size = UDim2.new(0, 36, 0, 18)
pill.BorderSizePixel = 0
local PC = Instance.new("UICorner"); PC.CornerRadius = UDim.new(1, 0); PC.Parent = pill
local PS = Instance.new("UIStroke"); PS.Thickness = 1; PS.Color = Ghost.border; PS.Transparency = 0.5; PS.Parent = pill
local knob = Instance.new("Frame")
knob.Parent = pill
knob.Size = UDim2.new(0, 12, 0, 12)
knob.BorderSizePixel = 0
local KC = Instance.new("UICorner"); KC.CornerRadius = UDim.new(1, 0); KC.Parent = knob
local function refresh(val)
TweenService:Create(pill, TweenInfo.new(0.2), {
BackgroundColor3 = val and Ghost.onGreenDim or Ghost.offGray
}):Play()
TweenService:Create(knob, TweenInfo.new(0.2), {
Position = val and UDim2.new(1, -15, 0.5, -6) or UDim2.new(0, 3, 0.5, -6),
BackgroundColor3 = val and Ghost.onGreen or Ghost.textDim
}):Play()
end
refresh(currentVal)
local btn = Instance.new("TextButton")
btn.Parent = row
btn.BackgroundTransparency = 1
btn.Size = UDim2.new(1, 0, 1, 0)
btn.Text = ""
btn.ZIndex = 5
btn.MouseButton1Click:Connect(function()
currentVal = not currentVal
refresh(currentVal)
callback(currentVal)
end)
-- Hover glow
btn.MouseEnter:Connect(function()
TweenService:Create(row, TweenInfo.new(0.15), {BackgroundTransparency = 0.1}):Play()
end)
btn.MouseLeave:Connect(function()
TweenService:Create(row, TweenInfo.new(0.15), {BackgroundTransparency = 0.3}):Play()
end)
end
-- Slider row
local function makeSliderRow(label, order, min, max, current, callback)
local row = Instance.new("Frame")
row.Parent = Scroll
row.BackgroundColor3 = Ghost.surface
row.BackgroundTransparency = 0.3
row.Size = UDim2.new(1, 0, 0, 48)
row.BorderSizePixel = 0
row.LayoutOrder = order
local RC = Instance.new("UICorner"); RC.CornerRadius = UDim.new(0, 6); RC.Parent = row
local RS = Instance.new("UIStroke"); RS.Thickness = 1; RS.Color = Ghost.border; RS.Transparency = 0.7; RS.Parent = row
local lbl = Instance.new("TextLabel")
lbl.Parent = row
lbl.BackgroundTransparency = 1
lbl.Position = UDim2.new(0, 10, 0, 5)
lbl.Size = UDim2.new(1, -20, 0, 16)
lbl.Font = Enum.Font.Gotham
lbl.Text = label .. ": " .. current
lbl.TextColor3 = Ghost.textPrimary
lbl.TextSize = 12
lbl.TextXAlignment = Enum.TextXAlignment.Left
lbl.TextTransparency = 0.1
local trackBG = Instance.new("Frame")
trackBG.Parent = row
trackBG.Position = UDim2.new(0, 10, 0, 30)
trackBG.Size = UDim2.new(1, -20, 0, 5)
trackBG.BackgroundColor3 = Ghost.surfaceHi
trackBG.BorderSizePixel = 0
local TBC = Instance.new("UICorner"); TBC.CornerRadius = UDim.new(1, 0); TBC.Parent = trackBG
local trackFill = Instance.new("Frame")
trackFill.Parent = trackBG
trackFill.BackgroundColor3 = Ghost.accent
trackFill.BorderSizePixel = 0
trackFill.Size = UDim2.new((current - min) / (max - min), 0, 1, 0)
local TFC = Instance.new("UICorner"); TFC.CornerRadius = UDim.new(1, 0); TFC.Parent = trackFill
local thumb = Instance.new("Frame")
thumb.Parent = trackBG
thumb.BackgroundColor3 = Ghost.accentGlow
thumb.BorderSizePixel = 0
thumb.AnchorPoint = Vector2.new(0.5, 0.5)
thumb.Size = UDim2.new(0, 10, 0, 10)
thumb.Position = UDim2.new((current - min) / (max - min), 0, 0.5, 0)
local ThC = Instance.new("UICorner"); ThC.CornerRadius = UDim.new(1, 0); ThC.Parent = thumb
local dragging = false
local function updateSlider(x)
local abs = trackBG.AbsolutePosition.X
local size = trackBG.AbsoluteSize.X
local pct = math.clamp((x - abs) / size, 0, 1)
local val = math.floor(min + (max - min) * pct)
trackFill.Size = UDim2.new(pct, 0, 1, 0)
thumb.Position = UDim2.new(pct, 0, 0.5, 0)
lbl.Text = label .. ": " .. val
callback(val)
end
trackBG.InputBegan:Connect(function(inp)
if inp.UserInputType == Enum.UserInputType.MouseButton1 then
dragging = true
updateSlider(inp.Position.X)
end
end)
UIS.InputEnded:Connect(function(inp)
if inp.UserInputType == Enum.UserInputType.MouseButton1 then dragging = false end
end)
UIS.InputChanged:Connect(function(inp)
if dragging and inp.UserInputType == Enum.UserInputType.MouseMovement then
updateSlider(inp.Position.X)
end
end)
end
-- Tracer origin cycler
local function makeTracerOriginRow(order)
local row = Instance.new("Frame")
row.Parent = Scroll
row.BackgroundColor3 = Ghost.surface
row.BackgroundTransparency = 0.3
row.Size = UDim2.new(1, 0, 0, 30)
row.BorderSizePixel = 0
row.LayoutOrder = order
local RC = Instance.new("UICorner"); RC.CornerRadius = UDim.new(0, 6); RC.Parent = row
local RS = Instance.new("UIStroke"); RS.Thickness = 1; RS.Color = Ghost.border; RS.Transparency = 0.7; RS.Parent = row
local lbl = Instance.new("TextLabel")
lbl.Parent = row
lbl.BackgroundTransparency = 1
lbl.Position = UDim2.new(0, 10, 0, 0)
lbl.Size = UDim2.new(0, 90, 1, 0)
lbl.Font = Enum.Font.Gotham
lbl.Text = "Tracer From"
lbl.TextColor3 = Ghost.textPrimary
lbl.TextSize = 12
lbl.TextXAlignment = Enum.TextXAlignment.Left
lbl.TextTransparency = 0.1
local options = {"Bottom", "Mouse"}
local current = 1
local btn = Instance.new("TextButton")
btn.Parent = row
btn.BackgroundColor3 = Ghost.surfaceHi
btn.BackgroundTransparency = 0.2
btn.Position = UDim2.new(1, -88, 0.5, -10)
btn.Size = UDim2.new(0, 78, 0, 20)
btn.Font = Enum.Font.GothamBold
btn.Text = "⟳ " .. options[current]
btn.TextColor3 = Ghost.accentGlow
btn.TextSize = 11
btn.BorderSizePixel = 0
local BC = Instance.new("UICorner"); BC.CornerRadius = UDim.new(0, 4); BC.Parent = btn
local BS = Instance.new("UIStroke"); BS.Thickness = 1; BS.Color = Ghost.border; BS.Transparency = 0.6; BS.Parent = btn
btn.MouseButton1Click:Connect(function()
current = current == 1 and 2 or 1
Config.TracerOrigin = options[current]
btn.Text = "⟳ " .. options[current]
end)
end
-- Build UI
makeSectionLabel("ELEMENTS", 1)
makeToggleRow("ESP Enabled", 2, Config.Enabled, function(v) Config.Enabled = v end)
makeToggleRow("Corner Boxes", 3, Config.Boxes, function(v) Config.Boxes = v end)
makeToggleRow("Name Tags", 4, Config.NameTags, function(v) Config.NameTags = v end)
makeToggleRow("Health Bar", 5, Config.HealthBar, function(v) Config.HealthBar = v end)
makeToggleRow("Distance", 6, Config.Distance, function(v) Config.Distance = v end)
makeToggleRow("Tracers", 7, Config.Tracers, function(v) Config.Tracers = v end)
makeSectionLabel("FILTERS", 8)
makeToggleRow("Team Check", 9, Config.TeamCheck, function(v) Config.TeamCheck = v end)
makeToggleRow("Visibility Check", 10, Config.VisibilityCheck, function(v) Config.VisibilityCheck = v end)
makeTracerOriginRow(11)
makeSliderRow("Max Distance", 12, 50, 2000, Config.MaxDistance, function(v) Config.MaxDistance = v end)
-- Minimize
local minimized = false
MinBtn.MouseButton1Click:Connect(function()
minimized = not minimized
Scroll.Visible = not minimized
Divider.Visible = not minimized
TweenService:Create(MainFrame, TweenInfo.new(0.2), {
Size = minimized and UDim2.new(0, 215, 0, 38) or UDim2.new(0, 215, 0, 420)
}):Play()
MinBtn.Text = minimized and "+" or "—"
end)
-- Close
CloseBtn.MouseButton1Click:Connect(function()
for player, _ in pairs(ESPObjects) do removeESP(player) end
ScreenGui:Destroy()
end)
print("Ghost Menu loaded.")
-- ============================================================
-- GHOST ESP — PART VISIBILITY PATCH
-- Replaces: createESP, removeESP, hideESP, render loop
-- Each body part gets its own line drawn in screen space.
-- Green = visible to camera. Red = occluded.
-- Drop this block in place of the existing ESP sections.
-- ============================================================
-- Parts to track per character (name = display label)
local TRACKED_PARTS = {
Head = "Head",
UpperTorso = "Torso", -- R15
Torso = "Torso", -- R6
RightUpperArm = "R.Arm",
LeftUpperArm = "L.Arm",
RightUpperLeg = "R.Leg",
LeftUpperLeg = "L.Leg",
RightHand = "R.Hand",
LeftHand = "L.Hand",
RightFoot = "R.Foot",
LeftFoot = "L.Foot",
HumanoidRootPart = "Root",
}
local COLOR_VISIBLE = Color3.fromRGB(80, 220, 120) -- green
local COLOR_OCCLUDED = Color3.fromRGB(220, 70, 70) -- red
local COLOR_TEXT = Color3.fromRGB(220, 220, 240)
local COLOR_TEXT_OCC = Color3.fromRGB(180, 80, 80)
-- ============================================================
-- ESP STORAGE (replaces old ESPObjects)
-- Structure per player:
-- obj.Parts[partName] = {
-- dot = Drawing "Circle",
-- label = Drawing "Text",
-- line = Drawing "Line", (tracer to screen center)
-- }
-- obj.DistLabel = Drawing "Text"
-- obj.HealthBar / obj.HealthBarBG = Drawing "Line"
-- ============================================================
local ESPObjects = {}
local function newDrawing(t, props)
local d = Drawing.new(t)
for k,v in pairs(props) do d[k] = v end
return d
end
local function createESP(player)
if ESPObjects[player] then return end
local obj = { Parts = {} }
for partName, label in pairs(TRACKED_PARTS) do
obj.Parts[partName] = {
dot = newDrawing("Circle", {
Visible = false,
Radius = 4,
Thickness = 1.5,
Color = COLOR_VISIBLE,
Filled = true,
ZIndex = 4,
}),
outline = newDrawing("Circle", {
Visible = false,
Radius = 5,
Thickness = 1,
Color = Color3.fromRGB(0,0,0),
Filled = false,
ZIndex = 3,
}),
label = newDrawing("Text", {
Visible = false,
Text = label,
Size = 11,
Color = COLOR_TEXT,
Center = false,
Outline = true,
OutlineColor= Color3.fromRGB(0,0,0),
ZIndex = 5,
}),
line = newDrawing("Line", {
Visible = false,
Color = COLOR_VISIBLE,
Thickness = 0.8,
Transparency= 0.55,
ZIndex = 1,
}),
}
end
-- Name tag above head
obj.NameTag = newDrawing("Text", {
Visible = false,
Text = player.Name,
Size = 13,
Color = Color3.fromRGB(200,210,240),
Center = true,
Outline = true,
OutlineColor= Color3.fromRGB(0,0,0),
ZIndex = 6,
})
-- Distance label
obj.DistLabel = newDrawing("Text", {
Visible = false,
Text = "",
Size = 11,
Color = Color3.fromRGB(120,130,160),
Center = true,
Outline = true,
OutlineColor= Color3.fromRGB(0,0,0),
ZIndex = 5,
})
-- Health bar bg + fill
obj.HealthBarBG = newDrawing("Line", {
Visible = false,
Color = Color3.fromRGB(0,0,0),
Thickness = 4,
Transparency= 1,
ZIndex = 2,
})
obj.HealthBar = newDrawing("Line", {
Visible = false,
Color = Color3.fromRGB(80,220,120),
Thickness = 3,
Transparency= 1,
ZIndex = 3,
})
ESPObjects[player] = obj
end
local function hideAllParts(obj)
for _, p in pairs(obj.Parts) do
p.dot.Visible = false
p.outline.Visible = false
p.label.Visible = false
p.line.Visible = false
end
obj.NameTag.Visible = false
obj.DistLabel.Visible = false
obj.HealthBarBG.Visible = false
obj.HealthBar.Visible = false
end
local function removeESP(player)
local obj = ESPObjects[player]
if not obj then return end
for _, p in pairs(obj.Parts) do
p.dot:Remove()
p.outline:Remove()
p.label:Remove()
p.line:Remove()
end
obj.NameTag:Remove()
obj.DistLabel:Remove()
obj.HealthBarBG:Remove()
obj.HealthBar:Remove()
ESPObjects[player] = nil
end
-- ============================================================
-- PER-PART VISIBILITY RAYCAST
-- Returns true if the part's centre is unoccluded from camera.
-- ============================================================
local function partIsVisible(character, part)
local origin = Camera.CFrame.Position
local target = part.Position
local direction = target - origin
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = { character, LocalPlayer.Character }
local result = workspace:Raycast(origin, direction, params)
return result == nil
end
-- ============================================================
-- HEALTH COLOR LERP
-- ============================================================
local function hpColor(pct)
return Color3.fromRGB(220,70,70):Lerp(Color3.fromRGB(80,220,120), pct)
end
-- ============================================================
-- RENDER LOOP (replaces old RunService.RenderStepped block)
-- ============================================================
RunService.RenderStepped:Connect(function()
if not Config.Enabled then
for _, obj in pairs(ESPObjects) do hideAllParts(obj) end
return
end
local vp = Camera.ViewportSize
local screenCenter = Vector2.new(vp.X / 2, vp.Y)
for player, obj in pairs(ESPObjects) do
if not player or not player.Parent then
removeESP(player); continue
end
local character = player.Character
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
local rootPart = character and character:FindFirstChild("HumanoidRootPart")
if not character or not humanoid or not rootPart or humanoid.Health <= 0 then
hideAllParts(obj); continue
end
-- Team check
if Config.TeamCheck then
if LocalPlayer.Team and player.Team and LocalPlayer.Team == player.Team then
hideAllParts(obj); continue
end
end
-- Distance
local myRoot = LocalPlayer.Character and LocalPlayer.Character:FindFirstChild("HumanoidRootPart")
if not myRoot then hideAllParts(obj); continue end
local dist = math.floor((rootPart.Position - myRoot.Position).Magnitude)
if dist > Config.MaxDistance then hideAllParts(obj); continue end
-- Root on screen check
local rootScreen, rootOnScreen = Camera:WorldToViewportPoint(rootPart.Position)
if not rootOnScreen then hideAllParts(obj); continue end
local hpPct = math.clamp(humanoid.Health / humanoid.MaxHealth, 0, 1)
-- Track screen bounds for name tag + health bar placement
local minY, maxY = math.huge, -math.huge
local minX, maxX = math.huge, -math.huge
-- --------------------------------------------------------
-- Per-part render
-- --------------------------------------------------------
for partName, drawings in pairs(obj.Parts) do
local part = character:FindFirstChild(partName)
if not part or not part:IsA("BasePart") then
drawings.dot.Visible = false
drawings.outline.Visible = false
drawings.label.Visible = false
drawings.line.Visible = false
continue
end
local sp, onScreen = Camera:WorldToViewportPoint(part.Position)
if not onScreen then
drawings.dot.Visible = false
drawings.outline.Visible = false
drawings.label.Visible = false
drawings.line.Visible = false
continue
end
local sx, sy = sp.X, sp.Y
-- Update bounds
minY = math.min(minY, sy)
maxY = math.max(maxY, sy)
minX = math.min(minX, sx)
maxX = math.max(maxX, sx)
-- Visibility per part
local visible = partIsVisible(character, part)
local dotColor = visible and COLOR_VISIBLE or COLOR_OCCLUDED
local lineColor = visible and COLOR_VISIBLE or COLOR_OCCLUDED
local txtColor = visible and COLOR_TEXT or COLOR_TEXT_OCC
-- Dot
drawings.dot.Position = Vector2.new(sx, sy)
drawings.dot.Color = dotColor
drawings.dot.Filled = visible -- solid = visible, hollow = hidden
drawings.dot.Visible = true
-- Outline ring (always drawn for contrast)
drawings.outline.Position = Vector2.new(sx, sy)
drawings.outline.Visible = true
-- Label (offset right of dot)
drawings.label.Position = Vector2.new(sx + 7, sy - 5)
drawings.label.Color = txtColor
drawings.label.Visible = Config.NameTags
-- Tracer line from screen center to part
if Config.Tracers then
local origin = screenCenter
if Config.TracerOrigin == "Mouse" then
local mp = UIS:GetMouseLocation()
origin = Vector2.new(mp.X, mp.Y)
end
drawings.line.From = origin
drawings.line.To = Vector2.new(sx, sy)
drawings.line.Color = lineColor
drawings.line.Visible = true
else
drawings.line.Visible = false
end
end
-- --------------------------------------------------------
-- Name tag (above highest visible part)
-- --------------------------------------------------------
if Config.NameTags and minY < math.huge then
obj.NameTag.Text = player.Name
obj.NameTag.Position = Vector2.new((minX + maxX) / 2, minY - 16)
obj.NameTag.Visible = true
else
obj.NameTag.Visible = false
end
-- --------------------------------------------------------
-- Distance label (below lowest visible part)
-- --------------------------------------------------------
if Config.Distance and maxY > -math.huge then
obj.DistLabel.Text = "[" .. dist .. "m]"
obj.DistLabel.Position = Vector2.new((minX + maxX) / 2, maxY + 5)
obj.DistLabel.Visible = true
else
obj.DistLabel.Visible = false
end
-- --------------------------------------------------------
-- Health bar (left side of bounding column)
-- --------------------------------------------------------
if Config.HealthBar and minY < math.huge then
local barX = minX - 8
local barTop = minY
local barBot = maxY
local fillTop = barBot - (barBot - barTop) * hpPct
obj.HealthBarBG.From = Vector2.new(barX, barTop)
obj.HealthBarBG.To = Vector2.new(barX, barBot)
obj.HealthBarBG.Visible = true
obj.HealthBar.From = Vector2.new(barX, fillTop)
obj.HealthBar.To = Vector2.new(barX, barBot)
obj.HealthBar.Color = hpColor(hpPct)
obj.HealthBar.Visible = true
else
obj.HealthBarBG.Visible = false
obj.HealthBar.Visible = false
end
end
end)
-- ============================================================
-- PLAYER MANAGEMENT (unchanged API, safe to copy as-is)
-- ============================================================
local function onPlayerAdded(player)
if player == LocalPlayer then return end
createESP(player)
end
local function onPlayerRemoving(player)
removeESP(player)
end
for _, p in pairs(Players:GetPlayers()) do onPlayerAdded(p) end
Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)
To embed this project on your website, copy the following code and paste it into your website's HTML: