Universal Workspace ESP
Key RequiredUniversal

Universal Workspace ESP

Universal ScriptHFJSHFJS 532 views 61 executesUpdated Feb 27, 2026
5.0/ 5(3 votes)
30100% Positive
Lua Script•387 lines (12617 chars)
--// SERVICES
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")

--// CONSTANTS
local PLAYER = Players.LocalPlayer
local THEME = {
    Bg = Color3.fromRGB(15, 15, 15),
    Header = Color3.fromRGB(25, 25, 25),
    Accent = Color3.fromRGB(0, 255, 140),
    Text = Color3.fromRGB(255, 255, 255),
    SubText = Color3.fromRGB(180, 180, 180)
}

--// GUI SETUP
local ScreenGui = Instance.new("ScreenGui")
ScreenGui.Name = "UniversalESP_Explorer"
ScreenGui.ResetOnSpawn = false
ScreenGui.IgnoreGuiInset = true
ScreenGui.Parent = PLAYER:WaitForChild("PlayerGui")

local MainFrame = Instance.new("Frame")
MainFrame.Name = "MainWindow"
MainFrame.Size = UDim2.new(0, 320, 0, 500)
MainFrame.Position = UDim2.new(0.5, -160, 0.5, -250)
MainFrame.BackgroundColor3 = THEME.Bg
MainFrame.BorderSizePixel = 0
MainFrame.Parent = ScreenGui
local MainCorner = Instance.new("UICorner")
MainCorner.CornerRadius = UDim.new(0, 6)
MainCorner.Parent = MainFrame
local MainStroke = Instance.new("UIStroke")
MainStroke.Color = THEME.Accent
MainStroke.Thickness = 1
MainStroke.Parent = MainFrame

-- Header
local Header = Instance.new("Frame")
Header.Name = "Header"
Header.Size = UDim2.new(1, 0, 0, 40)
Header.BackgroundColor3 = THEME.Header
Header.Parent = MainFrame
local HeaderCorner = Instance.new("UICorner")
HeaderCorner.CornerRadius = UDim.new(0, 6)
HeaderCorner.Parent = Header
local HeaderFix = Instance.new("Frame")
HeaderFix.Size = UDim2.new(1, 0, 0, 15)
HeaderFix.Position = UDim2.new(0, 0, 1, -15)
HeaderFix.BackgroundColor3 = THEME.Header
HeaderFix.BorderSizePixel = 0
HeaderFix.Parent = Header

local Title = Instance.new("TextLabel")
Title.Text = "MODEL EXPLORER [LIVE]"
Title.TextColor3 = THEME.Accent
Title.Font = Enum.Font.Code
Title.TextSize = 16
Title.BackgroundTransparency = 1
Title.Size = UDim2.new(1, -50, 1, 0)
Title.Position = UDim2.new(0, 15, 0, 0)
Title.TextXAlignment = Enum.TextXAlignment.Left
Title.Parent = Header

local CloseBtn = Instance.new("TextButton")
CloseBtn.Text = "-"
CloseBtn.TextColor3 = THEME.Accent
CloseBtn.Font = Enum.Font.Code
CloseBtn.TextSize = 20
CloseBtn.BackgroundTransparency = 1
CloseBtn.Size = UDim2.new(0, 30, 1, 0)
CloseBtn.Position = UDim2.new(1, -30, 0, 0)
CloseBtn.Parent = Header

-- Body
local Body = Instance.new("Frame")
Body.Name = "Body"
Body.Size = UDim2.new(1, 0, 1, -45)
Body.Position = UDim2.new(0, 0, 0, 42)
Body.BackgroundTransparency = 1
Body.Parent = MainFrame

-- Scroll Area
local ScrollingFrame = Instance.new("ScrollingFrame")
ScrollingFrame.Size = UDim2.new(1, -10, 1, -10)
ScrollingFrame.Position = UDim2.new(0, 5, 0, 5)
ScrollingFrame.BackgroundTransparency = 1
ScrollingFrame.ScrollBarThickness = 4
ScrollingFrame.ScrollBarImageColor3 = THEME.Accent
ScrollingFrame.BorderSizePixel = 0
ScrollingFrame.Parent = Body
ScrollingFrame.AutomaticCanvasSize = Enum.AutomaticSize.Y

local MainLayout = Instance.new("UIListLayout")
MainLayout.Parent = ScrollingFrame
MainLayout.SortOrder = Enum.SortOrder.Name -- Sort alphabetically automatically

--// LOGIC

-- Draggable
local dragging, dragStart, startPos
Header.InputBegan:Connect(function(input)
    if input.UserInputType == Enum.UserInputType.MouseButton1 then
        dragging = true; dragStart = input.Position; startPos = MainFrame.Position
    end
end)
Header.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then dragging = false end end)
UserInputService.InputChanged:Connect(function(input)
    if dragging and input.UserInputType == Enum.UserInputType.MouseMovement then
        local delta = input.Position - dragStart
        MainFrame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
    end
end)

-- Minimize
local isMin = false
CloseBtn.MouseButton1Click:Connect(function()
    isMin = not isMin
    if isMin then
        MainFrame:TweenSize(UDim2.new(0, 320, 0, 40), "Out", "Quad", 0.2, true)
        CloseBtn.Text = "+"
    else
        MainFrame:TweenSize(UDim2.new(0, 320, 0, 500), "Out", "Quad", 0.2, true)
        CloseBtn.Text = "-"
    end
end)

-- ESP Functions
local function addESP(object)
    if not object then return end
    local oldH = object:FindFirstChild("ESP_Highlight")
    local oldT = object:FindFirstChild("ESP_Tag")
    if oldH then oldH:Destroy() end
    if oldT then oldT:Destroy() end

    local h = Instance.new("Highlight")
    h.Name = "ESP_Highlight"
    h.FillColor = THEME.Accent
    h.OutlineColor = THEME.Accent
    h.FillTransparency = 0.5
    h.Adornee = object
    h.Parent = object

    local b = Instance.new("BillboardGui")
    b.Name = "ESP_Tag"
    b.Size = UDim2.new(0, 100, 0, 25)
    b.AlwaysOnTop = true
    b.StudsOffset = Vector3.new(0, 2, 0)
    
    if object:IsA("Model") then
        local p = object.PrimaryPart or object:FindFirstChildWhichIsA("BasePart")
        if p then b.Adornee = p end
    elseif object:IsA("Folder") then
        local p = object:FindFirstChildWhichIsA("BasePart")
        if p then b.Adornee = p end
    end

    local t = Instance.new("TextLabel")
    t.Size = UDim2.new(1, 0, 1, 0)
    t.BackgroundTransparency = 1
    t.Text = object.Name
    t.TextColor3 = THEME.Accent
    t.Font = Enum.Font.Code
    t.TextSize = 14
    t.TextStrokeTransparency = 0.5
    t.Parent = b
    
    b.Parent = object
end

local function removeESP(object)
    if not object then return end
    local h = object:FindFirstChild("ESP_Highlight")
    local t = object:FindFirstChild("ESP_Tag")
    if h then h:Destroy() end
    if t then t:Destroy() end
end

-- Helper: Check if valid (ONLY Models and Folders)
local function isValidObject(obj)
    return obj:IsA("Model") or obj:IsA("Folder")
end

-- Helper: Check for valid children (Models/Folders only)
local function hasValidChildren(obj)
    for _, child in pairs(obj:GetChildren()) do
        if isValidObject(child) then
            return true
        end
    end
    return false
end

--// RECURSIVE LOGIC HELPERS

-- Applies ESP to object and all valid descendants
local function setRecursiveESP(object, state)
    if state then
        addESP(object)
    else
        removeESP(object)
    end
    
    for _, child in pairs(object:GetChildren()) do
        if isValidObject(child) then
            setRecursiveESP(child, state)
        end
    end
end

-- Updates the visual checkbox of children inside a specific UI container
local function updateChildCheckboxes(container, state)
    for _, itemWrapper in pairs(container:GetChildren()) do
        if itemWrapper:IsA("Frame") then
            local row = itemWrapper:FindFirstChild("Row")
            if row then
                local checkbox = row:FindFirstChild("Checkbox")
                if checkbox then
                    checkbox.Text = state and "X" or ""
                end
            end
            -- If nested children are already loaded/visible, update them too
            local nestedChildren = itemWrapper:FindFirstChild("Children")
            if nestedChildren and nestedChildren.Visible then
                updateChildCheckboxes(nestedChildren, state)
            end
        end
    end
end

-- Mapping to track GUI elements for removal
local RootItemsMap = {} -- [Instance] = GUI_Frame

-- Recursive Builder
local function createItem(parentContainer, object, depth)
    -- 1. THE CONTAINER
    local itemWrapper = Instance.new("Frame")
    itemWrapper.Name = object.Name -- Name used for sorting
    itemWrapper.Size = UDim2.new(1, 0, 0, 0)
    itemWrapper.AutomaticSize = Enum.AutomaticSize.Y
    itemWrapper.BackgroundTransparency = 1
    itemWrapper.Parent = parentContainer -- Fixed typo: itemWriter -> itemWrapper
    
    local wrapperLayout = Instance.new("UIListLayout")
    wrapperLayout.SortOrder = Enum.SortOrder.LayoutOrder
    wrapperLayout.Parent = itemWrapper

    -- 2. THE ROW
    local rowFrame = Instance.new("Frame")
    rowFrame.Name = "Row"
    rowFrame.Size = UDim2.new(1, 0, 0, 24)
    rowFrame.BackgroundColor3 = THEME.Header
    rowFrame.BorderSizePixel = 0
    rowFrame.Parent = itemWrapper
    
    local indent = 15 * depth

    -- Expand Button
    local canExpand = hasValidChildren(object)
    local expandBtn = nil
    
    if canExpand then
        expandBtn = Instance.new("TextButton")
        expandBtn.Name = "ExpandBtn"
        expandBtn.Size = UDim2.new(0, 20, 1, 0)
        expandBtn.Position = UDim2.new(0, indent, 0, 0)
        expandBtn.BackgroundTransparency = 1
        expandBtn.Text = "+"
        expandBtn.TextColor3 = THEME.SubText
        expandBtn.Font = Enum.Font.Code
        expandBtn.TextSize = 14
        expandBtn.Parent = rowFrame
    end

    -- ESP Checkbox
    local checkbox = Instance.new("TextButton")
    checkbox.Name = "Checkbox" -- Named for lookup in updateChildCheckboxes
    checkbox.Size = UDim2.new(0, 24, 1, 0)
    checkbox.Position = UDim2.new(0, indent + (canExpand and 20 or 0), 0, 0)
    checkbox.BackgroundTransparency = 1
    checkbox.Text = ""
    checkbox.TextColor3 = THEME.Accent
    checkbox.Font = Enum.Font.Code
    checkbox.TextSize = 18
    checkbox.TextXAlignment = Enum.TextXAlignment.Center
    checkbox.Parent = rowFrame
    local cStroke = Instance.new("UIStroke")
    cStroke.Color = THEME.Accent
    cStroke.Thickness = 1
    cStroke.Parent = checkbox

    -- Name Label
    local label = Instance.new("TextLabel")
    label.Size = UDim2.new(1, -(indent + (canExpand and 50 or 30)), 1, 0)
    label.Position = UDim2.new(0, indent + (canExpand and 50 or 30), 0, 0)
    label.BackgroundTransparency = 1
    label.TextColor3 = THEME.Text
    label.TextXAlignment = Enum.TextXAlignment.Left
    label.Font = Enum.Font.Code
    label.TextSize = 13
    label.Text = object.Name .. " ["..object.ClassName.."]"
    label.Parent = rowFrame

    -- 3. CHILDREN CONTAINER
    local childContainer = Instance.new("Frame")
    childContainer.Name = "Children"
    childContainer.Size = UDim2.new(1, 0, 0, 0)
    childContainer.AutomaticSize = Enum.AutomaticSize.Y
    childContainer.BackgroundTransparency = 1
    childContainer.Visible = false
    childContainer.Parent = itemWrapper
    
    local childLayout = Instance.new("UIListLayout")
    childLayout.SortOrder = Enum.SortOrder.Name -- Sort children alphabetically
    childLayout.Parent = childContainer

    -- LOGIC: Initialize State (If parent was clicked before we loaded)
    if object:FindFirstChild("ESP_Highlight") then
        checkbox.Text = "X"
    end

    -- LOGIC: Expand
    if canExpand then
        local isExpanded = false
        expandBtn.MouseButton1Click:Connect(function()
            isExpanded = not isExpanded
            expandBtn.Text = isExpanded and "-" or "+"
            
            if isExpanded then
                -- Lazy load children
                if #childContainer:GetChildren() == 1 then -- only layout exists
                    local children = object:GetChildren()
                    for _, child in pairs(children) do
                        if isValidObject(child) then
                            createItem(childContainer, child, depth + 1)
                        end
                    end
                end
                childContainer.Visible = true
            else
                childContainer.Visible = false
            end
        end)
    end

    -- LOGIC: ESP Toggle (Recursive)
    checkbox.MouseButton1Click:Connect(function()
        local willEnable = (checkbox.Text == "")
        checkbox.Text = willEnable and "X" or ""
        
        -- 1. Apply ESP to self and all children recursively
        setRecursiveESP(object, willEnable)
        
        -- 2. Update UI of any children currently loaded in the GUI
        updateChildCheckboxes(childContainer, willEnable)
    end)
    
    return itemWrapper
end

--// LIVE UPDATE SYSTEM
-- 1. Initial Scan
for _, obj in pairs(workspace:GetChildren()) do
    if isValidObject(obj) then
        local guiItem = createItem(ScrollingFrame, obj, 0)
        RootItemsMap[obj] = guiItem
    end
end

-- 2. Listen for new items
workspace.ChildAdded:Connect(function(child)
    if isValidObject(child) then
        if not RootItemsMap[child] then
            local guiItem = createItem(ScrollingFrame, child, 0)
            RootItemsMap[child] = guiItem
        end
    end
end)

-- 3. Listen for removed items
workspace.ChildRemoved:Connect(function(child)
    if RootItemsMap[child] then
        RootItemsMap[child]:Destroy()
        RootItemsMap[child] = nil
    end
end)

Features & Information

Checks the workplace ESP for any object in game
#ESP#Workspace#Universal

Community Comments (2)

00Fazee00FazeeFeb 27, 2026

its gpt'd but its a good script btw

Replying to @00Fazee
HFJSHFJSFeb 28, 2026

Used it to make another script but it's so useful, just had to share

More Scripts for Universal Scripts