Universal hitbox npc
Key RequiredUniversal

Universal hitbox npc

Universal Script*rac3*rac3 4.1K views 1.9K executesUpdated Aug 17, 2025
2.5/ 5(2 votes)
1150% Positive
Lua Script•410 lines (13332 chars)
-- NPC Hitbox Expander GUI — Works with most damage tools
-- Modes:
--  - Proxy: Adds a welded neon-red hitbox part (CanTouch/CanQuery = true) so weapons and raycasts register.
--  - Resize: Resizes the real HRP, optionally tints neon red. Reverts cleanly on disable.
-- Default size: 9, transparency: 0.4, mode: Proxy

--// Services
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local CoreGui = game:GetService("CoreGui")

--// Constants
local GUI_NAME = "NPC_Hitbox_GUI"
local PROXY_NAME = "NF_NPC_Hitbox"
local TAG_ATTR = "NF_HitboxTag"
local MODE_PROXY, MODE_RESIZE = "Proxy", "Resize"

--// Cleanup previous UI
local old = CoreGui:FindFirstChild(GUI_NAME)
if old then old:Destroy() end

--// State
local enabled = false
local currentSize = 9
local currentTransparency = 0.40
local mode = MODE_PROXY

--// Helpers
local function isNPC(model)
    if not (model and model:IsA("Model")) then return false end
    local hum = model:FindFirstChildOfClass("Humanoid")
    if not hum then return false end
    return Players:GetPlayerFromCharacter(model) == nil
end

local function getRoot(model)
    if not model then return nil end
    return model:FindFirstChild("HumanoidRootPart")
        or model:FindFirstChild("UpperTorso")
        or model:FindFirstChild("Torso")
end

-- Proxy hitbox: real touch/query, no collisions
local function makeProxyHitbox(hrp, size, trans)
    local existing = hrp:FindFirstChild(PROXY_NAME)
    if existing and existing:IsA("BasePart") and existing:GetAttribute(TAG_ATTR) then
        existing.Size = Vector3.new(size, size, size)
        existing.Transparency = trans
        return existing
    end

    local part = Instance.new("Part")
    part.Name = PROXY_NAME
    part.Size = Vector3.new(size, size, size)
    part.Color = Color3.fromRGB(255, 0, 0)
    part.Material = Enum.Material.Neon
    part.Transparency = trans
    part.CanCollide = false     -- no physical push
    part.CanTouch = true        -- Touched events can fire on weapons
    part.CanQuery = true        -- Raycasts and spatial queries will hit
    part.Massless = true
    part.CastShadow = false
    part.Anchored = false
    part.CFrame = hrp.CFrame
    part:SetAttribute(TAG_ATTR, true)
    part.Parent = hrp

    local weld = Instance.new("WeldConstraint")
    weld.Part0 = hrp
    weld.Part1 = part
    weld.Parent = part

    return part
end

-- Resize HRP: stores and restores original visuals/size
local function storeOriginal(hrp)
    if hrp:GetAttribute("NF_Stored") then return end
    hrp:SetAttribute("NF_Stored", true)
    hrp:SetAttribute("NF_OrigSize", hrp.Size)
    hrp:SetAttribute("NF_OrigColor", hrp.Color)
    hrp:SetAttribute("NF_OrigMat", tostring(hrp.Material))
    hrp:SetAttribute("NF_OrigTrans", hrp.Transparency)
end

local function applyResize(hrp, size, trans)
    storeOriginal(hrp)
    hrp.Size = Vector3.new(size, size, size)
    hrp.Color = Color3.fromRGB(255, 0, 0)
    hrp.Material = Enum.Material.Neon
    hrp.Transparency = trans
    -- Ensure tools/rays can see/touch HRP
    hrp.CanQuery = true
    hrp.CanTouch = true
    -- Leave CanCollide as-is to avoid breaking NPC physics
end

local function restoreResize(hrp)
    if not hrp:GetAttribute("NF_Stored") then return end
    local origSize = hrp:GetAttribute("NF_OrigSize")
    local origColor = hrp:GetAttribute("NF_OrigColor")
    local origMat = hrp:GetAttribute("NF_OrigMat")
    local origTrans = hrp:GetAttribute("NF_OrigTrans")
    if typeof(origSize) == "Vector3" then hrp.Size = origSize end
    if typeof(origColor) == "Color3" then hrp.Color = origColor end
    if typeof(origMat) == "string" and Enum.Material[origMat] then
        hrp.Material = Enum.Material[origMat]
    end
    if typeof(origTrans) == "number" then hrp.Transparency = origTrans end
    hrp:SetAttribute("NF_Stored", nil)
    hrp:SetAttribute("NF_OrigSize", nil)
    hrp:SetAttribute("NF_OrigColor", nil)
    hrp:SetAttribute("NF_OrigMat", nil)
    hrp:SetAttribute("NF_OrigTrans", nil)
end

local function applyToNPC(model, size, trans)
    local hrp = getRoot(model)
    if not hrp then return end
    if mode == MODE_PROXY then
        makeProxyHitbox(hrp, size, trans)
    else
        applyResize(hrp, size, trans)
    end
end

local function removeFromNPC(model)
    local hrp = getRoot(model)
    if not hrp then return end
    if mode == MODE_PROXY then
        local hb = hrp:FindFirstChild(PROXY_NAME)
        if hb and hb:IsA("BasePart") and hb:GetAttribute(TAG_ATTR) then
            hb:Destroy()
        end
    else
        restoreResize(hrp)
    end
end

local function applyAll(size, trans)
    for _, d in ipairs(workspace:GetDescendants()) do
        if d:IsA("Model") and isNPC(d) then
            applyToNPC(d, size, trans)
        end
    end
end

local function removeAll()
    for _, d in ipairs(workspace:GetDescendants()) do
        if d:IsA("Model") and isNPC(d) then
            removeFromNPC(d)
        end
    end
end

-- Auto-apply to new NPCs
local descConn
local function startAuto()
    if descConn then descConn:Disconnect() end
    descConn = workspace.DescendantAdded:Connect(function(obj)
        if not enabled then return end
        if obj:IsA("Humanoid") then
            local m = obj.Parent
            if isNPC(m) then
                local hrp = getRoot(m)
                if hrp then applyToNPC(m, currentSize, currentTransparency) end
            end
        elseif obj:IsA("BasePart") and (obj.Name == "HumanoidRootPart" or obj.Name == "UpperTorso" or obj.Name == "Torso") then
            local m = obj:FindFirstAncestorOfClass("Model")
            if isNPC(m) then applyToNPC(m, currentSize, currentTransparency) end
        end
    end)
end

local function stopAuto()
    if descConn then descConn:Disconnect() end
    descConn = nil
end

local function setEnabled(on)
    enabled = on
    if enabled then
        applyAll(currentSize, currentTransparency)
        startAuto()
    else
        stopAuto()
        removeAll()
    end
end

--// UI
local ui = Instance.new("ScreenGui")
ui.Name = GUI_NAME
ui.ResetOnSpawn = false
ui.IgnoreGuiInset = false
ui.Parent = CoreGui

local frame = Instance.new("Frame")
frame.Name = "Main"
frame.Size = UDim2.new(0, 320, 0, 200)
frame.Position = UDim2.new(0, 40, 0, 120)
frame.BackgroundColor3 = Color3.fromRGB(22, 22, 22)
frame.BorderSizePixel = 0
frame.Parent = ui
Instance.new("UICorner", frame).CornerRadius = UDim.new(0, 8)

local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, -36, 0, 32)
title.Position = UDim2.new(0, 12, 0, 8)
title.BackgroundTransparency = 1
title.Text = "NPC Hitbox Expander (works)"
title.TextColor3 = Color3.fromRGB(255, 255, 255)
title.TextSize = 18
title.Font = Enum.Font.GothamBold
title.TextXAlignment = Enum.TextXAlignment.Left
title.Parent = frame

local closeBtn = Instance.new("TextButton")
closeBtn.Size = UDim2.new(0, 24, 0, 24)
closeBtn.Position = UDim2.new(1, -32, 0, 10)
closeBtn.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
closeBtn.Text = "×"
closeBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
closeBtn.TextSize = 20
closeBtn.Font = Enum.Font.GothamBold
closeBtn.Parent = frame
Instance.new("UICorner", closeBtn).CornerRadius = UDim.new(1, 0)

local status = Instance.new("TextLabel")
status.Size = UDim2.new(1, -24, 0, 16)
status.Position = UDim2.new(0, 12, 0, 36)
status.BackgroundTransparency = 1
status.Text = "NPC-only • Neon red • Touch & Raycast enabled"
status.TextColor3 = Color3.fromRGB(140, 140, 140)
status.TextSize = 12
status.Font = Enum.Font.Gotham
status.TextXAlignment = Enum.TextXAlignment.Left
status.Parent = frame

-- Size input
local sizeLabel = Instance.new("TextLabel")
sizeLabel.Size = UDim2.new(0, 120, 0, 28)
sizeLabel.Position = UDim2.new(0, 12, 0, 56)
sizeLabel.BackgroundTransparency = 1
sizeLabel.Text = "Hitbox size"
sizeLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
sizeLabel.TextSize = 14
sizeLabel.Font = Enum.Font.Gotham
sizeLabel.TextXAlignment = Enum.TextXAlignment.Left
sizeLabel.Parent = frame

local sizeBox = Instance.new("TextBox")
sizeBox.Size = UDim2.new(0, 80, 0, 28)
sizeBox.Position = UDim2.new(0, 140, 0, 56)
sizeBox.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
sizeBox.Text = tostring(currentSize)
sizeBox.TextColor3 = Color3.fromRGB(255, 255, 255)
sizeBox.TextSize = 14
sizeBox.Font = Enum.Font.Gotham
sizeBox.ClearTextOnFocus = false
sizeBox.Parent = frame
Instance.new("UICorner", sizeBox).CornerRadius = UDim.new(0, 6)

-- Transparency input
local tLabel = Instance.new("TextLabel")
tLabel.Size = UDim2.new(0, 120, 0, 28)
tLabel.Position = UDim2.new(0, 12, 0, 92)
tLabel.BackgroundTransparency = 1
tLabel.Text = "Transparency"
tLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
tLabel.TextSize = 14
tLabel.Font = Enum.Font.Gotham
tLabel.TextXAlignment = Enum.TextXAlignment.Left
tLabel.Parent = frame

local tBox = Instance.new("TextBox")
tBox.Size = UDim2.new(0, 80, 0, 28)
tBox.Position = UDim2.new(0, 140, 0, 92)
tBox.BackgroundColor3 = Color3.fromRGB(35, 35, 35)
tBox.Text = string.format("%.2f", currentTransparency)
tBox.TextColor3 = Color3.fromRGB(255, 255, 255)
tBox.TextSize = 14
tBox.Font = Enum.Font.Gotham
tBox.ClearTextOnFocus = false
tBox.Parent = frame
Instance.new("UICorner", tBox).CornerRadius = UDim.new(0, 6)

-- Mode toggle
local modeBtn = Instance.new("TextButton")
modeBtn.Size = UDim2.new(0, 120, 0, 28)
modeBtn.Position = UDim2.new(0, 232, 0, 56)
modeBtn.BackgroundColor3 = Color3.fromRGB(80, 80, 80)
modeBtn.Text = "Mode: Proxy"
modeBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
modeBtn.TextSize = 14
modeBtn.Font = Enum.Font.GothamBold
modeBtn.Parent = frame
Instance.new("UICorner", modeBtn).CornerRadius = UDim.new(0, 6)

-- Toggle
local toggleBtn = Instance.new("TextButton")
toggleBtn.Size = UDim2.new(0, 140, 0, 36)
toggleBtn.Position = UDim2.new(0, 12, 0, 136)
toggleBtn.BackgroundColor3 = Color3.fromRGB(180, 35, 35)
toggleBtn.Text = "Enable"
toggleBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
toggleBtn.TextSize = 16
toggleBtn.Font = Enum.Font.GothamBold
toggleBtn.Parent = frame
Instance.new("UICorner", toggleBtn).CornerRadius = UDim.new(0, 8)

-- Update
local updateBtn = Instance.new("TextButton")
updateBtn.Size = UDim2.new(0, 140, 0, 36)
updateBtn.Position = UDim2.new(0, 168, 0, 136)
updateBtn.BackgroundColor3 = Color3.fromRGB(40, 120, 255)
updateBtn.Text = "Update"
updateBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
updateBtn.TextSize = 16
updateBtn.Font = Enum.Font.GothamBold
updateBtn.Parent = frame
Instance.new("UICorner", updateBtn).CornerRadius = UDim.new(0, 8)

-- Draggable
do
    local dragging, dragStart, startPos
    frame.InputBegan:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
            dragging = true
            dragStart = input.Position
            startPos = frame.Position
            input.Changed:Connect(function()
                if input.UserInputState == Enum.UserInputState.End then dragging = false end
            end)
        end
    end)
    UserInputService.InputChanged:Connect(function(input)
        if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
            local delta = input.Position - dragStart
            frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
        end
    end)
end

-- Logic
local function clampSize(v)
    v = math.floor(v + 0.5)
    if v < 3 then v = 3 end
    if v > 60 then v = 60 end
    return v
end

local function clampTrans(v)
    if v < 0 then v = 0 end
    if v > 0.95 then v = 0.95 end
    return v
end

local function parseInputs()
    local s = tonumber(sizeBox.Text)
    local t = tonumber(tBox.Text)
    if s then currentSize = clampSize(s) end
    if t then currentTransparency = clampTrans(t) end
    sizeBox.Text = tostring(currentSize)
    tBox.Text = string.format("%.2f", currentTransparency)
end

local function refreshAll()
    if not enabled then return end
    -- Re-apply based on current mode
    removeAll()
    applyAll(currentSize, currentTransparency)
end

modeBtn.MouseButton1Click:Connect(function()
    mode = (mode == MODE_PROXY) and MODE_RESIZE or MODE_PROXY
    modeBtn.Text = "Mode: " .. mode
    status.Text = (mode == MODE_PROXY)
        and "Proxy mode • Touch & Raycast enabled"
        or "Resize HRP mode • Most tools will register"
    refreshAll()
end)

updateBtn.MouseButton1Click:Connect(function()
    parseInputs()
    refreshAll()
end)

sizeBox.FocusLost:Connect(function() parseInputs(); refreshAll() end)
tBox.FocusLost:Connect(function() parseInputs(); refreshAll() end)

toggleBtn.MouseButton1Click:Connect(function()
    parseInputs()
    if not enabled then
        setEnabled(true)
        toggleBtn.Text = "Disable"
        toggleBtn.BackgroundColor3 = Color3.fromRGB(45, 160, 75)
        status.Text = string.format("%s • size %d • trans %.2f", mode, currentSize, currentTransparency)
    else
        setEnabled(false)
        toggleBtn.Text = "Enable"
        toggleBtn.BackgroundColor3 = Color3.fromRGB(180, 35, 35)
        status.Text = "Disabled"
    end
end)

closeBtn.MouseButton1Click:Connect(function()
    setEnabled(false)
    ui:Destroy()
end)

Features & Information

Max limit of 60 to prevent lag

Community Comments (3)

*rac3*rac3Aug 17, 2025

Made by me and universal

*rac3*rac3Aug 17, 2025

I have no thumbnail btw

IlovesinglemomsIlovesinglemomsJul 21, 2026

Can I change the size of the hitbox or its just that so it can function properly

More Scripts for Universal Scripts