remote keybinder aim
Key RequiredUniversal

remote keybinder aim

Universal Scriptreverb0012reverb0012 1.3K views 570 executesUpdated Dec 15, 2025
5.0/ 5(2 votes)
20100% Positive
Lua Script•1816 lines (73123 chars)
-- Remote Keybinder + Placement (placement fixes: sphere, StraightForward level, CustomPlacement follows entity)
-- Place as LocalScript in StarterGui (runs in PlayerGui)

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local HttpService = game:GetService("HttpService")
local Camera = workspace.CurrentCamera

local player = Players.LocalPlayer
local backpack = player:WaitForChild("Backpack")
local guiParent = player:WaitForChild("PlayerGui")
local character = player.Character or player.CharacterAdded:Wait()

-- --------------------
-- Small helpers
-- --------------------
local function trim(s) return (tostring(s):gsub("^%s*(.-)%s*$","%1")) end
local function safeGetMouse() local ok,m = pcall(function() return player:GetMouse() end) if ok then return m end return nil end
local function getMouseHitPos()
    local m = safeGetMouse()
    if not m then return nil end
    local ok, hit = pcall(function() return m.Hit end)
    if not ok or not hit then return nil end
    local p = hit.Position or (hit.p and hit.p)
    if typeof(p) == "Vector3" then return p end
    return nil
end
local function isRemote(inst) return inst and (inst:IsA("RemoteEvent") or inst:IsA("RemoteFunction")) end
local function keyEnumToName(k) if not k then return "<none>" end return tostring(k):gsub("Enum.KeyCode.","") end
local function nameToKeyEnum(name) if not name then return nil end local ok,e = pcall(function() return Enum.KeyCode[name] end) return ok and e or nil end

local function parseSingleToken(tok)
    tok = trim(tok)
    if tok == "" then return nil end
    local quoted = tok:match('^"(.*)"$') or tok:match("^'(.*)'$")
    if quoted then return tostring(quoted) end
    if tok:lower() == "true" then return true end
    if tok:lower() == "false" then return false end
    local n = tonumber(tok)
    if n then return n end
    local a,b,c = tok:match("^Vector3%.new%(%s*([-+]?%d*%.?%d+)%s*,%s*([-+]?%d*%.?%d+)%s*,%s*([-+]?%d*%.?%d+)%s*%)$")
    if a and b and c then return Vector3.new(tonumber(a), tonumber(b), tonumber(c)) end
    return tostring(tok)
end

local function parseArgsText(txt)
    txt = tostring(txt or "")
    txt = trim(txt)
    if txt == "" then return {} end
    local out = {}
    for token in txt:gmatch("([^,]+)") do
        local v = parseSingleToken(token)
        if v ~= nil then table.insert(out, v) end
    end
    return out
end

local function safeCallRemoteSingle(remote, argsTable, sendAsXYZ)
    if not remote or not remote.Parent then return false, "remote missing" end
    local ok, err = pcall(function()
        if sendAsXYZ then
            if #argsTable >= 1 and typeof(argsTable[1]) == "Vector3" then
                local v = argsTable[1]
                local rest = {}
                for i = 2, #argsTable do table.insert(rest, argsTable[i]) end
                local sendArgs = {v.X, v.Y, v.Z}
                for _,o in ipairs(rest) do table.insert(sendArgs, o) end
                if remote:IsA("RemoteEvent") then remote:FireServer(unpack(sendArgs)) else remote:InvokeServer(unpack(sendArgs)) end
            else
                if remote:IsA("RemoteEvent") then remote:FireServer(unpack(argsTable)) else remote:InvokeServer(unpack(argsTable)) end
            end
        else
            if remote:IsA("RemoteEvent") then remote:FireServer(unpack(argsTable)) else remote:InvokeServer(unpack(argsTable)) end
        end
    end)
    return ok, err
end

local function safeCallRemote(remoteOrList, argsTable, sendAsXYZ)
    if not remoteOrList then return false, "no remotes" end
    if typeof(remoteOrList) == "Instance" then
        return safeCallRemoteSingle(remoteOrList, argsTable, sendAsXYZ)
    elseif type(remoteOrList) == "table" then
        local anyOk = false
        local lastErr = nil
        for _,rm in ipairs(remoteOrList) do
            local ok, err = pcall(function() return safeCallRemoteSingle(rm, argsTable, sendAsXYZ) end)
            if ok and err ~= false then anyOk = true else lastErr = err end
        end
        return anyOk, lastErr
    else
        return false, "invalid remote type"
    end
end

-- --------------------
-- Prediction & humanoid cache
-- --------------------
local function getLocalReferencePos()
    local ch = player.Character
    if ch and ch.PrimaryPart then return ch.PrimaryPart.Position end
    if ch and ch:FindFirstChild("HumanoidRootPart") and ch.HumanoidRootPart:IsA("BasePart") then return ch.HumanoidRootPart.Position end
    if Camera then return Camera.CFrame.p end
    return Vector3.new(0,0,0)
end

local function getLocalForwardVector()
    local ch = player.Character
    if ch and ch.PrimaryPart then return ch.PrimaryPart.CFrame.LookVector end
    if Camera then return Camera.CFrame.LookVector end
    return Vector3.new(0,0,-1)
end

local function clampPredictionForSpeed(predX, predY, speed)
    if speed > 200 then
        if predX > 0 then predX = math.min(predX, 200 / speed) end
        if predY > 0 then predY = math.min(predY, 200 / speed) end
    end
    return predX, predY
end

local humanoidCache = {}
local humanoidCacheLock = false
local HUMANOID_CACHE_INTERVAL = 0.6
local function refreshHumanoidCache()
    if humanoidCacheLock then return end
    humanoidCacheLock = true
    local newCache = {}
    for _, child in ipairs(workspace:GetChildren()) do
        if child and child:IsA("Model") and child.Name ~= player.Name then
            local humanoid = child:FindFirstChildOfClass("Humanoid")
            if humanoid and humanoid.Health > 0 then
                local root = child:FindFirstChild("HumanoidRootPart") or child.PrimaryPart
                if root and root:IsA("BasePart") then
                    table.insert(newCache, { model = child, root = root, humanoid = humanoid })
                end
            end
        end
    end
    humanoidCache = newCache
    humanoidCacheLock = false
end
task.spawn(function()
    while true do
        pcall(refreshHumanoidCache)
        task.wait(HUMANOID_CACHE_INTERVAL)
    end
end)

local function getNearestPlayerPredictedPos(predX, predY)
    predX = tonumber(predX) or 0; predY = tonumber(predY) or 0
    local refPos = getLocalReferencePos()
    local bestPl, bestPos, bestDist = nil, nil, math.huge
    for _,pl in ipairs(Players:GetPlayers()) do
        if pl ~= player and pl.Character then
            local hrp = pl.Character:FindFirstChild("HumanoidRootPart") or pl.Character.PrimaryPart
            if hrp and hrp:IsA("BasePart") then
                local d = (hrp.Position - refPos).Magnitude
                if d < bestDist then bestDist = d; bestPl = pl; bestPos = hrp.Position end
            end
        end
    end
    if not bestPl or not bestPos then return nil, nil end
    local hrpInst = bestPl.Character and (bestPl.Character:FindFirstChild("HumanoidRootPart") or bestPl.Character.PrimaryPart)
    local vel = Vector3.new(0,0,0)
    if hrpInst and hrpInst:IsA("BasePart") then vel = hrpInst.Velocity or Vector3.new(0,0,0) end
    predX, predY = clampPredictionForSpeed(predX, predY, vel.Magnitude)
    local predicted = bestPos + Vector3.new(vel.X * predX, vel.Y * predY, vel.Z * predX)
    return predicted, bestPl
end

local function getNearestHumanoidPredictedPos(predX, predY)
    predX = tonumber(predX) or 0; predY = tonumber(predY) or 0
    local refPos = getLocalReferencePos()
    local bestEntry, bestDist = nil, math.huge
    for _,entry in ipairs(humanoidCache) do
        local root, humanoid = entry.root, entry.humanoid
        if root and humanoid and humanoid.Health > 0 then
            local ok,pos = pcall(function() return root.Position end)
            if ok and pos then
                local d = (pos - refPos).Magnitude
                if d < bestDist then bestDist = d; bestEntry = entry end
            end
        end
    end
    if not bestEntry then
        for _,child in ipairs(workspace:GetChildren()) do
            if child and child:IsA("Model") and child.Name ~= player.Name then
                local humanoid = child:FindFirstChildOfClass("Humanoid")
                if humanoid and humanoid.Health > 0 then
                    local root = child:FindFirstChild("HumanoidRootPart") or child.PrimaryPart
                    if root and root:IsA("BasePart") then
                        local ok,pos = pcall(function() return root.Position end)
                        if ok and pos then
                            local d = (pos - refPos).Magnitude
                            if d < bestDist then bestDist = d; bestEntry = {model = child, root = root, humanoid = humanoid} end
                        end
                    end
                end
            end
        end
    end
    if not bestEntry or not bestEntry.root then return nil, nil end
    local rootPart = bestEntry.root
    local vel = Vector3.new(0,0,0)
    if rootPart and rootPart:IsA("BasePart") then vel = rootPart.Velocity or Vector3.new(0,0,0) end
    predX, predY = clampPredictionForSpeed(predX, predY, vel.Magnitude)
    local predicted = rootPart.Position + Vector3.new(vel.X * predX, vel.Y * predY, vel.Z * predX)
    return predicted, bestEntry.model
end

-- --------------------
-- Placement system state & helpers (fixed)
-- --------------------
local placement = {
    part = nil,
    billboard = nil,
    studs = 6,
    lastPos = nil,
    selectedModel = nil,
    stickToEntity = false,
    clickCapture = false
}

local function findModelAdornee(model)
    if not model then return nil end
    local root = model:FindFirstChild("HumanoidRootPart") or model.PrimaryPart
    if root and root:IsA("BasePart") then return root end
    -- fallback: find the first BasePart
    for _,v in ipairs(model:GetDescendants()) do
        if v:IsA("BasePart") then return v end
    end
    return nil
end

local function createPlacementPartIfNeeded()
    if placement.part and placement.part.Parent then return end
    if placement.part then pcall(function() placement.part:Destroy() end) end
    local p = Instance.new("Part")
    p.Name = "RKB_PlacementPart"
    p.Size = Vector3.new(1.2,1.2,1.2)
    p.Shape = Enum.PartType.Ball -- sphere
    p.Anchored = true
    p.CanCollide = false
    p.Transparency = 0.45
    p.Color = Color3.fromRGB(70, 200, 120)
    p.Material = Enum.Material.SmoothPlastic
    p.Parent = workspace
    placement.part = p

    if placement.billboard then pcall(function() placement.billboard:Destroy() end) end
    local bb = Instance.new("BillboardGui")
    bb.Name = "RKB_PlacementBB"
    bb.Size = UDim2.new(0,120,0,36)
    bb.Adornee = p
    bb.AlwaysOnTop = true
    local lbl = Instance.new("TextLabel", bb)
    lbl.Size = UDim2.new(1,0,1,0)
    lbl.BackgroundTransparency = 1
    lbl.Text = "Placement"
    lbl.Font = Enum.Font.GothamBold
    lbl.TextSize = 14
    lbl.TextColor3 = Color3.new(1,1,1)
    lbl.TextStrokeTransparency = 0.6
    bb.Parent = p
    placement.billboard = bb
end

local function destroyPlacementVisual()
    if placement.billboard then pcall(function() placement.billboard:Destroy() end) placement.billboard = nil end
    if placement.part then pcall(function() placement.part:Destroy() end) placement.part = nil end
end

local function createSelectionBillboardForModel(model)
    if not model then return end
    local adornee = findModelAdornee(model)
    if not adornee then return end
    -- remove previous billboard attached to model
    local existing = model:FindFirstChild("RKB_SelectedBB")
    if existing then existing:Destroy() end
    local bb = Instance.new("BillboardGui")
    bb.Name = "RKB_SelectedBB"
    bb.Size = UDim2.new(0,160,0,36)
    bb.AlwaysOnTop = true
    bb.Adornee = adornee
    local lbl = Instance.new("TextLabel", bb)
    lbl.Size = UDim2.new(1,0,1,0)
    lbl.BackgroundTransparency = 0.6
    lbl.BackgroundColor3 = Color3.fromRGB(30,30,40)
    lbl.Text = "Selected: "..tostring(model.Name)
    lbl.Font = Enum.Font.GothamBold
    lbl.TextSize = 14
    lbl.TextColor3 = Color3.new(1,1,1)
    lbl.TextStrokeTransparency = 0.6
    bb.Parent = model
end

local function clearSelectionBillboard(model)
    if not model then return end
    local existing = model:FindFirstChild("RKB_SelectedBB")
    if existing then existing:Destroy() end
end

local function updatePlacementVisual(aimMode)
    if aimMode == "StraightForward" then
        createPlacementPartIfNeeded()
        -- flatten forward so it doesn't aim up
        local forward = getLocalForwardVector()
        forward = Vector3.new(forward.X, 0, forward.Z)
        if forward.Magnitude == 0 then
            forward = Camera and Vector3.new(Camera.CFrame.LookVector.X, 0, Camera.CFrame.LookVector.Z) or Vector3.new(0,0,-1)
        end
        local base = getLocalReferencePos()
        local studs = tonumber(placement.studs) or 6
        local pos = base + (forward.Unit * studs)
        -- lock Y to local reference Y (prevents aiming up)
        pos = Vector3.new(pos.X, base.Y, pos.Z)
        placement.lastPos = pos
        if placement.part then
            placement.part.Position = pos
            if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then
                placement.billboard:FindFirstChildOfClass("TextLabel").Text = ("Straight: %.1f studs"):format(studs)
            end
        end
        if placement.selectedModel then
            clearSelectionBillboard(placement.selectedModel)
            placement.selectedModel = nil
        end
    elseif aimMode == "CustomPlacement" then
        createPlacementPartIfNeeded()
        -- if a model was selected, always follow the model's adornee (Primary/HumanoidRootPart)
        if placement.selectedModel then
            local adornee = findModelAdornee(placement.selectedModel)
            if adornee then
                local pos = adornee.Position
                placement.lastPos = pos
                placement.part.Position = pos
                if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then
                    placement.billboard:FindFirstChildOfClass("TextLabel").Text = ("Stuck to: %s"):format(tostring(placement.selectedModel.Name))
                end
                -- ensure selection billboard exists
                createSelectionBillboardForModel(placement.selectedModel)
            else
                -- fallback to last known pos
                if placement.lastPos then
                    placement.part.Position = placement.lastPos
                    if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then
                        placement.billboard:FindFirstChildOfClass("TextLabel").Text = "Custom: "..tostring(placement.lastPos)
                    end
                else
                    placement.part.Position = getLocalReferencePos() + Vector3.new(0,-300,0)
                end
            end
        elseif placement.lastPos then
            placement.part.Position = placement.lastPos
            if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then
                placement.billboard:FindFirstChildOfClass("TextLabel").Text = "Custom: "..tostring(placement.lastPos)
            end
        else
            -- nothing set yet: hide
            placement.part.Position = getLocalReferencePos() + Vector3.new(0,-300,0)
            if placement.billboard and placement.billboard:FindFirstChildOfClass("TextLabel") then
                placement.billboard:FindFirstChildOfClass("TextLabel").Text = "Custom: <none>"
            end
        end
    else
        -- not a placement mode: move out of view but remember data
        if placement.part then
            placement.part.Position = getLocalReferencePos() + Vector3.new(0,-300,0)
        end
        if placement.selectedModel and not placement.stickToEntity then
            clearSelectionBillboard(placement.selectedModel)
            placement.selectedModel = nil
        end
    end
end

-- keep RenderStepped visual updates (reads global aim mode set by UI)
RunService.RenderStepped:Connect(function()
    if _G.RKB_currentAimMode then
        pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end)
    end
end)

-- --------------------
-- Persistence storage helpers
-- --------------------
local settingsFolder = player:FindFirstChild("RemoteKeybinderSettings")
if not settingsFolder then
    settingsFolder = Instance.new("Folder")
    settingsFolder.Name = "RemoteKeybinderSettings"
    settingsFolder.Parent = player
end

local function saveBindingToFolder(keyName, bindingTable)
    if not keyName or not bindingTable then return false, "invalid params" end
    local data = {
        key = keyName,
        remotePath = bindingTable.remotePath or "",
        remotePaths = bindingTable.remotePaths or nil,
        extraArgsText = bindingTable.extraArgsText or "",
        hold = bindingTable.hold and true or false,
        interval = tonumber(bindingTable.interval) or 0.12,
        mode = bindingTable.mode or "Mouse",
        predictionX = tonumber(bindingTable.predictionX) or 0,
        predictionY = tonumber(bindingTable.predictionY) or 0,
        argFormat = bindingTable.argFormat or "Vector3",
        placeStuds = tonumber(bindingTable.placeStuds) or nil,
        placeLastPos = bindingTable.placeLastPos or nil,
        placeStick = bindingTable.placeStick and true or false
    }
    local s = HttpService:JSONEncode(data)
    local name = "binding_" .. keyName
    local existing = settingsFolder:FindFirstChild(name)
    if existing and existing:IsA("StringValue") then existing.Value = s else
        local sv = Instance.new("StringValue")
        sv.Name = name
        sv.Value = s
        sv.Parent = settingsFolder
    end
    return true
end

local function deleteSavedBinding(keyName)
    if not keyName then return false end
    local name = "binding_" .. keyName
    local existing = settingsFolder:FindFirstChild(name)
    if existing then existing:Destroy(); return true end
    return false
end

local function loadSavedBindingsIntoTable()
    local out = {}
    for _,child in ipairs(settingsFolder:GetChildren()) do
        if child:IsA("StringValue") and child.Name:match("^binding_") then
            local ok, data = pcall(function() return HttpService:JSONDecode(child.Value) end)
            if ok and type(data) == "table" and data.key then out[data.key] = data end
        end
    end
    return out
end

local function findInstanceByFullName(fullPath)
    if not fullPath or fullPath == "" then return nil end
    local function scanContainer(container)
        if not container then return nil end
        for _,inst in ipairs(container:GetDescendants()) do
            local ok, p = pcall(function() return inst:GetFullName() end)
            if ok and p == fullPath then return inst end
        end
        return nil
    end
    local res = scanContainer(backpack)
    if res then return res end
    res = scanContainer(character)
    if res then return res end
    return nil
end

-- --------------------
-- UI BUILD + placement controls (kept same layout as previous)
-- --------------------
local existingGui = guiParent:FindFirstChild("PolishedRemoteKeybinder")
if existingGui then existingGui:Destroy() end

local ScreenGui = Instance.new("ScreenGui")
ScreenGui.Name = "PolishedRemoteKeybinder"
ScreenGui.ResetOnSpawn = false
ScreenGui.Parent = guiParent

local frameMain = Instance.new("Frame")
frameMain.Name = "Main"
frameMain.Size = UDim2.new(0, 920, 0, 520)
frameMain.Position = UDim2.new(0.5, -460, 0.5, -260)
frameMain.BackgroundColor3 = Color3.fromRGB(20,20,26)
frameMain.BorderSizePixel = 0
frameMain.Active = true
frameMain.Draggable = true
frameMain.Parent = ScreenGui

local header = Instance.new("Frame", frameMain)
header.Size = UDim2.new(1,0,0,64)
header.Position = UDim2.new(0,0,0,0)
header.BackgroundColor3 = Color3.fromRGB(28,28,36)
header.BorderSizePixel = 0

local title = Instance.new("TextLabel", header)
title.Text = "Remote Keybinder — Inventory (Backpack + Character)"
title.Font = Enum.Font.GothamBold
title.TextSize = 18
title.TextColor3 = Color3.fromRGB(235,235,235)
title.BackgroundTransparency = 1
title.Size = UDim2.new(0.7, -20, 1, 0)
title.Position = UDim2.new(0, 14, 0, 0)
title.TextXAlignment = Enum.TextXAlignment.Left

local subtitle = Instance.new("TextLabel", header)
subtitle.Text = "Click entries to inspect, or toggle Multi-Select below the list to pick several then bind."
subtitle.Font = Enum.Font.Gotham
subtitle.TextSize = 12
subtitle.TextColor3 = Color3.fromRGB(180,180,190)
subtitle.BackgroundTransparency = 1
subtitle.Size = UDim2.new(0.7, -20, 1, 0)
subtitle.Position = UDim2.new(0, 14, 0, 26)
subtitle.TextXAlignment = Enum.TextXAlignment.Left

local reloadBtn = Instance.new("TextButton", header)
reloadBtn.Name = "Reload"
reloadBtn.Size = UDim2.new(0, 110, 0, 36)
reloadBtn.Position = UDim2.new(1, -360, 0, 14)
reloadBtn.BackgroundColor3 = Color3.fromRGB(56,56,76)
reloadBtn.Text = "Reload (R)"
reloadBtn.Font = Enum.Font.Gotham
reloadBtn.TextSize = 14
reloadBtn.TextColor3 = Color3.fromRGB(240,240,240)
reloadBtn.BorderSizePixel = 0

local resetToolsBtn = Instance.new("TextButton", header)
resetToolsBtn.Name = "ResetTools"
resetToolsBtn.Size = UDim2.new(0, 130, 0, 36)
resetToolsBtn.Position = UDim2.new(1, -236, 0, 14)
resetToolsBtn.BackgroundColor3 = Color3.fromRGB(96,64,32)
resetToolsBtn.Text = "Reset Tools"
resetToolsBtn.Font = Enum.Font.Gotham
resetToolsBtn.TextSize = 14
resetToolsBtn.TextColor3 = Color3.fromRGB(240,240,240)
resetToolsBtn.BorderSizePixel = 0

-- left pane (remotes)
local leftPane = Instance.new("Frame", frameMain)
leftPane.Position = UDim2.new(0, 14, 0, 74)
leftPane.Size = UDim2.new(0, 420, 0, 420)
leftPane.BackgroundTransparency = 1

local leftTitle = Instance.new("TextLabel", leftPane)
leftTitle.Size = UDim2.new(1, 0, 0, 20)
leftTitle.Position = UDim2.new(0,0,0,0)
leftTitle.BackgroundTransparency = 1
leftTitle.Font = Enum.Font.Gotham
leftTitle.TextSize = 13
leftTitle.TextColor3 = Color3.fromRGB(210,210,210)
leftTitle.Text = "Detected inventory remotes (click to inspect)"

local leftScroll = Instance.new("ScrollingFrame", leftPane)
leftScroll.Size = UDim2.new(1, 0, 1, -80)
leftScroll.Position = UDim2.new(0, 0, 0, 28)
leftScroll.BackgroundTransparency = 1
leftScroll.ScrollBarThickness = 6

local leftListLayout = Instance.new("UIListLayout", leftScroll)
leftListLayout.Padding = UDim.new(0,8)
leftListLayout.SortOrder = Enum.SortOrder.LayoutOrder

-- multi-select control area (under the remote list)
local multiArea = Instance.new("Frame", leftPane)
multiArea.Position = UDim2.new(0, 0, 1, -46)
multiArea.Size = UDim2.new(1, 0, 0, 46)
multiArea.BackgroundTransparency = 1

local multiToggle = Instance.new("TextButton", multiArea)
multiToggle.Position = UDim2.new(0,6,0,6)
multiToggle.Size = UDim2.new(0,140,0,34)
multiToggle.Text = "Multi-Select: Off"
multiToggle.Font = Enum.Font.Gotham
multiToggle.TextSize = 14
multiToggle.BackgroundColor3 = Color3.fromRGB(64,64,76)
multiToggle.TextColor3 = Color3.fromRGB(240,240,240)
multiToggle.BorderSizePixel = 0

local clearSelectionBtn = Instance.new("TextButton", multiArea)
clearSelectionBtn.Position = UDim2.new(0,156,0,6)
clearSelectionBtn.Size = UDim2.new(0,110,0,34)
clearSelectionBtn.Text = "Clear Selection"
clearSelectionBtn.Font = Enum.Font.Gotham
clearSelectionBtn.TextSize = 14
clearSelectionBtn.BackgroundColor3 = Color3.fromRGB(84,44,44)
clearSelectionBtn.TextColor3 = Color3.fromRGB(240,240,240)
clearSelectionBtn.BorderSizePixel = 0

local clearMultiBindsBtn = Instance.new("TextButton", multiArea)
clearMultiBindsBtn.Position = UDim2.new(0,276,0,6)
clearMultiBindsBtn.Size = UDim2.new(0,136,0,34)
clearMultiBindsBtn.Text = "Clear Multi Binds (Del)"
clearMultiBindsBtn.Font = Enum.Font.Gotham
clearMultiBindsBtn.TextSize = 13
clearMultiBindsBtn.BackgroundColor3 = Color3.fromRGB(42,122,255)
clearMultiBindsBtn.TextColor3 = Color3.fromRGB(240,240,240)
clearMultiBindsBtn.BorderSizePixel = 0

-- right pane (inspector + placement controls)
local rightPane = Instance.new("Frame", frameMain)
rightPane.Position = UDim2.new(0, 448, 0, 74)
rightPane.Size = UDim2.new(0, 464, 0, 420)
rightPane.BackgroundTransparency = 1

local inspectorTitle = Instance.new("TextLabel", rightPane)
inspectorTitle.Position = UDim2.new(0,0,0,0)
inspectorTitle.Size = UDim2.new(1,0,0,20)
inspectorTitle.BackgroundTransparency = 1
inspectorTitle.Font = Enum.Font.Gotham
inspectorTitle.TextSize = 13
inspectorTitle.TextColor3 = Color3.fromRGB(210,210,210)
inspectorTitle.Text = "Inspector & Keybinds"

local lblRemote = Instance.new("TextLabel", rightPane)
lblRemote.Position = UDim2.new(0,0,0,28)
lblRemote.Size = UDim2.new(1,0,0,20)
lblRemote.BackgroundTransparency = 1
lblRemote.Font = Enum.Font.Gotham
lblRemote.TextSize = 12
lblRemote.TextColor3 = Color3.fromRGB(220,220,220)
lblRemote.Text = "Remote: <none>"

local lblParent = Instance.new("TextLabel", rightPane)
lblParent.Position = UDim2.new(0,0,0,48)
lblParent.Size = UDim2.new(1,0,0,16)
lblParent.BackgroundTransparency = 1
lblParent.Font = Enum.Font.Gotham
lblParent.TextSize = 11
lblParent.TextColor3 = Color3.fromRGB(170,170,170)
lblParent.Text = "Parent: <none>"

local lblType = Instance.new("TextLabel", rightPane)
lblType.Position = UDim2.new(0,0,0,66)
lblType.Size = UDim2.new(1,0,0,16)
lblType.BackgroundTransparency = 1
lblType.Font = Enum.Font.Gotham
lblType.TextSize = 11
lblType.TextColor3 = Color3.fromRGB(170,170,170)
lblType.Text = "Type: <none>"

local aimLabel = Instance.new("TextLabel", rightPane)
aimLabel.Position = UDim2.new(0,0,0,92)
aimLabel.Size = UDim2.new(0,220,0,18)
aimLabel.BackgroundTransparency = 1
aimLabel.Font = Enum.Font.Gotham
aimLabel.TextSize = 12
aimLabel.TextColor3 = Color3.fromRGB(200,200,200)
aimLabel.Text = "Aim mode:"

local aimDropdown = Instance.new("TextButton", rightPane)
aimDropdown.Position = UDim2.new(0,0,0,114)
aimDropdown.Size = UDim2.new(0,220,0,28)
aimDropdown.Font = Enum.Font.Gotham
aimDropdown.TextSize = 12
aimDropdown.TextColor3 = Color3.fromRGB(240,240,240)
aimDropdown.Text = "Mouse" -- cycles: Mouse, NearestPlayer, NearestHumanoid, StraightForward, CustomPlacement
aimDropdown.BackgroundColor3 = Color3.fromRGB(48,48,62)
aimDropdown.BorderSizePixel = 0

local predXLabel = Instance.new("TextLabel", rightPane)
predXLabel.Position = UDim2.new(0,232,0,92)
predXLabel.Size = UDim2.new(0,110,0,18)
predXLabel.BackgroundTransparency = 1
predXLabel.Font = Enum.Font.Gotham
predXLabel.TextSize = 12
predXLabel.TextColor3 = Color3.fromRGB(200,200,200)
predXLabel.Text = "Prediction X (s):"

local predXBox = Instance.new("TextBox", rightPane)
predXBox.Position = UDim2.new(0,232,0,114)
predXBox.Size = UDim2.new(0,66,0,28)
predXBox.BackgroundColor3 = Color3.fromRGB(34,34,40)
predXBox.PlaceholderText = "0.15"
predXBox.Text = "0.15"
predXBox.ClearTextOnFocus = false
predXBox.TextColor3 = Color3.fromRGB(230,230,230)
predXBox.Font = Enum.Font.Gotham
predXBox.TextSize = 12

local predYLabel = Instance.new("TextLabel", rightPane)
predYLabel.Position = UDim2.new(0,302,0,92)
predYLabel.Size = UDim2.new(0,160,0,18)
predYLabel.BackgroundTransparency = 1
predYLabel.Font = Enum.Font.Gotham
predYLabel.TextSize = 12
predYLabel.TextColor3 = Color3.fromRGB(200,200,200)
predYLabel.Text = "Prediction Y (s):"

local predYBox = Instance.new("TextBox", rightPane)
predYBox.Position = UDim2.new(0,302,0,114)
predYBox.Size = UDim2.new(0,66,0,28)
predYBox.BackgroundColor3 = Color3.fromRGB(34,34,40)
predYBox.PlaceholderText = "0.05"
predYBox.Text = "0.05"
predYBox.ClearTextOnFocus = false
predYBox.TextColor3 = Color3.fromRGB(230,230,230)
predYBox.Font = Enum.Font.Gotham
predYBox.TextSize = 12

-- Place studs / click controls
local placeLabel = Instance.new("TextLabel", rightPane)
placeLabel.Position = UDim2.new(0,0,0,154)
placeLabel.Size = UDim2.new(0,140,0,18)
placeLabel.BackgroundTransparency = 1
placeLabel.Font = Enum.Font.Gotham
placeLabel.TextSize = 12
placeLabel.TextColor3 = Color3.fromRGB(200,200,200)
placeLabel.Text = "Place studs:"

local placeStudsBox = Instance.new("TextBox", rightPane)
placeStudsBox.Position = UDim2.new(0,140,0,150)
placeStudsBox.Size = UDim2.new(0,60,0,26)
placeStudsBox.BackgroundColor3 = Color3.fromRGB(34,34,40)
placeStudsBox.PlaceholderText = "6"
placeStudsBox.Text = tostring(placement.studs)
placeStudsBox.ClearTextOnFocus = false
placeStudsBox.TextColor3 = Color3.fromRGB(230,230,230)
placeStudsBox.Font = Enum.Font.Gotham
placeStudsBox.TextSize = 12

local placeClickBtn = Instance.new("TextButton", rightPane)
placeClickBtn.Position = UDim2.new(0,220,0,150)
placeClickBtn.Size = UDim2.new(0,140,0,26)
placeClickBtn.Font = Enum.Font.Gotham
placeClickBtn.Text = "Place / Select (Click)"
placeClickBtn.BackgroundColor3 = Color3.fromRGB(56,56,76)
placeClickBtn.TextColor3 = Color3.fromRGB(240,240,240)
placeClickBtn.TextSize = 12
placeClickBtn.BorderSizePixel = 0

local stickToggle = Instance.new("TextButton", rightPane)
stickToggle.Position = UDim2.new(0,370,0,150)
stickToggle.Size = UDim2.new(0,86,0,26)
stickToggle.Font = Enum.Font.Gotham
stickToggle.Text = "Stick: Off"
stickToggle.BackgroundColor3 = Color3.fromRGB(44,44,60)
stickToggle.TextColor3 = Color3.fromRGB(230,230,230)
stickToggle.TextSize = 12
stickToggle.BorderSizePixel = 0

local placementSelectedLabel = Instance.new("TextLabel", rightPane)
placementSelectedLabel.Position = UDim2.new(0,0,0,182)
placementSelectedLabel.Size = UDim2.new(1,0,0,18)
placementSelectedLabel.BackgroundTransparency = 1
placementSelectedLabel.Font = Enum.Font.Gotham
placementSelectedLabel.TextSize = 12
placementSelectedLabel.TextColor3 = Color3.fromRGB(200,200,200)
placementSelectedLabel.Text = "Selected placement: <none>"

-- rest of previous UI (format, args, keybinds, etc.)
local formatLabel = Instance.new("TextLabel", rightPane)
formatLabel.Position = UDim2.new(0,0,0,206)
formatLabel.Size = UDim2.new(0,200,0,18)
formatLabel.BackgroundTransparency = 1
formatLabel.Font = Enum.Font.Gotham
formatLabel.TextSize = 12
formatLabel.TextColor3 = Color3.fromRGB(200,200,200)
formatLabel.Text = "Arg format:"

local formatDropdown = Instance.new("TextButton", rightPane)
formatDropdown.Position = UDim2.new(0,0,0,228)
formatDropdown.Size = UDim2.new(0,120,0,26)
formatDropdown.Font = Enum.Font.Gotham
formatDropdown.TextSize = 12
formatDropdown.TextColor3 = Color3.fromRGB(240,240,240)
formatDropdown.Text = "Vector3"
formatDropdown.BackgroundColor3 = Color3.fromRGB(48,48,62)
formatDropdown.BorderSizePixel = 0

local extraLabel = Instance.new("TextLabel", rightPane)
extraLabel.Position = UDim2.new(0,0,0,262)
extraLabel.Size = UDim2.new(1,0,0,18)
extraLabel.BackgroundTransparency = 1
extraLabel.Font = Enum.Font.Gotham
extraLabel.TextSize = 12
extraLabel.TextColor3 = Color3.fromRGB(180,180,180)
extraLabel.Text = "Extra args (comma-separated):"

local argsBox = Instance.new("TextBox", rightPane)
argsBox.Position = UDim2.new(0,0,0,284)
argsBox.Size = UDim2.new(1,-12,0,64)
argsBox.BackgroundColor3 = Color3.fromRGB(34,34,40)
argsBox.ClearTextOnFocus = false
argsBox.TextWrap = true
argsBox.MultiLine = true
argsBox.Text = ""
argsBox.TextColor3 = Color3.fromRGB(230,230,230)
argsBox.Font = Enum.Font.Gotham
argsBox.TextSize = 12

local setKeyBtn = Instance.new("TextButton", rightPane)
setKeyBtn.Position = UDim2.new(0,0,1,-124)
setKeyBtn.Size = UDim2.new(0,160,0,36)
setKeyBtn.BackgroundColor3 = Color3.fromRGB(64,64,88)
setKeyBtn.Font = Enum.Font.Gotham
setKeyBtn.Text = "Set Keybind (single)"
setKeyBtn.TextSize = 13
setKeyBtn.TextColor3 = Color3.fromRGB(240,240,240)
setKeyBtn.BorderSizePixel = 0

local bindSelectedBtn = Instance.new("TextButton", rightPane)
bindSelectedBtn.Position = UDim2.new(0,170,1,-124)
bindSelectedBtn.Size = UDim2.new(0,160,0,36)
bindSelectedBtn.BackgroundColor3 = Color3.fromRGB(56,96,120)
bindSelectedBtn.Font = Enum.Font.Gotham
bindSelectedBtn.Text = "Bind Selected (multi)"
bindSelectedBtn.TextSize = 13
bindSelectedBtn.TextColor3 = Color3.fromRGB(240,240,240)
bindSelectedBtn.BorderSizePixel = 0

local selectedCountLabel = Instance.new("TextLabel", bindSelectedBtn)
selectedCountLabel.Size = UDim2.new(0,56,0,28)
selectedCountLabel.Position = UDim2.new(1,-62,0,4)
selectedCountLabel.BackgroundTransparency = 1
selectedCountLabel.Font = Enum.Font.Gotham
selectedCountLabel.TextSize = 13
selectedCountLabel.TextColor3 = Color3.fromRGB(220,220,220)
selectedCountLabel.Text = "0"

local assignedLabel = Instance.new("TextLabel", rightPane)
assignedLabel.Position = UDim2.new(0,0,1,-84)
assignedLabel.Size = UDim2.new(1,0,0,24)
assignedLabel.BackgroundTransparency = 1
assignedLabel.Font = Enum.Font.Gotham
assignedLabel.TextSize = 12
assignedLabel.Text = "Assigned: <none>"
assignedLabel.TextColor3 = Color3.fromRGB(200,200,200)

local holdToggle = Instance.new("TextButton", rightPane)
holdToggle.Position = UDim2.new(0,0,1,-52)
holdToggle.Size = UDim2.new(0,120,0,28)
holdToggle.BackgroundColor3 = Color3.fromRGB(44,44,60)
holdToggle.Font = Enum.Font.Gotham
holdToggle.Text = "Hold mode"
holdToggle.TextSize = 12
holdToggle.TextColor3 = Color3.fromRGB(230,230,230)
holdToggle.BorderSizePixel = 0

local intervalLabel = Instance.new("TextLabel", rightPane)
intervalLabel.Position = UDim2.new(0,132,1,-52)
intervalLabel.Size = UDim2.new(0,120,0,18)
intervalLabel.BackgroundTransparency = 1
intervalLabel.Font = Enum.Font.Gotham
intervalLabel.TextSize = 11
intervalLabel.Text = "Interval (s):"
intervalLabel.TextColor3 = Color3.fromRGB(180,180,180)

local intervalBox = Instance.new("TextBox", rightPane)
intervalBox.Position = UDim2.new(0,132,1,-34)
intervalBox.Size = UDim2.new(0,80,0,28)
intervalBox.BackgroundColor3 = Color3.fromRGB(34,34,40)
intervalBox.Text = "0.12"
intervalBox.ClearTextOnFocus = false
intervalBox.Font = Enum.Font.Gotham
intervalBox.TextSize = 12
intervalBox.TextColor3 = Color3.fromRGB(230,230,230)

local saveBtn = Instance.new("TextButton", rightPane)
saveBtn.Position = UDim2.new(0,0,1, -4)
saveBtn.Size = UDim2.new(0,86,0,30)
saveBtn.Font = Enum.Font.Gotham
saveBtn.Text = "Save"
saveBtn.BackgroundColor3 = Color3.fromRGB(36,120,44)
saveBtn.TextSize = 12
saveBtn.TextColor3 = Color3.fromRGB(240,240,240)
saveBtn.BorderSizePixel = 0

local updateBtn = Instance.new("TextButton", rightPane)
updateBtn.Position = UDim2.new(0,96,1,-4)
updateBtn.Size = UDim2.new(0,86,0,30)
updateBtn.Font = Enum.Font.Gotham
updateBtn.Text = "Update"
updateBtn.BackgroundColor3 = Color3.fromRGB(52,140,46)
updateBtn.TextSize = 12
updateBtn.TextColor3 = Color3.fromRGB(240,240,240)
updateBtn.BorderSizePixel = 0

local loadBtn = Instance.new("TextButton", rightPane)
loadBtn.Position = UDim2.new(0,192,1,-4)
loadBtn.Size = UDim2.new(0,120,0,30)
loadBtn.Font = Enum.Font.Gotham
loadBtn.Text = "Load Saved"
loadBtn.BackgroundColor3 = Color3.fromRGB(60,60,84)
loadBtn.TextSize = 12
loadBtn.TextColor3 = Color3.fromRGB(240,240,240)
loadBtn.BorderSizePixel = 0

local fireBtn = Instance.new("TextButton", rightPane)
fireBtn.Position = UDim2.new(0,324,1,-4)
fireBtn.Size = UDim2.new(0,86,0,30)
fireBtn.Font = Enum.Font.Gotham
fireBtn.Text = "Fire Now"
fireBtn.TextSize = 12
fireBtn.TextColor3 = Color3.fromRGB(240,240,240)
fireBtn.BackgroundColor3 = Color3.fromRGB(80,40,40)
fireBtn.BorderSizePixel = 0

local statusBar = Instance.new("TextLabel", frameMain)
statusBar.Position = UDim2.new(0,14,1,-32)
statusBar.Size = UDim2.new(1,-28,0,24)
statusBar.BackgroundTransparency = 1
statusBar.Font = Enum.Font.Gotham
statusBar.TextSize = 12
statusBar.TextColor3 = Color3.fromRGB(200,200,200)
statusBar.Text = "Ready."

-- --------------------
-- State (keeps older state variables)
-- --------------------
local entries = {}
local infos = {}
local selectedInfo = nil
local selectedSet = {}
local capturingKey = false
local capturingConn = nil
local bindings = {}
local pendingSaved = {}
local multiSelectMode = false

local NORMAL_BG = Color3.fromRGB(36,36,44)
local HOVER_BG = Color3.fromRGB(46,46,68)
local SELECT_BG = Color3.fromRGB(42,122,255)

-- store current aim mode so RenderStepped update can reference
_G.RKB_currentAimMode = aimDropdown.Text

-- --------------------
-- createEntryForRemote must be defined BEFORE scanInventoryOnce uses it (fixed)
-- --------------------
local function createEntryForRemote(remote)
    if not remote or not remote.Parent then return end
    if entries[remote] then return end
    local info = { remote = remote, lastArgs = {}, lastArgsText = "" }
    table.insert(infos, info)

    local frame = Instance.new("Frame")
    frame.Size = UDim2.new(1, -12, 0, 60)
    frame.BackgroundColor3 = NORMAL_BG
    frame.BorderSizePixel = 0
    frame.Parent = leftScroll

    local nameLbl = Instance.new("TextLabel", frame)
    nameLbl.Size = UDim2.new(1, -12, 0, 22)
    nameLbl.Position = UDim2.new(0, 6, 0, 6)
    nameLbl.BackgroundTransparency = 1
    nameLbl.Font = Enum.Font.GothamBold
    nameLbl.TextSize = 12
    nameLbl.TextColor3 = Color3.fromRGB(230,230,230)
    local ok, fullname = pcall(function() return remote:GetFullName() end)
    nameLbl.Text = ok and fullname or tostring(remote.Name)

    local parentLbl = Instance.new("TextLabel", frame)
    parentLbl.Size = UDim2.new(1, -12, 0, 14)
    parentLbl.Position = UDim2.new(0,6,0,30)
    parentLbl.BackgroundTransparency = 1
    parentLbl.Font = Enum.Font.Gotham
    parentLbl.TextSize = 11
    parentLbl.TextColor3 = Color3.fromRGB(170,170,170)
    parentLbl.Text = "Parent: " .. tostring(remote.Parent and remote.Parent.Name or "<nil>")

    local btn = Instance.new("TextButton", frame)
    btn.Size = UDim2.new(1, -12, 1, -10)
    btn.Position = UDim2.new(0,6,0,5)
    btn.BackgroundTransparency = 1
    btn.Text = ""
    btn.AutoButtonColor = true

    btn.MouseEnter:Connect(function()
        if multiSelectMode then
            if selectedSet[remote] then return end
            pcall(function() frame.BackgroundColor3 = Color3.fromRGB(58,142,255) end)
        else
            pcall(function() frame.BackgroundColor3 = HOVER_BG end)
        end
    end)
    btn.MouseLeave:Connect(function()
        if multiSelectMode then
            if selectedSet[remote] then pcall(function() frame.BackgroundColor3 = SELECT_BG end) else pcall(function() frame.BackgroundColor3 = NORMAL_BG end) end
        else
            pcall(function() frame.BackgroundColor3 = NORMAL_BG end)
        end
    end)

    btn.MouseButton1Click:Connect(function()
        if multiSelectMode then
            if selectedSet[remote] then
                selectedSet[remote] = nil
                pcall(function() frame.BackgroundColor3 = NORMAL_BG end)
            else
                selectedSet[remote] = true
                pcall(function() frame.BackgroundColor3 = SELECT_BG end)
            end
            local c = 0 for _ in pairs(selectedSet) do c = c + 1 end
            selectedCountLabel.Text = tostring(c)
            statusBar.Text = ("Selected %d remotes."):format(c)
        else
            for r,f in pairs(entries) do
                if f and f:IsA("Frame") then
                    pcall(function() TweenService:Create(f, TweenInfo.new(0.12), {BackgroundColor3 = NORMAL_BG}):Play() end)
                end
            end
            pcall(function() TweenService:Create(frame, TweenInfo.new(0.12), {BackgroundColor3 = HOVER_BG}):Play() end)

            selectedInfo = info
            local ok2, full2 = pcall(function() return remote:GetFullName() end)
            lblRemote.Text = "Remote: " .. (ok2 and full2 or tostring(remote.Name))
            lblParent.Text = "Parent: " .. tostring(remote.Parent and remote.Parent:GetFullName() or "<nil>")
            lblType.Text = "Type: " .. (remote:IsA("RemoteEvent") and "RemoteEvent" or "RemoteFunction")
            argsBox.Text = info.lastArgsText or ""
            statusBar.Text = "Selected remote: " .. (ok2 and full2 or tostring(remote.Name))
            local found = nil; local count = 0
            for keyEnum,bd in pairs(bindings) do
                local rlist = bd.remote
                if typeof(rlist) == "Instance" then
                    if rlist == remote then found = keyEnumToName(keyEnum); count = 1; break end
                else
                    for _, rr in ipairs(rlist or {}) do
                        if rr == remote then found = keyEnumToName(keyEnum); count = #rlist; break end
                    end
                end
                if found then break end
            end
            if found then assignedLabel.Text = ("Assigned: %s  (remotes: %d)"):format(found, count) else assignedLabel.Text = "Assigned: <none>" end
        end
    end)

    entries[remote] = frame
end

-- cleanup when remote removed (keeps multi-selection & bindings clean)
local function handleRemoteRemoved(remote)
    if selectedSet[remote] then
        selectedSet[remote] = nil
        if selectedCountLabel then
            local c = 0
            for _ in pairs(selectedSet) do c = c + 1 end
            selectedCountLabel.Text = tostring(c)
        end
    end

    for keyEnum, bd in pairs(bindings) do
        local rr = bd.remote
        if typeof(rr) == "Instance" then
            if rr == remote then
                bindings[keyEnum] = nil
                pcall(function() deleteSavedBinding(keyEnumToName(keyEnum)) end)
            end
        elseif type(rr) == "table" then
            local changed = false
            for i = #rr, 1, -1 do
                if rr[i] == remote then
                    table.remove(rr, i)
                    changed = true
                end
            end
            if changed then
                if #rr == 0 then
                    bindings[keyEnum] = nil
                    pcall(function() deleteSavedBinding(keyEnumToName(keyEnum)) end)
                else
                    if bd.remotePaths and type(bd.remotePaths) == "table" then
                        for i = #bd.remotePaths, 1, -1 do
                            local path = bd.remotePaths[i]
                            if path and path:match("%." .. remote.Name .. "$") then
                                table.remove(bd.remotePaths, i)
                            end
                        end
                        bd.remotePath = bd.remotePaths[1]
                    end
                    bd.remote = rr
                end
            end
        end
    end
end

-- scanning inventory and creating entries (uses createEntryForRemote defined above)
local function scanInventoryOnce()
    for r,fr in pairs(entries) do
        if not r or not r.Parent then
            if fr and fr.Parent then fr:Destroy() end
            entries[r] = nil
            pcall(function() handleRemoteRemoved(r) end)
        end
    end

    local function scanContainer(container)
        if not container then return end
        for _, inst in ipairs(container:GetDescendants()) do
            if isRemote(inst) and not entries[inst] then
                createEntryForRemote(inst)
            end
        end
    end

    -- scan backpack and character (covers tools in both)
    scanContainer(backpack)
    scanContainer(character)
end

-- --------------------
-- Argument builder & firing (now supports placement modes and follows model)
-- --------------------
local function buildArgsForBinding(bd)
    if not bd or not bd.remote then return {} end
    local args = {}
    local targetPos = nil

    if bd.mode == "Mouse" then
        targetPos = getMouseHitPos()
    elseif bd.mode == "NearestPlayer" then
        local pos,pl = getNearestPlayerPredictedPos(bd.predictionX, bd.predictionY)
        if pos then targetPos = pos end
    elseif bd.mode == "NearestHumanoid" then
        local pos,mdl = getNearestHumanoidPredictedPos(bd.predictionX, bd.predictionY)
        if pos then targetPos = pos end
    elseif bd.mode == "StraightForward" then
        local studs = tonumber(bd.placeStuds) or tonumber(placeStudsBox.Text) or placement.studs or 6
        local forward = getLocalForwardVector()
        forward = Vector3.new(forward.X, 0, forward.Z)
        if forward.Magnitude == 0 then
            forward = Camera and Vector3.new(Camera.CFrame.LookVector.X, 0, Camera.CFrame.LookVector.Z) or Vector3.new(0,0,-1)
        end
        local base = getLocalReferencePos()
        local pos = base + (forward.Unit * studs)
        pos = Vector3.new(pos.X, base.Y, pos.Z)
        targetPos = pos
    elseif bd.mode == "CustomPlacement" then
        -- IMPORTANT: prefer following the selected model's live position (do not use static block)
        -- Use binding's stored placeLastPos if it exists, otherwise live selection from placement.selectedModel takes priority
        local pos = nil
        -- if there's a live selected model (user-selected during session), prefer that live model position
        if placement.selectedModel then
            local adornee = findModelAdornee(placement.selectedModel)
            if adornee then
                pos = adornee.Position
            end
        end
        -- if no live selected model or not available, try stored binding last pos
        if not pos and bd.placeLastPos and typeof(bd.placeLastPos) == "table" and #bd.placeLastPos == 3 then
            pos = Vector3.new(bd.placeLastPos[1], bd.placeLastPos[2], bd.placeLastPos[3])
        end
        -- fallback to placement.lastPos if still no pos
        if not pos and placement.lastPos then pos = placement.lastPos end
        targetPos = pos
    end

    if targetPos then
        if bd.argFormat == "Vector3" or bd.argFormat == "Vector3 " then
            table.insert(args, targetPos)
        else
            table.insert(args, targetPos.X)
            table.insert(args, targetPos.Y)
            table.insert(args, targetPos.Z)
        end
    end

    if bd.extraArgs and #bd.extraArgs > 0 then
        for _,v in ipairs(bd.extraArgs) do table.insert(args, v) end
    end
    return args
end

local function fireBindingOnce(bd)
    if not bd or not bd.remote then return false, "no binding" end
    local args = buildArgsForBinding(bd)
    local ok, err = pcall(function() return safeCallRemote(bd.remote, args, bd.argFormat == "XYZ") end)
    if ok then return err else return false, err end
end

-- --------------------
-- Binding management (unchanged but extended to include place fields)
-- --------------------
local function removeBindingByKey(keyEnum)
    if bindings[keyEnum] then
        local kn = keyEnumToName(keyEnum)
        if kn and settingsFolder:FindFirstChild("binding_"..kn) then settingsFolder:FindFirstChild("binding_"..kn):Destroy() end
        local bd = bindings[keyEnum]
        if bd and bd.active then bd.active = false end
        bindings[keyEnum] = nil
    end
end

local function removeBindingByRemote(remote)
    if not remote then return end
    local toRemove = {}
    for k,bd in pairs(bindings) do
        local rr = bd.remote
        if typeof(rr) == "Instance" then
            if rr == remote then table.insert(toRemove, k) end
        elseif type(rr) == "table" then
            for _,r in ipairs(rr) do
                if r == remote then table.insert(toRemove, k); break end
            end
        end
    end
    for _,k in ipairs(toRemove) do
        local kn = keyEnumToName(k)
        if kn then deleteSavedBinding(kn) end
        local bd = bindings[k]
        if bd and bd.active then bd.active = false end
        bindings[k] = nil
    end
end

local function removeBindingByRemoteList(remoteList)
    if not remoteList then return end
    if typeof(remoteList) == "Instance" then
        removeBindingByRemote(remoteList)
        return
    end
    if type(remoteList) ~= "table" then return end
    local seen = {}
    for _,r in ipairs(remoteList) do
        if not seen[r] then removeBindingByRemote(r); seen[r] = true end
    end
end

local function setBindingForKey(keyEnum, bd)
    if not keyEnum or not bd or not bd.remote then return false, "invalid args" end
    removeBindingByKey(keyEnum)
    removeBindingByRemoteList(bd.remote)
    bindings[keyEnum] = {
        remote = bd.remote,
        extraArgs = bd.extraArgs or {},
        hold = bd.hold and true or false,
        interval = tonumber(bd.interval) or 0.12,
        mode = bd.mode or "Mouse",
        predictionX = tonumber(bd.predictionX) or 0,
        predictionY = tonumber(bd.predictionY) or 0,
        argFormat = bd.argFormat or "Vector3",
        placeStuds = bd.placeStuds or nil,
        placeLastPos = bd.placeLastPos or nil,
        placeStick = bd.placeStick and true or false,
        active = false,
        remotePath = bd.remotePath or (pcall(function() return (typeof(bd.remote)=="Instance" and bd.remote:GetFullName()) end) and (typeof(bd.remote)=="Instance" and bd.remote:GetFullName())) or "",
        remotePaths = bd.remotePaths or nil
    }
    return true
end

local function startBinding(keyEnum)
    local bd = bindings[keyEnum]
    if not bd or not bd.remote then return end
    if bd.hold then
        if bd.active then return end
        bd.active = true
        bd._co = coroutine.create(function()
            while bd.active do
                pcall(function() fireBindingOnce(bd) end)
                task.wait(math.max(0.01, tonumber(bd.interval) or 0.12))
            end
        end)
        coroutine.resume(bd._co)
    else
        bd.active = not bd.active
        if bd.active then
            bd._co = coroutine.create(function()
                while bd.active do
                    pcall(function() fireBindingOnce(bd) end)
                    task.wait(math.max(0.01, tonumber(bd.interval) or 0.12))
                end
            end)
            coroutine.resume(bd._co)
        else
            bd.active = false
        end
    end
end

local function stopBinding(keyEnum)
    local bd = bindings[keyEnum]
    if not bd then return end
    if bd.hold then bd.active = false end
end

-- --------------------
-- Input handling & UI callbacks (add placement capture)
-- --------------------
local function clearSelectedBindingsAndSelection()
    local remotesToClear = {}
    for r,_ in pairs(selectedSet) do
        if r then table.insert(remotesToClear, r) end
    end
    local cleared = 0
    for _,r in ipairs(remotesToClear) do
        pcall(function() removeBindingByRemote(r) end)
        selectedSet[r] = nil
        cleared = cleared + 1
    end
    selectedCountLabel.Text = "0"
    assignedLabel.Text = "Assigned: <none>"
    statusBar.Text = ("Cleared bindings for %d selected remotes."):format(cleared)
end

UserInputService.InputBegan:Connect(function(input, gp)
    if input.UserInputType == Enum.UserInputType.Keyboard then
        local code = input.KeyCode
        if code then
            if code == Enum.KeyCode.R then
                pcall(function()
                    scanInventoryOnce()
                    statusBar.Text = "Reloaded (hotkey R)."
                    leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12)
                    local saved = loadSavedBindingsIntoTable()
                    for k, data in pairs(saved) do
                        pcall(function()
                            local ok, err = applySavedBinding(data)
                            if ok then pendingSaved[k] = nil end
                        end)
                    end
                end)
                return
            end

            if code == Enum.KeyCode.Delete then
                clearSelectedBindingsAndSelection()
                return
            end

            if bindings[code] then startBinding(code) end
        end
    end
end)
UserInputService.InputEnded:Connect(function(input, gp)
    if input.UserInputType == Enum.UserInputType.Keyboard then
        local code = input.KeyCode
        if code and bindings[code] then stopBinding(code) end
    end
end)

aimDropdown.MouseButton1Click:Connect(function()
    local cur = aimDropdown.Text
    if cur == "Mouse" then aimDropdown.Text = "NearestPlayer"
    elseif cur == "NearestPlayer" then aimDropdown.Text = "NearestHumanoid"
    elseif cur == "NearestHumanoid" then aimDropdown.Text = "StraightForward"
    elseif cur == "StraightForward" then aimDropdown.Text = "CustomPlacement"
    else aimDropdown.Text = "Mouse" end

    _G.RKB_currentAimMode = aimDropdown.Text
    pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end)
end)

formatDropdown.MouseButton1Click:Connect(function() formatDropdown.Text = (formatDropdown.Text == "Vector3") and "XYZ" or "Vector3" end)
holdToggle.MouseButton1Click:Connect(function()
    if holdToggle.Text == "Hold mode" then
        holdToggle.Text = "Toggle mode"
        holdToggle.BackgroundColor3 = Color3.fromRGB(68,44,68)
    else
        holdToggle.Text = "Hold mode"
        holdToggle.BackgroundColor3 = Color3.fromRGB(44,44,60)
    end
end)

-- placement click capture flow (selection follows model)
local mouse = safeGetMouse()
local clickConn = nil
placeClickBtn.MouseButton1Click:Connect(function()
    if not mouse then mouse = safeGetMouse() end
    if not mouse then statusBar.Text = "Mouse not available"; return end
    statusBar.Text = "Click somewhere in the world to place/select (Esc to cancel)."
    placement.clickCapture = true

    local function cancelCapture()
        placement.clickCapture = false
        statusBar.Text = "Placement canceled."
        if clickConn then clickConn:Disconnect(); clickConn = nil end
    end

    local escConn
    escConn = UserInputService.InputBegan:Connect(function(inp, gp)
        if inp.UserInputType == Enum.UserInputType.Keyboard and inp.KeyCode == Enum.KeyCode.Escape then
            cancelCapture()
            escConn:Disconnect(); escConn = nil
        end
    end)

    clickConn = mouse.Button1Down:Connect(function()
        if not placement.clickCapture then return end
        local target = mouse.Target
        local hit = nil
        pcall(function() hit = mouse.Hit.Position end)
        if target and target.Parent and target.Parent:IsA("Model") then
            local model = target.Parent
            local hum = model:FindFirstChildOfClass("Humanoid")
            if hum and model.Name ~= player.Name then
                -- select the model (follow it directly)
                if placement.selectedModel and placement.selectedModel ~= model then
                    clearSelectionBillboard(placement.selectedModel)
                end
                placement.selectedModel = model
                placement.stickToEntity = stickToggle.Text == "Stick: On"
                createSelectionBillboardForModel(model)
                local adornee = findModelAdornee(model)
                placement.lastPos = (adornee and adornee.Position) or placement.lastPos
                placementSelectedLabel.Text = "Selected placement: "..tostring(model.Name)
                statusBar.Text = "Selected entity: "..tostring(model.Name)
            else
                if hit then
                    placement.lastPos = hit
                    if placement.selectedModel then
                        clearSelectionBillboard(placement.selectedModel)
                        placement.selectedModel = nil
                    end
                    placementSelectedLabel.Text = "Selected placement: Custom position"
                    statusBar.Text = ("Placed at: %.1f, %.1f, %.1f"):format(hit.X, hit.Y, hit.Z)
                end
            end
        else
            if hit then
                placement.lastPos = hit
                if placement.selectedModel then
                    clearSelectionBillboard(placement.selectedModel)
                    placement.selectedModel = nil
                end
                placementSelectedLabel.Text = "Selected placement: Custom position"
                statusBar.Text = ("Placed at: %.1f, %.1f, %.1f"):format(hit.X, hit.Y, hit.Z)
            end
        end

        placement.clickCapture = false
        if clickConn then clickConn:Disconnect(); clickConn = nil end
        if escConn then escConn:Disconnect(); escConn = nil end
        pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end)
    end)
end)

stickToggle.MouseButton1Click:Connect(function()
    if stickToggle.Text == "Stick: Off" then
        stickToggle.Text = "Stick: On"
        stickToggle.BackgroundColor3 = Color3.fromRGB(42,122,255)
        placement.stickToEntity = true
    else
        stickToggle.Text = "Stick: Off"
        stickToggle.BackgroundColor3 = Color3.fromRGB(44,44,60)
        placement.stickToEntity = false
    end
    placementSelectedLabel.Text = placement.selectedModel and ("Selected placement: "..tostring(placement.selectedModel.Name)) or "Selected placement: <none>"
    pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end)
end)

placeStudsBox:GetPropertyChangedSignal("Text"):Connect(function()
    local v = tonumber(placeStudsBox.Text)
    if v and v > 0 then placement.studs = v end
    pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end)
end)

-- key capture flows (when binding, store placement fields)
local function endCapture()
    capturingKey = false
    setKeyBtn.Text = "Set Keybind (single)"
    bindSelectedBtn.Text = "Bind Selected (multi)"
    statusBar.Text = "Ready."
    if capturingConn then capturingConn:Disconnect(); capturingConn = nil end
end

local function beginKeyCaptureForRemotes(remotesTable)
    if capturingKey then return end
    capturingKey = true
    setKeyBtn.Text = "Press key (Esc cancel)"
    bindSelectedBtn.Text = "Press key (Esc cancel)"
    statusBar.Text = "Waiting for key..."
    capturingConn = UserInputService.InputBegan:Connect(function(input, gp)
        if not capturingKey then return end
        if input.UserInputType == Enum.UserInputType.Keyboard then
            local code = input.KeyCode
            if code == Enum.KeyCode.Escape then endCapture(); return end
            local bd = {
                remote = (type(remotesTable)=="table" and (#remotesTable==1 and remotesTable[1] or remotesTable)) or remotesTable,
                extraArgs = parseArgsText(argsBox.Text),
                hold = (holdToggle.Text == "Hold mode"),
                interval = tonumber(intervalBox.Text) or 0.12,
                mode = aimDropdown.Text,
                predictionX = tonumber(predXBox.Text) or 0,
                predictionY = tonumber(predYBox.Text) or 0,
                argFormat = formatDropdown.Text,
                remotePath = nil,
                remotePaths = nil,
                placeStuds = tonumber(placeStudsBox.Text) or placement.studs,
                placeLastPos = (placement.lastPos and {placement.lastPos.X, placement.lastPos.Y, placement.lastPos.Z}) or nil,
                placeStick = placement.stickToEntity
            }
            if type(bd.remote) == "Instance" then
                local ok, fp = pcall(function() return bd.remote:GetFullName() end)
                if ok and fp then bd.remotePath = fp end
            elseif type(bd.remote) == "table" then
                bd.remotePaths = {}
                for _,r in ipairs(bd.remote) do
                    local ok, fp = pcall(function() return r:GetFullName() end)
                    if ok and fp then table.insert(bd.remotePaths, fp) end
                end
                bd.remotePath = bd.remotePaths[1]
            end

            setBindingForKey(code, bd)
            deleteSavedBinding(keyEnumToName(code))
            assignedLabel.Text = "Assigned: " .. keyEnumToName(code) .. "  (remotes: " .. (type(bd.remote)=="table" and #bd.remote or 1) .. ")"
            statusBar.Text = "Bound to key " .. keyEnumToName(code)
            endCapture()
        end
    end)
end

setKeyBtn.MouseButton1Click:Connect(function()
    if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first (single)"; return end
    beginKeyCaptureForRemotes(selectedInfo.remote)
end)

bindSelectedBtn.MouseButton1Click:Connect(function()
    local remotes = {}
    for r,_ in pairs(selectedSet) do
        if r and r.Parent then table.insert(remotes, r) end
    end
    if #remotes == 0 then statusBar.Text = "No remotes selected (toggle Multi-Select on, then click entries)"; return end
    beginKeyCaptureForRemotes(remotes)
end)

clearMultiBindsBtn.MouseButton1Click:Connect(function()
    clearSelectedBindingsAndSelection()
end)

-- multi-toggle behaviors
multiToggle.MouseButton1Click:Connect(function()
    multiSelectMode = not multiSelectMode
    if multiSelectMode then
        multiToggle.Text = "Multi-Select: On"
        statusBar.Text = "Multi-Select ON — click entries to add/remove them (blue = selected)."
        for r,fr in pairs(entries) do
            if selectedSet[r] then fr.BackgroundColor3 = SELECT_BG end
        end
    else
        multiToggle.Text = "Multi-Select: Off"
        statusBar.Text = "Multi-Select OFF — inspector mode."
        for r,fr in pairs(entries) do
            if selectedSet[r] then fr.BackgroundColor3 = NORMAL_BG end
        end
    end
end)

clearSelectionBtn.MouseButton1Click:Connect(function()
    for r,fr in pairs(entries) do
        if selectedSet[r] and fr and fr.Parent then fr.BackgroundColor3 = NORMAL_BG end
    end
    selectedSet = {}
    selectedCountLabel.Text = "0"
    statusBar.Text = "Selection cleared."
end)

-- Save/Update/Load/Fire/Clear UI handlers (behaviour kept but now store placement fields)
local function buildBindingDataFromUIForKey(keyName)
    if not keyName then return nil, "no key" end
    local data = {
        key = keyName,
        remotePath = (selectedInfo and pcall(function() return selectedInfo.remote:GetFullName() end) and selectedInfo.remote:GetFullName()) or "",
        extraArgsText = argsBox.Text or "",
        hold = (holdToggle.Text == "Hold mode"),
        interval = tonumber(intervalBox.Text) or 0.12,
        mode = aimDropdown.Text or "Mouse",
        predictionX = tonumber(predXBox.Text) or 0,
        predictionY = tonumber(predYBox.Text) or 0,
        argFormat = formatDropdown.Text or "Vector3",
        placeStuds = tonumber(placeStudsBox.Text) or placement.studs,
        placeLastPos = (placement.lastPos and {placement.lastPos.X, placement.lastPos.Y, placement.lastPos.Z}) or nil,
        placeStick = placement.stickToEntity
    }
    return data
end

function applySavedBinding(data)
    if not data or not data.key then return false, "invalid data" end
    local keyEnum = nameToKeyEnum(data.key)
    if not keyEnum then return false, "invalid key name " .. tostring(data.key) end

    local resolvedRemotes = {}
    if data.remotePaths and type(data.remotePaths) == "table" then
        for _,p in ipairs(data.remotePaths) do
            local inst = findInstanceByFullName(p)
            if inst then table.insert(resolvedRemotes, inst) end
        end
    elseif data.remotePath and data.remotePath ~= "" then
        local inst = findInstanceByFullName(data.remotePath)
        if inst then table.insert(resolvedRemotes, inst) end
    end

    if #resolvedRemotes == 0 then
        if data.remotePath and data.remotePath ~= "" then
            local short = data.remotePath:match("([^%.]+)$")
            if short then
                for _,inst in ipairs(backpack:GetDescendants()) do if isRemote(inst) and inst.Name == short then table.insert(resolvedRemotes, inst) end end
                for _,inst in ipairs(character:GetDescendants()) do if isRemote(inst) and inst.Name == short then table.insert(resolvedRemotes, inst) end end
            end
        end
    end

    if #resolvedRemotes == 0 then
        pendingSaved[data.key] = data
        return false, "remote(s) not found"
    end

    local px = tonumber(data.predictionX); local py = tonumber(data.predictionY)
    if px == nil and tonumber(data.prediction) then px = tonumber(data.prediction) end
    if py == nil and tonumber(data.prediction) then py = tonumber(data.prediction) end
    px = px or 0; py = py or 0

    local bd = {
        remote = (#resolvedRemotes==1) and resolvedRemotes[1] or resolvedRemotes,
        extraArgs = parseArgsText(data.extraArgsText or ""),
        hold = data.hold and true or false,
        interval = tonumber(data.interval) or 0.12,
        mode = data.mode or "Mouse",
        predictionX = px,
        predictionY = py,
        argFormat = data.argFormat or "Vector3",
        placeStuds = tonumber(data.placeStuds) or nil,
        placeLastPos = data.placeLastPos or nil,
        placeStick = data.placeStick and true or false,
        remotePath = data.remotePath or "",
        remotePaths = data.remotePaths or nil
    }
    setBindingForKey(keyEnum, bd)
    return true
end

_G.applySavedBinding = applySavedBinding

saveBtn.MouseButton1Click:Connect(function()
    if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first to Save"; return end
    local boundKey = nil
    for k,bd in pairs(bindings) do
        if bd.remote and ((typeof(bd.remote)=="Instance" and bd.remote == selectedInfo.remote) or (type(bd.remote)=="table" and table.find(bd.remote, selectedInfo.remote))) then
            boundKey = keyEnumToName(k); break
        end
    end
    if not boundKey then statusBar.Text = "No keybind for selected remote. Use Set Keybind first."; return end
    local data, err = buildBindingDataFromUIForKey(boundKey)
    if not data then statusBar.Text = "Save error: "..tostring(err); return end
    local ok, e = saveBindingToFolder(boundKey, data)
    if ok then statusBar.Text = "Saved binding for key "..boundKey else statusBar.Text = "Save failed: "..tostring(e) end
end)

updateBtn.MouseButton1Click:Connect(function()
    if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first."; return end
    local boundKey = nil
    for k,bd in pairs(bindings) do
        if bd.remote and ((typeof(bd.remote)=="Instance" and bd.remote == selectedInfo.remote) or (type(bd.remote) == "table" and table.find(bd.remote, selectedInfo.remote))) then
            boundKey = keyEnumToName(k); break
        end
    end
    if not boundKey then statusBar.Text = "No keybind to update. Use Set Keybind first."; return end
    local data, err = buildBindingDataFromUIForKey(boundKey)
    if not data then statusBar.Text = "Update error: "..tostring(err); return end
    local ok, e = saveBindingToFolder(boundKey, data)
    if ok then statusBar.Text = "Updated saved binding for "..boundKey else statusBar.Text = "Update failed: "..tostring(e) end
end)

loadBtn.MouseButton1Click:Connect(function()
    statusBar.Text = "Loading saved bindings..."
    local saved = loadSavedBindingsIntoTable()
    pendingSaved = {}
    local applied = 0
    for keyName, data in pairs(saved) do
        local ok, err = applySavedBinding(data)
        if ok then applied = applied + 1 else pendingSaved[keyName] = data end
    end
    statusBar.Text = ("Loaded %d saved. Pending: %d"):format(applied, (function() local c=0; for _ in pairs(pendingSaved) do c=c+1 end; return c end)())
    leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12)
end)

fireBtn.MouseButton1Click:Connect(function()
    if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first."; return end
    local bd = {
        remote = selectedInfo.remote,
        extraArgs = parseArgsText(argsBox.Text),
        mode = aimDropdown.Text,
        predictionX = tonumber(predXBox.Text) or 0,
        predictionY = tonumber(predYBox.Text) or 0,
        argFormat = formatDropdown.Text,
        placeStuds = tonumber(placeStudsBox.Text) or placement.studs,
        placeLastPos = (placement.lastPos and {placement.lastPos.X, placement.lastPos.Y, placement.lastPos.Z}) or nil,
        placeStick = placement.stickToEntity
    }
    local ok, err = safeCallRemote(bd.remote, buildArgsForBinding(bd), bd.argFormat == "XYZ")
    if ok then statusBar.Text = "Test fire success." else statusBar.Text = "Test fire failed: "..tostring(err) end
end)

local function clearBindingsForSelected()
    if not selectedInfo or not selectedInfo.remote then statusBar.Text = "Select a remote first."; return end
    local removed = false
    local toDelete = {}
    for k,bd in pairs(bindings) do
        local rr = bd.remote
        if typeof(rr) == "Instance" then
            if rr == selectedInfo.remote then table.insert(toDelete, k); removed = true end
        else
            for _,r in ipairs(rr or {}) do
                if r == selectedInfo.remote then table.insert(toDelete, k); removed = true; break end
            end
        end
    end
    for _,k in ipairs(toDelete) do
        local kn = keyEnumToName(k)
        if kn then deleteSavedBinding(kn) end
        bindings[k] = nil
    end
    if removed then assignedLabel.Text = "Assigned: <none>"; statusBar.Text = "Cleared binding(s) for selected remote." else statusBar.Text = "No binding found for selected remote." end
end

local clearBindBtn = Instance.new("TextButton", rightPane)
clearBindBtn.Position = UDim2.new(0,324,1,-84)
clearBindBtn.Size = UDim2.new(0,86,0,28)
clearBindBtn.Font = Enum.Font.Gotham
clearBindBtn.Text = "Clear Bind"
clearBindBtn.BackgroundColor3 = Color3.fromRGB(92,36,36)
clearBindBtn.TextColor3 = Color3.fromRGB(240,240,240)
clearBindBtn.BorderSizePixel = 0
clearBindBtn.TextSize = 12
clearBindBtn.MouseButton1Click:Connect(clearBindingsForSelected)

reloadBtn.MouseButton1Click:Connect(function()
    pcall(function()
        scanInventoryOnce()
        statusBar.Text = "Remotes reloaded."
        leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12)
        local saved = loadSavedBindingsIntoTable()
        for k,data in pairs(saved) do
            local ok, err = applySavedBinding(data)
            if ok then pendingSaved[k] = nil end
        end
    end)
end)

local function resetToolsNow()
    statusBar.Text = "Resetting tools..."
    pcall(function()
        character = player.Character or player.CharacterAdded:Wait()
        for _,obj in ipairs(character:GetChildren()) do
            if obj:IsA("Tool") then
                pcall(function() obj.Parent = backpack end)
                task.wait(0.06)
                pcall(function() obj.Parent = character end)
                task.wait(0.06)
            end
        end
        for _,obj in ipairs(backpack:GetChildren()) do
            if obj:IsA("Tool") then
                pcall(function() obj.Parent = character end)
                task.wait(0.03)
                pcall(function() obj.Parent = backpack end)
            end
        end
        scanInventoryOnce()
        leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12)
    end)
    statusBar.Text = "Reset tools attempted; reloaded inventory."
end
resetToolsBtn.MouseButton1Click:Connect(resetToolsNow)

-- --------------------
-- Periodic scan start & load saved
-- --------------------
task.spawn(function()
    while true do
        pcall(function()
            scanInventoryOnce()
            for r,fr in pairs(entries) do
                if fr and fr.Parent then
                    local lbl = fr:FindFirstChildOfClass("TextLabel")
                    if lbl then
                        local ok, full = pcall(function() return r:GetFullName() end)
                        lbl.Text = ok and full or tostring(r.Name)
                    end
                end
            end
            leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12)
        end)
        task.wait(1.0)
    end
end)

task.spawn(function()
    task.wait(0.6)
    local saved = loadSavedBindingsIntoTable()
    for k,data in pairs(saved) do
        local ok, err = applySavedBinding(data)
        if not ok then pendingSaved[k] = data end
    end
    statusBar.Text = "Ready — Multi-Select button under list. Toggle it, click entries to select."
end)

-- --------------------
-- Respawn handling & cleanup (keep visuals following new character)
-- --------------------
player.CharacterAdded:Connect(function(char)
    character = char
    task.delay(0.25, function()
        pcall(function()
            backpack = player:FindFirstChild("Backpack") or backpack
            refreshHumanoidCache()
            scanInventoryOnce()
            local saved = loadSavedBindingsIntoTable()
            for k,data in pairs(saved) do
                local ok, err = applySavedBinding(data)
                if not ok then pendingSaved[k] = data end
            end
            leftScroll.CanvasSize = UDim2.new(0,0,0, leftListLayout.AbsoluteContentSize.Y + 12)
            statusBar.Text = "Respawned — reloaded inventory & saved bindings."
        end)
    end)
    task.delay(0.2, function() pcall(function() updatePlacementVisual(_G.RKB_currentAimMode) end) end)
end)

player.AncestryChanged:Connect(function(_, parent)
    if not parent then
        pcall(destroyPlacementVisual)
    end
end)

-- debug helpers
_G.RKB_getBindings = function() return bindings end
_G.RKB_reload = function() scanInventoryOnce(); statusBar.Text = "Manual reload (exposed)"; end
_G.RKB_resetTools = resetToolsNow

-- end of script

Features & Information

it uses tools keybinds as a aim system and also slient aim(i think) i added striaght forward so attacks like blasters aim forward. features are mouse,nearestplayer,nearesthumanoid,straightforward,customplacement(prob just in beta testing) and custom prediction tho this is only main for like sans fighting games you might find some use of remote abuse also multi keybinds and toggle and hold mode. also this was made by ai not me. Updated note today: this is also a reupload since it prob hard to find tho this is universal to most games that uses tools and have remotes behind them
#remote#keybind#remote keybinder gui#auto aim#slient aim

Community Comments (4)

reverb0012reverb0012Dec 15, 2025

comment if there something that needs to be fix

Replying to @reverb0012
tankkktankkkDec 18, 2025

@reverb0012 change the ui

reverb0012reverb0012Dec 15, 2025

can i get reviews if this script is good also it will prob suppport

jorik1111jorik1111Dec 18, 2025

My problem is that I can't close the cheat menu.

More Scripts for Universal Scripts