universal simple drawing esp I open source
Key RequiredUniversal

universal simple drawing esp I open source

Universal Scriptvaulttvaultt 957 views 48 executesUpdated Jan 7, 2026
5.0/ 5(1 votes)
10100% Positive
Lua Script•853 lines (24994 chars)
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local lp = Players.LocalPlayer
local character = nil
if lp.Character then
    character = lp.Character
end
lp.CharacterAdded:Connect(function(char)
    character = char
end)
local Camera = game.Workspace.CurrentCamera

local settings = {}
settings.box = {}
    settings.box.transparency = 1
    settings.box.color = Color3.new(1,1,1)
    settings.box.thickness = 1
settings.boxoutline = {}
    settings.boxoutline.transparency = 1
    settings.boxoutline.color = Color3.new(0,0,0)
    settings.boxoutline.thickness = 1 -- size of outline on either side of box
settings.healthbar = {}
    settings.healthbar.healthcolor = Color3.new(0,1,0)
    settings.healthbar.backgroundcolor = Color3.new(0,0,0)
    settings.healthbar.borderthickness = 1 -- pixels on either side
    settings.healthbar.width = 1 -- pixels
    settings.healthbar.gap = 3 -- pixels
settings.text = {}
    settings.text.spacing = 2 -- pixels
    settings.text.priority = {}
    settings.text.priority.top = {}
        settings.text.priority.top.name = 1
    settings.text.priority.bottom = {}
        settings.text.priority.bottom.distance = 1
        settings.text.priority.bottom.weapon = 2
settings.name = {}
    settings.name.top = true
    settings.name.transparency = 1
    settings.name.color = Color3.new(1,1,1)
    settings.name.size = 11
    settings.name.outline = true
    settings.name.outlinecolor = Color3.new(0,0,0)
settings.distance = {}
    settings.distance.top = false
    settings.distance.transparency = 1
    settings.distance.color = Color3.new(1,1,1)
    settings.distance.size = 11
    settings.distance.outline = true
    settings.distance.outlinecolor = Color3.new(0,0,0)
settings.weapon = {}
    settings.weapon.top = false
    settings.weapon.transparency = 1
    settings.weapon.color = Color3.new(1,1,1)
    settings.weapon.size = 11
    settings.weapon.outline = true
    settings.weapon.outlinecolor = Color3.new(0,0,0)

local toggles = {}
    toggles.healthcheck = true
toggles.box = true
toggles.boxoutline = true
toggles.name = true
toggles.distance = true
toggles.healthbar = true
toggles.healthbarbackground = true
toggles.weapon = true

local whitelistedweapons = {"Salvaged AK47"}

local entities = {} -- esp entities
entities.box = {}
entities.boxoutline = {}
entities.healthbar = {}
entities.healthbarbackground = {}
entities.text = {} -- table per id, table.top & table.bottom, both will have multiple text entities within them, first is closest to the box, last is furthest
    entities.text.top = {}
    entities.text.bottom = {}

local valid = {}
local charconnections = {}

local mins = {}
local maxes = {}
local onscreens = {}

local Math = {}
Math.calculateExtent = function(cf, size)
    local r = cf.RightVector
    local u = cf.UpVector
    local b = cf.LookVector

    local hx = size.X * 0.5
    local hy = size.Y * 0.5
    local hz = size.Z * 0.5

    return Vector3.new(
        math.abs(r.X)*hx + math.abs(u.X)*hy + math.abs(b.X)*hz,
        math.abs(r.Y)*hx + math.abs(u.Y)*hy + math.abs(b.Y)*hz,
        math.abs(r.Z)*hx + math.abs(u.Z)*hy + math.abs(b.Z)*hz
    )
end

Math.minMaxFromExtent = function(cf, extent)
    local c = cf.Position
    return c - extent, c + extent
end

Math.getboundingbox = function(instances: {BasePart}, orientation: CFrame?)
    if not orientation then
        orientation = CFrame.new()
    end
    
    local j = 0

    repeat
        j += 1
    
        if instances[j] == nil then
            return CFrame.new(), Vector3.new()
        end
    
    until instances[j]:IsA("BasePart")

    orientation = CFrame.new(instances[j].Position) * orientation
    local inversedOrientation = orientation:Inverse()
    local localCF = inversedOrientation * instances[j].CFrame
    local extent = Math.calculateExtent(localCF, instances[j].Size)
    local min, max = Math.minMaxFromExtent(localCF, extent)

    for i = j + 1, #instances do
        local part = instances[i]
        if part:IsA("BasePart") then
            local cf = inversedOrientation * part.CFrame
            local e = Math.calculateExtent(cf, part.Size)
            local lmin, lmax = Math.minMaxFromExtent(cf, e)

            min = Vector3.new(
                math.min(min.X, lmin.X),
                math.min(min.Y, lmin.Y),
                math.min(min.Z, lmin.Z)
            )

            max = Vector3.new(
                math.max(max.X, lmax.X),
                math.max(max.Y, lmax.Y),
                math.max(max.Z, lmax.Z)
            )
        end
    end
    
    local centerLocal = (min + max) * 0.5
    local size = max - min
    local centerWorld = orientation * CFrame.new(centerLocal)

    return centerWorld, size
end

Math.getcorners = function(char)
    local centerWorld, size = Math.getboundingbox(char:GetChildren())

    local half = size/2
    local pos = centerWorld.Position

    local minV = pos - half
    local maxV = pos + half

    local minScreen, minOnscreen = Camera:WorldToViewportPoint(minV)
    local maxScreen, maxOnscreen = Camera:WorldToViewportPoint(maxV)

    local onscreen = minOnscreen or maxOnscreen
    local min = {
        x = math.min(minScreen.X, maxScreen.X),
        y = math.min(minScreen.Y, maxScreen.Y)
    }

    local max = {
        x = math.max(minScreen.X, maxScreen.X),
        y = math.max(minScreen.Y, maxScreen.Y)
    }

    return min, max, onscreen
end


local util = {}
util.watchCharacter = function(plr, id)
    if plr == lp then
        return
    end

    charconnections[id] = plr.CharacterAdded:Connect(function(char)
        valid[id] = char
    end)
end


local check = {}
check.valid = function(plr) -- handles all player checks to see if they are a valid candidate for esp
    if (not plr) or (not plr.Parent) then
        return false
    end 

    if plr == lp then
        return false
    end

    local char = plr.Character

    if not char then
        return false
    end

    if toggles.healthcheck then
        local hum = char:FindFirstChild("Humanoid")
        if not hum then
            return false
        end

        if not (hum.Health > 0) then
            return false
        end
    end

    return true
end

check.exists = function(Type, id, istext) -- checks if id under esp Type exists
    if not istext then
        return entities[Type][id]
    else
        local place = 'top'
        if settings[Type].top == false then
            place = 'bottom'
        end

        return entities.text[place][Type][id]
    end
end


local create = {}
create.box = function(id, min, max, onscreen) -- creates a new box
    local outline = Drawing.new('Square')
    outline.Visible = onscreen
    outline.Transparency = settings.boxoutline.transparency
    outline.Color = settings.boxoutline.color
    outline.Thickness = settings.box.thickness + settings.boxoutline.thickness * 2

    local box = Drawing.new('Square')
    box.Visible = onscreen
    box.Transparency = settings.box.transparency
    box.Color = settings.box.color
    box.Thickness = settings.box.thickness

    if onscreen then
        local pos = Vector2.new(min.x, min.y)
        outline.Position = pos
        box.Position = pos
        local length = max.x - min.x
        local height = max.y - min.y
        outline.Size = Vector2.new(length, height)
        box.Size = Vector2.new(length, height)
    end

    entities.box[id] = box
    entities.boxoutline[id] = outline
end
create.name = function(id, plrname, min, max, onscreen) -- creates a new box
    local text = Drawing.new('Text')
    text.Visible = onscreen

    local place = 'bottom'
    if settings.name.top then
        place = 'top'
    end
    
    text.Transparency = settings.name.transparency
    text.Color = settings.name.color
    text.Size = settings.name.size
    text.Outline = settings.name.outline
    text.OutlineColor = settings.name.outlinecolor
    text.Center = true
    text.Text = plrname

    local priority = settings.text.priority[place].name
    local location = priority
    for i,v in pairs(settings.text.priority[place]) do
        if v < priority then
            if toggles[i] == false then
                location -= 1
            end
        end
    end

    if onscreen then
        local offset
        if place == 'top' then
            offset = (settings.text.spacing + settings.name.size) * (location)
        else
            offset = settings.text.spacing + (settings.text.spacing + settings.name.size) * (location-1)
        end

        local yPos = place == 'top' and (min.y - offset) or (max.y + offset)
        local pos = Vector2.new(min.x + (max.x - min.x) / 2, yPos)
        text.Position = pos
    end

    entities.text[place].name[id] = text
end
create.distance = function(id, min, max, onscreen) -- creates a new box
    local text = Drawing.new('Text')
    text.Visible = onscreen

    local place = 'bottom'
    if settings.distance.top then
        place = 'top'
    end
    
    local priority = settings.text.priority[place].distance
    local location = priority
    for i,v in pairs(settings.text.priority[place]) do
        if v < priority then
            if toggles[i] == false then
                location -= 1
            end
        end
    end
    
    text.Transparency = settings.distance.transparency
    text.Color = settings.distance.color
    text.Size = settings.distance.size
    text.Outline = settings.distance.outline
    text.OutlineColor = settings.distance.outlinecolor
    text.Center = true
    text.Text = '[0 m]'

    if onscreen then
        local offset
        if place == 'top' then
            offset = (settings.text.spacing + settings.distance.size) * (location)
        else
            offset = settings.text.spacing + (settings.text.spacing + settings.distance.size) * (location-1)
        end

        local yPos = place == 'top' and (min.y - offset) or (max.y + offset)
        local pos = Vector2.new(min.x + (max.x - min.x) / 2, yPos)
        text.Position = pos
    end

    entities.text[place].distance[id] = text
end
create.weapon = function(id, min, max, onscreen) -- creates a new box
    local text = Drawing.new('Text')
    text.Visible = onscreen

    local place = 'bottom'
    if settings.weapon.top then
        place = 'top'
    end
    
    local priority = settings.text.priority[place].weapon
    local location = priority
    for i,v in pairs(settings.text.priority[place]) do
        if v < priority then
            if toggles[i] == false then
                location -= 1
            end
        end
    end
    
    text.Transparency = settings.weapon.transparency
    text.Color = settings.weapon.color
    text.Size = settings.weapon.size
    text.Outline = settings.weapon.outline
    text.OutlineColor = settings.weapon.outlinecolor
    text.Center = true
    text.Text = '[None]'

    if onscreen then
        local offset
        if place == 'top' then
            offset = (settings.text.spacing + settings.weapon.size) * (location)
        else
            offset = settings.text.spacing + (settings.text.spacing + settings.weapon.size) * (location-1)
        end

        local yPos = place == 'top' and (min.y - offset) or (max.y + offset)
        local pos = Vector2.new(min.x + (max.x - min.x) / 2, yPos)
        text.Position = pos
    end

    entities.text[place].weapon[id] = text
end
create.healthbar = function(id, min, max, onscreen)
    local left = min.x - settings.healthbar.gap - settings.healthbar.width - settings.healthbar.borderthickness -- left of the actual bar not the background
    local height = max.y - min.y

    local background = Drawing.new("Square")
    background.Visible = onscreen and toggles.healthbarbackground and toggles.healthbar
    background.Transparency = 1
    background.Color = settings.healthbar.backgroundcolor
    background.Filled = true

    local bar = Drawing.new('Square')
    bar.Visible = onscreen and toggles.healthbar
    bar.Transparency = 1
    bar.Color = settings.healthbar.healthcolor
    bar.Filled = true
    
    if onscreen and toggles.healthbar then
        if toggles.healthbarbackground then
            local size = Vector2.new(settings.healthbar.width + settings.healthbar.borderthickness * 2, height + settings.healthbar.borderthickness * 2)
            local pos = Vector2.new(left - settings.healthbar.borderthickness, min.y - settings.healthbar.borderthickness)

            background.Position = pos
            background.Size = size
        end

        local hum = valid[id]:FindFirstChild("Humanoid")
        local health
        if hum then
            health = hum.Health
        else
            health = 100
        end

        local healthchange = height * (1 - health/100)

        local size = Vector2.new(settings.healthbar.width, height - healthchange)
        local pos = Vector2.new(left, min.y + healthchange)

        bar.Size = size
        bar.Position = pos
    end

    entities.healthbar[id] = bar
    entities.healthbarbackground[id] = background
end

local update = {}
update.box = function(id, min, max, onscreen) -- updates an existing box
    local box = entities.box[id]
    local outline = entities.boxoutline[id]

    box.Visible = onscreen and toggles.box
    outline.Visible = onscreen and toggles.boxoutline

    if onscreen and toggles.box then
        box.Transparency = settings.box.transparency
        box.Color = settings.box.color
        box.Thickness = settings.box.thickness

        local pos = Vector2.new(min.x, min.y)

        box.Position = pos
        local length = max.x - min.x
        local height = max.y - min.y
        local size = Vector2.new(length, height)
        box.Size = size

        if toggles.boxoutline then
            outline.Transparency = settings.boxoutline.transparency
            outline.Color = settings.boxoutline.color
            outline.Thickness = settings.box.thickness + settings.boxoutline.thickness * 2

            outline.Position = pos
            outline.Size = size
        end
    end
end
update.name = function(id, min, max, onscreen) -- updates an existing box
    local place = 'bottom'
    if settings.name.top then
        place = 'top'
    end

    local text = entities.text[place].name[id]

    text.Visible = onscreen and toggles.name

    local priority = settings.text.priority[place].name
    local location = priority
    for i,v in pairs(settings.text.priority[place]) do
        if v < priority then
            if toggles[i] == false then
                location -= 1
            end
        end
    end

    if onscreen and toggles.name then
        local priority = settings.text.priority[place].name
        local location = priority
        for i,v in pairs(settings.text.priority[place]) do
            if v < priority then
                if toggles[i] == false then
                    location -= 1
                end
            end
        end

        local offset
        if place == 'top' then
            offset = (settings.text.spacing + settings.name.size) * (location)
        else
            offset = settings.text.spacing + (settings.text.spacing + settings.name.size) * (location-1)
        end

        text.Transparency = settings.name.transparency
        text.Color = settings.name.color
        text.Size = settings.name.size
        text.Outline = settings.name.outline
        text.OutlineColor = settings.name.outlinecolor

        local yPos = place == 'top' and (min.y - offset) or (max.y + offset)
        local pos = Vector2.new(min.x + (max.x - min.x) / 2, yPos)
        text.Position = pos
    end
end
update.distance = function(id, min, max, onscreen) -- updates an existing box
    local place = 'bottom'
    if settings.distance.top then
        place = 'top'
    end

    local text = entities.text[place].distance[id]

    text.Visible = onscreen and toggles.distance

    if onscreen and toggles.distance then
        local priority = settings.text.priority[place].distance
        local location = priority
        for i,v in pairs(settings.text.priority[place]) do
            if v < priority then
                if toggles[i] == false then
                    location -= 1
                end
            end
        end

        local char = valid[id]
        local distance = (character:GetPivot().Position - char:GetPivot().Position).Magnitude
        distance = math.round(distance)

        text.Text = '['..tostring(distance)..' m]'
        local offset
        if place == 'top' then
            offset = (settings.text.spacing + settings.distance.size) * (location)
        else
            offset = settings.text.spacing + (settings.text.spacing + settings.distance.size) * (location-1)
        end

        text.Transparency = settings.distance.transparency
        text.Color = settings.distance.color
        text.Size = settings.distance.size
        text.Outline = settings.distance.outline
        text.OutlineColor = settings.distance.outlinecolor

        local yPos = place == 'top' and (min.y - offset) or (min.y + (max.y - min.y) + offset)
        local pos = Vector2.new(min.x + (max.x - min.x) / 2, yPos)
        text.Position = pos
    end
end
update.weapon = function(id, min, max, onscreen) -- updates an existing box
    local place = 'bottom'
    if settings.weapon.top then
        place = 'top'
    end

    local text = entities.text[place].weapon[id]

    text.Visible = onscreen and toggles.weapon

    if onscreen and toggles.weapon then
        local priority = settings.text.priority[place].weapon
        local location = priority
        for i,v in pairs(settings.text.priority[place]) do
            if v < priority then
                if toggles[i] == false then
                    location -= 1
                end
            end
        end

        local char = valid[id]
        local children = char:GetChildren()
        local weapon = 'None'
        for _,child in pairs(children) do
            if child:IsA('Tool') and (table.find(whitelistedweapons, child.Name) ~= nil) then
                weapon = child.Name
            end
        end

        text.Text = '['..weapon..']'
        local offset
        if place == 'top' then
            offset = (settings.text.spacing + settings.weapon.size) * (location)
        else
            offset = settings.text.spacing + (settings.text.spacing + settings.weapon.size) * (location-1)
        end

        text.Transparency = settings.weapon.transparency
        text.Color = settings.weapon.color
        text.Size = settings.weapon.size
        text.Outline = settings.weapon.outline
        text.OutlineColor = settings.weapon.outlinecolor

        local yPos = place == 'top' and (min.y - offset) or (max.y + offset)
        local pos = Vector2.new(min.x + (max.x - min.x) / 2, yPos)
        text.Position = pos
    end
end
update.healthbar = function(id, min, max, onscreen)
    local background = entities.healthbarbackground[id]
    local bar = entities.healthbar[id]

    background.Visible = onscreen and toggles.healthbarbackground and toggles.healthbar
    bar.Visible = onscreen and toggles.healthbar
    
    if onscreen and toggles.healthbar then
        local left = min.x - settings.healthbar.gap - settings.healthbar.width - settings.healthbar.borderthickness -- left of the actual bar not the background
        local height = max.y - min.y

        if toggles.healthbarbackground then
            background.Transparency = 1
            background.Color = settings.healthbar.backgroundcolor
            
            local size = Vector2.new(settings.healthbar.width + settings.healthbar.borderthickness * 2, height + settings.healthbar.borderthickness * 2)
            local pos = Vector2.new(left - settings.healthbar.borderthickness, min.y - settings.healthbar.borderthickness)

            background.Position = pos
            background.Size = size
        end

        bar.Transparency = 1
        bar.Color = settings.healthbar.healthcolor

        local hum = valid[id]:FindFirstChild("Humanoid")
        local health
        if hum then
            health = hum.Health
        else
            health = 100
        end

        local healthchange = height * (1 - health/100)

        local size = Vector2.new(settings.healthbar.width, height - healthchange)
        local pos = Vector2.new(left, min.y + healthchange)

        bar.Size = size
        bar.Position = pos
    end
end


local remove = function(Type, id) -- removes an existing box
    local isText

    if settings[Type] then
        isText = settings[Type].top
    else
        isText = nil
    end

    local place = 'top'
    if isText == false then
        place = 'bottom'
    end

    if isText ~= nil then
        if not entities.text[place][Type][id] then
            return
        end

        entities.text[place][Type][id]:Remove()
        local index = table.find(entities.text[place][Type], id)
        if index then
            table.remove(entities.text[place][Type], index)
        end
        return
    elseif isText == nil then
        if not entities[Type][id] then
            return
        end

        entities[Type][id]:Remove()
        local index = table.find(entities[Type], id)
        if index then
            table.remove(entities[Type], index)
        end
        return
    end
end


local handler = {}
handler.box = function(id, char) -- coordinates everything box related
    if toggles.box ~= true then
        return
    end

    local min = mins[id]
    local max = maxes[id]
    local onscreen = onscreens[id]

    if not check.exists('box', id, false) then -- doesnt exist? create one
        create.box(id, min, max, onscreen)
        return
    else -- exists? update it
        update.box(id, min, max, onscreen)
        return
    end
end

handler.name = function(id, char)
    if toggles.name ~= true then
        return
    end

    local min = mins[id]
    local max = maxes[id]
    local onscreen = onscreens[id]

    if not check.exists('name', id, true) then -- doesnt exist? create one
        create.name(id, char.Name, min, max, onscreen)
        return
    else -- exists? update it
        update.name(id, min, max, onscreen)
        return
    end
end

handler.distance = function(id, char)
    if toggles.distance ~= true then
        return
    end

    local min = mins[id]
    local max = maxes[id]
    local onscreen = onscreens[id]

    if not check.exists('distance', id, true) then -- doesnt exist? create one
        create.distance(id, min, max, onscreen)
        return
    else -- exists? update it
        update.distance(id, min, max, onscreen)
        return
    end
end

handler.weapon = function(id, char)
    if toggles.weapon ~= true then
        return
    end

    local min = mins[id]
    local max = maxes[id]
    local onscreen = onscreens[id]

    if not check.exists('weapon', id, true) then -- doesnt exist? create one
        create.weapon(id, min, max, onscreen)
        return
    else -- exists? update it
        update.weapon(id, min, max, onscreen)
        return
    end
end

handler.healthbar = function(id, char)
    if toggles.healthbar ~= true then
        return
    end

    local min = mins[id]
    local max = maxes[id]
    local onscreen = onscreens[id]

    if not check.exists('healthbar', id, false) then -- doesnt exist? create one
        create.healthbar(id, min, max, onscreen)
        return
    else -- exists? update it
        update.healthbar(id, min, max, onscreen)
        return
    end
end

--init text types
for text, _ in pairs(handler) do
    if settings[text].top == true then
        entities.text.top[text] = {}
    elseif settings[text].top == false then
        entities.text.bottom[text] = {}
    end
end

--init valid table
for _, player in pairs(Players:GetChildren()) do
    local id = player.UserId
    util.watchCharacter(player, id)
    if check.valid(player) then
        valid[id] = player.Character
    end
end


-- main thread
RunService:BindToRenderStep("render", Enum.RenderPriority.Camera.Value + 1, function()
    for id, char in valid do
        local min, max, onscreen = Math.getcorners(char)
        mins[id] = min
        maxes[id] = max
        onscreens[id] = onscreen

        for _, func in pairs(handler) do
            func(id, char)
        end
    end
end)

--player leave
Players.PlayerRemoving:Connect(function(plr)
    local id = plr.UserId
    table.remove(valid, id)

    for Type, _ in pairs(entities) do
        if Type == 'text' then
            continue
        end

        remove(Type, id)
    end

    for Type, _ in pairs(entities.text.top) do
        remove(Type, id)
    end

    for Type, _ in pairs(entities.text.bottom) do
        remove(Type, id)
    end
end)

--player add
Players.PlayerAdded:Connect(function(player)
    repeat task.wait() until player.Character

    local id = player.UserId

    if check.valid(player) then
        valid[id] = player.Character
        util.watchCharacter(player, id)
    end
end)

Features & Information

box esp names distances weapons (currently only works for tools stored under the character, name of tool needs to be present in the whitelistedweapons table) healthbars if you want to update anything just update the functions in the create or update tables, ive tried to keep the code neat this time :p

Community Comments (0)

No comments yet for this script.

More Scripts for Universal Scripts