FCAL Hub keyless under development
Key Required

FCAL Hub keyless under development

ForsakenImYoshikiImYoshiki 1.1K views 51 executesUpdated Feb 20, 2026
Unrated
00
Lua Script•1235 lines (41638 chars)
--[[
    ███████╗███████╗ █████╗ ██╗     
    ██╔════╝██╔════╝██╔══██╗██║     
    █████╗  █████╗  ███████║██║     
    ██╔══╝  ██╔══╝  ██╔══██║██║     
    ██║     ██║     ██║  ██║███████╗
    ╚═╝     ╚═╝     ╚═╝  ╚═╝╚══════╝

    FCAL HUB - Client Sided
    Version: 1.0.6
--]]

-- Services
local Players = game:GetService("Players")
local TeleportService = game:GetService("TeleportService")
local RunService = game:GetService("RunService")
local Lighting = game:GetService("Lighting")
local UserInputService = game:GetService("UserInputService")
local Workspace = game:GetService("Workspace")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local LocalPlayer = Players.LocalPlayer

-- Config
local Config = {
    WalkSpeedDefault = 16,
    JumpPowerDefault = 50,
    GravityDefault = 196,
    Theme = "Midnight",
    FlySpeed = 100,
    FlySpeedDefault = 100,
}

-- Load Modal UI
local Modal = loadstring(game:HttpGet("https://github.com/BloxCrypto/Modal/releases/download/v1.0-beta/main.lua"))()

-- Create Window
local Window = Modal:CreateWindow({
    Title = "FCAL HUB",
    SubTitle = "v1.0.6 | Client Sided",
    Size = UDim2.fromOffset(500, 420),
    MinimumSize = Vector2.new(350, 300),
    Transparency = 0,
    Icon = "rbxassetid://68073547",
})

Window:SetTheme(Config.Theme)

-- UI Element References (for syncing)
local UIElements = {
    WalkSpeedSlider = nil,
    WalkSpeedInput = nil,
    JumpPowerSlider = nil,
    JumpPowerInput = nil,
    GravitySlider = nil,
    GravityInput = nil,
    FlySpeedSlider = nil,
    FlySpeedInput = nil,
}

-- Helpers
local function Notify(title, desc, typ)
    Window:Notify({Title = title, Description = desc, Duration = 3, Type = typ or "Info"})
end

local function GetHumanoid()
    local char = LocalPlayer.Character
    return char and char:FindFirstChildOfClass("Humanoid")
end

local function GetRootPart()
    local char = LocalPlayer.Character
    return char and char:FindFirstChild("HumanoidRootPart")
end

local function GetPlayerByName(name)
    name = name:lower()
    for _, p in pairs(Players:GetPlayers()) do
        if p.Name:lower():sub(1, #name) == name or p.DisplayName:lower():sub(1, #name) == name then
            return p
        end
    end
    return nil
end

-- Update UI Elements (Sync sliders and inputs)
local function UpdateWalkSpeedUI(value)
    if UIElements.WalkSpeedSlider then
        pcall(function() UIElements.WalkSpeedSlider:Set(value) end)
    end
    if UIElements.WalkSpeedInput then
        pcall(function() UIElements.WalkSpeedInput:Set(tostring(value)) end)
    end
end

local function UpdateJumpPowerUI(value)
    if UIElements.JumpPowerSlider then
        pcall(function() UIElements.JumpPowerSlider:Set(value) end)
    end
    if UIElements.JumpPowerInput then
        pcall(function() UIElements.JumpPowerInput:Set(tostring(value)) end)
    end
end

local function UpdateGravityUI(value)
    if UIElements.GravitySlider then
        pcall(function() UIElements.GravitySlider:Set(value) end)
    end
    if UIElements.GravityInput then
        pcall(function() UIElements.GravityInput:Set(tostring(value)) end)
    end
end

local function UpdateFlySpeedUI(value)
    if UIElements.FlySpeedSlider then
        pcall(function() UIElements.FlySpeedSlider:Set(value) end)
    end
    if UIElements.FlySpeedInput then
        pcall(function() UIElements.FlySpeedInput:Set(tostring(value)) end)
    end
end

-- Role Detection
local function GetPlayerRole(player)
    local inGame = false
    local gameGui = LocalPlayer:FindFirstChild("PlayerGui")
    if gameGui then
        for _, gui in pairs(gameGui:GetChildren()) do
            if gui.Name:lower():find("game") or gui.Name:lower():find("match") 
                or gui.Name:lower():find("survive") or gui.Name:lower():find("ingame") then
                if gui.Enabled then inGame = true break end
            end
        end
    end
    if not inGame then
        for _, obj in pairs(Workspace:GetChildren()) do
            if obj.Name:lower():find("generator") or obj.Name:lower():find("gate") 
                or obj.Name:lower():find("survivor") or obj.Name:lower():find("killer") then
                inGame = true break
            end
        end
    end
    if not inGame then return "Neutral" end
    local character = player.Character
    if not character then return "Neutral" end
    if player:GetAttribute("Role") then
        local role = player:GetAttribute("Role")
        if type(role) == "string" then
            if role:lower():find("killer") then return "Killer" end
            if role:lower():find("survivor") or role:lower():find("survive") then return "Survivor" end
        end
    end
    if player:GetAttribute("IsKiller") then return "Killer" end
    if player:GetAttribute("IsSurvivor") then return "Survivor" end
    if character:GetAttribute("Role") then
        local role = character:GetAttribute("Role")
        if type(role) == "string" then
            if role:lower():find("killer") then return "Killer" end
            if role:lower():find("survivor") or role:lower():find("survive") then return "Survivor" end
        end
    end
    if character:GetAttribute("IsKiller") then return "Killer" end
    if character:GetAttribute("IsSurvivor") then return "Survivor" end
    local roleValue = character:FindFirstChild("Role")
    if roleValue and roleValue:IsA("StringValue") then
        local role = roleValue.Value:lower()
        if role:find("killer") then return "Killer" end
        if role:find("survivor") or role:find("survive") then return "Survivor" end
    end
    local isKillerValue = character:FindFirstChild("IsKiller")
    if isKillerValue and isKillerValue:IsA("BoolValue") and isKillerValue.Value then return "Killer" end
    local isSurvivorValue = character:FindFirstChild("IsSurvivor")
    if isSurvivorValue and isSurvivorValue:IsA("BoolValue") and isSurvivorValue.Value then return "Survivor" end
    if player.Team then
        local teamName = player.Team.Name:lower()
        if teamName:find("killer") then return "Killer" end
        if teamName:find("survivor") or teamName:find("survive") then return "Survivor" end
        local teamColor = player.TeamColor
        if teamColor == BrickColor.new("Really red") then return "Killer" end
        if teamColor == BrickColor.new("Lime green") or teamColor == BrickColor.new("Bright green") then return "Survivor" end
    end
    local charName = character.Name:lower()
    if charName:find("killer") then return "Killer" end
    if charName:find("survivor") then return "Survivor" end
    for _, item in pairs(character:GetChildren()) do
        if item:IsA("Tool") then
            local toolName = item.Name:lower()
            if toolName:find("knife") or toolName:find("weapon") or toolName:find("killer") then return "Killer" end
        end
    end
    return "Survivor"
end

local function GetESPColor(player)
    local role = GetPlayerRole(player)
    if role == "Killer" then return Color3.fromRGB(255, 0, 0)
    elseif role == "Survivor" then return Color3.fromRGB(0, 255, 0)
    else return Color3.fromRGB(255, 255, 255) end
end

-- Generator Detection - STRICT version
local function IsGenerator(obj)
    if not obj then return false end
    if not (obj:IsA("Model") or obj:IsA("BasePart")) then return false end
    
    local name = obj.Name:lower()
    
    -- EXCLUDE: Player characters, NPCs, tools, GUI elements
    if name:find("player") or name:find("character") or name:find("npc") 
        or name:find("killer") or name:find("survivor") or name:find("humanoid") then
        return false
    end
    
    -- Check if it's actually a player character (has Humanoid)
    if obj:IsA("Model") then
        if obj:FindFirstChildOfClass("Humanoid") then return false end
        -- Also check if it's in Players folder
        for _, p in pairs(Players:GetPlayers()) do
            if p.Character == obj then return false end
        end
    end
    
    -- ONLY match specific generator patterns
    local isGen = false
    
    -- Direct generator names
    if name:find("generator") then isGen = true end
    if name:find("gen%d") or name:find("gen_%d") or name:find("gen %d") then isGen = true end
    if name == "gen" then isGen = true end
    
    -- Forsaken specific (common patterns)
    if name:find("fusebox") or name:find("fuse_box") or name:find("fuse box") then isGen = true end
    if name:find("powerbox") or name:find("power_box") or name:find("power box") then isGen = true end
    if name:find("switchbox") or name:find("switch_box") then isGen = true end
    if name:find("lever") and not name:find("player") then isGen = true end
    
    return isGen
end

-- Generator Status Detection
local function IsGeneratorCompleted(gen)
    local genName = gen.Name:lower()
    
    -- Check attributes
    if gen:GetAttribute("Completed") == true then return true end
    if gen:GetAttribute("IsCompleted") == true then return true end
    if gen:GetAttribute("Finished") == true then return true end
    if gen:GetAttribute("Powered") == true then return true end
    if gen:GetAttribute("Done") == true then return true end
    
    -- Progress check
    local progress = gen:GetAttribute("Progress")
    if progress and (progress >= 1 or progress >= 100) then return true end
    
    -- Check children for completion
    for _, child in pairs(gen:GetChildren()) do
        local childName = child.Name:lower()
        
        if child:IsA("BoolValue") then
            if (childName:find("complet") or childName:find("finish") or childName:find("done")) and child.Value then 
                return true 
            end
        end
        
        if child:IsA("NumberValue") or child:IsA("IntValue") then
            if childName:find("progress") and (child.Value >= 100 or child.Value >= 1) then
                return true
            end
        end
    end
    
    return false
end

local function GetGeneratorProgress(gen)
    local progress = gen:GetAttribute("Progress")
    if progress then
        if progress <= 1 then return progress * 100 end
        return progress
    end
    
    for _, child in pairs(gen:GetChildren()) do
        if child.Name:lower():find("progress") then
            if child:IsA("NumberValue") or child:IsA("IntValue") then
                local val = child.Value
                if val <= 1 then return val * 100 end
                return val
            end
        end
    end
    
    return 0
end

-- ESP System
local ESPConnections = {}
local ESPHighlights = {}
local ESPLabels = {}
local GenHighlights = {}
local GenUpdateConnection = nil

local function CreateESPForPlayer(player)
    if player == LocalPlayer then return end
    local character = player.Character
    if not character then return end
    
    -- Clean up existing
    if ESPHighlights[player] then
        if ESPHighlights[player].Parent then ESPHighlights[player]:Destroy() end
    end
    if ESPLabels[player] then
        if ESPLabels[player].Parent then ESPLabels[player]:Destroy() end
    end
    
    local color = GetESPColor(player)
    local role = GetPlayerRole(player)
    
    local hl = Instance.new("Highlight")
    hl.Name = "ESP_Player_" .. player.Name
    hl.FillColor = color
    hl.OutlineColor = Color3.fromRGB(255, 255, 255)
    hl.FillTransparency = 0.5
    hl.Adornee = character
    hl.Parent = character
    ESPHighlights[player] = hl
    
    local head = character:FindFirstChild("Head")
    if head then
        local billboard = Instance.new("BillboardGui")
        billboard.Name = "ESP_PlayerLabel_" .. player.Name
        billboard.Size = UDim2.new(0, 150, 0, 40)
        billboard.StudsOffset = Vector3.new(0, 3, 0)
        billboard.Adornee = head
        billboard.AlwaysOnTop = true
        billboard.Parent = game.CoreGui
        
        local label = Instance.new("TextLabel")
        label.Size = UDim2.new(1, 0, 1, 0)
        label.BackgroundTransparency = 1
        label.TextColor3 = color
        label.TextStrokeTransparency = 0
        label.TextStrokeColor3 = Color3.fromRGB(0, 0, 0)
        label.TextScaled = true
        label.Font = Enum.Font.GothamBold
        label.Text = player.Name .. " [" .. role .. "]"
        label.Parent = billboard
        
        ESPLabels[player] = billboard
    end
end

local function RemoveESPForPlayer(player)
    if ESPHighlights[player] then
        if ESPHighlights[player].Parent then ESPHighlights[player]:Destroy() end
        ESPHighlights[player] = nil
    end
    if ESPLabels[player] then
        if ESPLabels[player].Parent then ESPLabels[player]:Destroy() end
        ESPLabels[player] = nil
    end
end

local function UpdateESPForPlayer(player)
    if not _G.ESP then return end
    if player == LocalPlayer then return end
    local character = player.Character
    if not character then return end
    
    local color = GetESPColor(player)
    local role = GetPlayerRole(player)
    
    if ESPHighlights[player] and ESPHighlights[player].Parent then
        ESPHighlights[player].FillColor = color
        ESPHighlights[player].Adornee = character
    end
    
    if ESPLabels[player] and ESPLabels[player].Parent then
        local label = ESPLabels[player]:FindFirstChild("TextLabel")
        if label then
            label.TextColor3 = color
            label.Text = player.Name .. " [" .. role .. "]"
        end
        local head = character:FindFirstChild("Head")
        if head then ESPLabels[player].Adornee = head end
    end
end

-- Generator ESP System
local function CreateGeneratorESP(gen)
    -- Skip if already tracked
    if GenHighlights[gen] then return end
    
    local isCompleted = IsGeneratorCompleted(gen)
    local progress = GetGeneratorProgress(gen)
    
    local fillColor, outlineColor, textColor
    if isCompleted then
        fillColor = Color3.fromRGB(0, 255, 100)
        outlineColor = Color3.fromRGB(150, 255, 150)
        textColor = Color3.fromRGB(0, 255, 100)
    else
        fillColor = Color3.fromRGB(255, 170, 0)
        outlineColor = Color3.fromRGB(255, 220, 100)
        textColor = Color3.fromRGB(255, 170, 0)
    end
    
    -- Create highlight
    local hl = Instance.new("Highlight")
    hl.Name = "GenESP_Highlight"
    hl.FillColor = fillColor
    hl.OutlineColor = outlineColor
    hl.FillTransparency = 0.5
    hl.Adornee = gen
    hl.Parent = gen
    
    -- Create label (only one)
    local billboard = nil
    local primaryPart = gen:IsA("Model") and gen.PrimaryPart 
        or (gen:IsA("BasePart") and gen or gen:FindFirstChildWhichIsA("BasePart"))
    
    if primaryPart then
        billboard = Instance.new("BillboardGui")
        billboard.Name = "GenESP_Label"
        billboard.Size = UDim2.new(0, 120, 0, 30)
        billboard.StudsOffset = Vector3.new(0, 5, 0)
        billboard.Adornee = primaryPart
        billboard.AlwaysOnTop = true
        billboard.Parent = game.CoreGui
        
        local label = Instance.new("TextLabel")
        label.Name = "GenLabel"
        label.Size = UDim2.new(1, 0, 1, 0)
        label.BackgroundTransparency = 1
        label.TextColor3 = textColor
        label.TextStrokeTransparency = 0
        label.TextStrokeColor3 = Color3.fromRGB(0, 0, 0)
        label.TextScaled = true
        label.Font = Enum.Font.GothamBold
        label.Text = isCompleted and "✓ COMPLETE" or ("⚡ " .. math.floor(progress) .. "%")
        label.Parent = billboard
    end
    
    -- Store reference
    GenHighlights[gen] = {
        Highlight = hl, 
        Label = billboard, 
        LastCompleted = isCompleted, 
        LastProgress = progress
    }
end

local function UpdateGeneratorESP()
    if not _G.GenESP then return end
    
    for gen, data in pairs(GenHighlights) do
        if gen and gen.Parent then
            local isCompleted = IsGeneratorCompleted(gen)
            local progress = GetGeneratorProgress(gen)
            
            -- Update if state changed
            if isCompleted ~= data.LastCompleted then
                data.LastCompleted = isCompleted
                
                local fillColor, outlineColor, textColor
                if isCompleted then
                    fillColor = Color3.fromRGB(0, 255, 100)
                    outlineColor = Color3.fromRGB(150, 255, 150)
                    textColor = Color3.fromRGB(0, 255, 100)
                else
                    fillColor = Color3.fromRGB(255, 170, 0)
                    outlineColor = Color3.fromRGB(255, 220, 100)
                    textColor = Color3.fromRGB(255, 170, 0)
                end
                
                if data.Highlight and data.Highlight.Parent then
                    data.Highlight.FillColor = fillColor
                    data.Highlight.OutlineColor = outlineColor
                end
                
                if data.Label and data.Label.Parent then
                    local label = data.Label:FindFirstChild("GenLabel")
                    if label then
                        label.TextColor3 = textColor
                        label.Text = isCompleted and "✓ COMPLETE" or ("⚡ " .. math.floor(progress) .. "%")
                    end
                end
            end
            
            -- Update progress
            if not isCompleted and progress ~= data.LastProgress then
                data.LastProgress = progress
                if data.Label and data.Label.Parent then
                    local label = data.Label:FindFirstChild("GenLabel")
                    if label then
                        label.Text = "⚡ " .. math.floor(progress) .. "%"
                    end
                end
            end
        else
            -- Clean up removed generators
            if data.Highlight then data.Highlight:Destroy() end
            if data.Label then data.Label:Destroy() end
            GenHighlights[gen] = nil
        end
    end
end

local function RemoveAllGeneratorESP()
    for gen, data in pairs(GenHighlights) do
        if data.Highlight then data.Highlight:Destroy() end
        if data.Label then data.Label:Destroy() end
    end
    GenHighlights = {}
end

-- Find all generators
local function FindAllGenerators()
    local generators = {}
    
    for _, obj in pairs(Workspace:GetDescendants()) do
        if IsGenerator(obj) then
            table.insert(generators, obj)
        end
    end
    
    return generators
end

-- Tabs
local MainTab = Window:AddTab("Main")
local PlayerTab = Window:AddTab("Player")
local GameTab = Window:AddTab("Game")
local ServerTab = Window:AddTab("Server")
local SettingsTab = Window:AddTab("Settings")

-- MAIN TAB
MainTab:New("Title")({ Title = "🛠️ Quick Actions" })

MainTab:New("Button")({
    Title = "Reset Character",
    Description = "Respawn your character",
    Callback = function()
        LocalPlayer:LoadCharacter()
        Notify("Success", "Character reset!", "Success")
    end,
})

MainTab:New("Button")({
    Title = "Refresh Movement",
    Description = "Reset WalkSpeed, JumpPower & Gravity to defaults",
    Callback = function()
        local hum = GetHumanoid()
        if hum then
            hum.WalkSpeed = Config.WalkSpeedDefault
            hum.JumpPower = Config.JumpPowerDefault
        end
        Workspace.Gravity = Config.GravityDefault
        
        UpdateWalkSpeedUI(Config.WalkSpeedDefault)
        UpdateJumpPowerUI(Config.JumpPowerDefault)
        UpdateGravityUI(Config.GravityDefault)
        
        Notify("Reset", "Movement & gravity refreshed!", "Success")
    end,
})

MainTab:New("Title")({ Title = "🎯 Teleport" })

local TargetName = ""
MainTab:New("Input")({
    Title = "Player Name",
    Description = "Enter target player name",
    Placeholder = "Type name here...",
    Callback = function(v) TargetName = v end,
})

MainTab:New("Button")({
    Title = "Teleport To",
    Description = "Go to target player",
    Callback = function()
        if TargetName == "" then Notify("Warning", "Enter a player name!", "Warning") return end
        local target = GetPlayerByName(TargetName)
        if target and target.Character then
            local myRoot = GetRootPart()
            local tRoot = target.Character:FindFirstChild("HumanoidRootPart")
            if myRoot and tRoot then
                myRoot.CFrame = tRoot.CFrame * CFrame.new(0, 0, 3)
                Notify("Success", "Teleported to " .. target.Name, "Success")
            end
        else
            Notify("Error", "Player not found!", "Error")
        end
    end,
})

MainTab:New("Button")({
    Title = "Bring Player",
    Description = "Bring target to you (visual)",
    Callback = function()
        if TargetName == "" then Notify("Warning", "Enter a player name!", "Warning") return end
        local target = GetPlayerByName(TargetName)
        if target and target.Character then
            local myRoot = GetRootPart()
            local tRoot = target.Character:FindFirstChild("HumanoidRootPart")
            if myRoot and tRoot then
                tRoot.CFrame = myRoot.CFrame * CFrame.new(0, 0, -3)
                Notify("Success", "Brought " .. target.Name, "Success")
            end
        else
            Notify("Error", "Player not found!", "Error")
        end
    end,
})

-- PLAYER TAB
PlayerTab:New("Title")({ Title = "🏃 Movement" })

local currentWalkSpeed = Config.WalkSpeedDefault
UIElements.WalkSpeedSlider = PlayerTab:New("Slider")({
    Title = "WalkSpeed",
    Description = "Adjust walking speed (Default: 16)",
    Default = Config.WalkSpeedDefault,
    Minimum = 1,
    Maximum = 200,
    DecimalCount = 0,
    Callback = function(v)
        currentWalkSpeed = v
        local hum = GetHumanoid()
        if hum then hum.WalkSpeed = v end
        if UIElements.WalkSpeedInput then
            pcall(function() UIElements.WalkSpeedInput:Set(tostring(v)) end)
        end
    end,
})

UIElements.WalkSpeedInput = PlayerTab:New("Input")({
    Title = "WalkSpeed (Custom Value)",
    Description = "Type any value (no limits)",
    Placeholder = "16",
    Callback = function(v)
        local num = tonumber(v)
        if num then
            currentWalkSpeed = math.clamp(num, 1, 200)
            local hum = GetHumanoid()
            if hum then hum.WalkSpeed = currentWalkSpeed end
            if UIElements.WalkSpeedSlider then
                pcall(function() UIElements.WalkSpeedSlider:Set(currentWalkSpeed) end)
            end
        end
    end,
})

local currentJumpPower = Config.JumpPowerDefault
UIElements.JumpPowerSlider = PlayerTab:New("Slider")({
    Title = "Jump Power",
    Description = "Adjust jump power (Default: 50)",
    Default = Config.JumpPowerDefault,
    Minimum = 0,
    Maximum = 300,
    DecimalCount = 0,
    Callback = function(v)
        currentJumpPower = v
        local hum = GetHumanoid()
        if hum then hum.JumpPower = v end
        if UIElements.JumpPowerInput then
            pcall(function() UIElements.JumpPowerInput:Set(tostring(v)) end)
        end
    end,
})

UIElements.JumpPowerInput = PlayerTab:New("Input")({
    Title = "Jump Power (Custom Value)",
    Description = "Type any value (no limits)",
    Placeholder = "50",
    Callback = function(v)
        local num = tonumber(v)
        if num then
            currentJumpPower = math.clamp(num, 0, 300)
            local hum = GetHumanoid()
            if hum then hum.JumpPower = currentJumpPower end
            if UIElements.JumpPowerSlider then
                pcall(function() UIElements.JumpPowerSlider:Set(currentJumpPower) end)
            end
        end
    end,
})

local currentGravity = Config.GravityDefault
UIElements.GravitySlider = PlayerTab:New("Slider")({
    Title = "Gravity",
    Description = "Adjust workspace gravity (Default: 196)",
    Default = Config.GravityDefault,
    Minimum = 0,
    Maximum = 500,
    DecimalCount = 0,
    Callback = function(v)
        currentGravity = v
        Workspace.Gravity = v
        if UIElements.GravityInput then
            pcall(function() UIElements.GravityInput:Set(tostring(v)) end)
        end
    end,
})

UIElements.GravityInput = PlayerTab:New("Input")({
    Title = "Gravity (Custom Value)",
    Description = "Type any value (no limits)",
    Placeholder = "196",
    Callback = function(v)
        local num = tonumber(v)
        if num then
            currentGravity = math.clamp(num, 0, 500)
            Workspace.Gravity = currentGravity
            if UIElements.GravitySlider then
                pcall(function() UIElements.GravitySlider:Set(currentGravity) end)
            end
        end
    end,
})

PlayerTab:New("Title")({ Title = "⚡ Toggles" })

PlayerTab:New("Toggle")({
    Title = "Infinite Jump",
    Description = "Jump in the air",
    DefaultValue = false,
    Callback = function(v)
        if v then
            _G.InfJump = true
            _G.InfJumpCon = UserInputService.JumpRequest:Connect(function()
                if _G.InfJump then
                    local hum = GetHumanoid()
                    if hum then hum:ChangeState(Enum.HumanoidStateType.Jumping) end
                end
            end)
            Notify("Enabled", "Infinite Jump ON", "Success")
        else
            _G.InfJump = false
            if _G.InfJumpCon then _G.InfJumpCon:Disconnect() end
            Notify("Disabled", "Infinite Jump OFF", "Info")
        end
    end,
})

PlayerTab:New("Toggle")({
    Title = "NoClip",
    Description = "Walk through walls",
    DefaultValue = false,
    Callback = function(v)
        if v then
            _G.NC = true
            _G.NCCon = RunService.Stepped:Connect(function()
                if _G.NC then
                    local char = LocalPlayer.Character
                    if char then
                        for _, p in pairs(char:GetDescendants()) do
                            if p:IsA("BasePart") then p.CanCollide = false end
                        end
                    end
                end
            end)
            Notify("Enabled", "NoClip ON", "Success")
        else
            _G.NC = false
            if _G.NCCon then _G.NCCon:Disconnect() end
            Notify("Disabled", "NoClip OFF", "Info")
        end
    end,
})

PlayerTab:New("Title")({ Title = "✈️ Fly Settings" })

local currentFlySpeed = Config.FlySpeedDefault
UIElements.FlySpeedSlider = PlayerTab:New("Slider")({
    Title = "Fly Speed",
    Description = "Set fly movement speed (Default: 100)",
    Default = Config.FlySpeedDefault,
    Minimum = 1,
    Maximum = 500,
    DecimalCount = 0,
    Callback = function(v)
        currentFlySpeed = v
        Config.FlySpeed = v
        if UIElements.FlySpeedInput then
            pcall(function() UIElements.FlySpeedInput:Set(tostring(v)) end)
        end
    end,
})

UIElements.FlySpeedInput = PlayerTab:New("Input")({
    Title = "Fly Speed (Custom Value)",
    Description = "Type any value (no limits)",
    Placeholder = "100",
    Callback = function(v)
        local num = tonumber(v)
        if num then
            currentFlySpeed = math.clamp(num, 1, 500)
            Config.FlySpeed = currentFlySpeed
            if UIElements.FlySpeedSlider then
                pcall(function() UIElements.FlySpeedSlider:Set(currentFlySpeed) end)
            end
        end
    end,
})

PlayerTab:New("Button")({
    Title = "Reset Fly Speed",
    Description = "Reset fly speed to default (100)",
    Callback = function()
        Config.FlySpeed = Config.FlySpeedDefault
        currentFlySpeed = Config.FlySpeedDefault
        UpdateFlySpeedUI(Config.FlySpeedDefault)
        Notify("Reset", "Fly speed reset to " .. Config.FlySpeedDefault, "Success")
    end,
})

PlayerTab:New("Toggle")({
    Title = "Fly [DETECTED AFTER FEW SECONDS OF USE!]",
    Description = "Toggle client fly",
    DefaultValue = false,
    Callback = function(v)
        if v then
            _G.Fly = true
            local root = GetRootPart()
            if root then
                local bodyVel = Instance.new("BodyVelocity")
                bodyVel.Name = "FlyVel"
                bodyVel.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
                bodyVel.Velocity = Vector3.new(0, 0, 0)
                bodyVel.Parent = root
                local bodyGyro = Instance.new("BodyGyro")
                bodyGyro.Name = "FlyGyro"
                bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
                bodyGyro.P = 9e4
                bodyGyro.Parent = root
                _G.FlyCon = RunService.RenderStepped:Connect(function()
                    if _G.Fly and root and root.Parent then
                        local cam = Workspace.CurrentCamera
                        local move = Vector3.new(0, 0, 0)
                        local hum = GetHumanoid()
                        if hum and hum.MoveDirection.Magnitude > 0 then
                            move = cam.CFrame:VectorToWorldSpace(Vector3.new(hum.MoveDirection.X, 0, hum.MoveDirection.Z))
                        end
                        bodyVel.Velocity = move * Config.FlySpeed
                        bodyGyro.CFrame = cam.CFrame
                    end
                end)
                Notify("Enabled", "Fly ON (Speed: " .. Config.FlySpeed .. ")", "Success")
            end
        else
            _G.Fly = false
            if _G.FlyCon then _G.FlyCon:Disconnect() end
            local root = GetRootPart()
            if root then
                local bv = root:FindFirstChild("FlyVel")
                local bg = root:FindFirstChild("FlyGyro")
                if bv then bv:Destroy() end
                if bg then bg:Destroy() end
            end
            Notify("Disabled", "Fly OFF", "Info")
        end
    end,
})

-- GAME TAB
GameTab:New("Title")({ Title = "👁️ Visuals" })

GameTab:New("Toggle")({
    Title = "ESP Players",
    Description = "Survivors=Green, Killers=Red, Lobby=White",
    DefaultValue = false,
    Callback = function(v)
        if v then
            _G.ESP = true
            for _, p in pairs(Players:GetPlayers()) do
                if p ~= LocalPlayer then
                    p.CharacterAdded:Connect(function(char)
                        if _G.ESP then task.wait(0.5) CreateESPForPlayer(p) end
                    end)
                    if p.Character then CreateESPForPlayer(p) end
                end
            end
            local playerAddedConn = Players.PlayerAdded:Connect(function(p)
                p.CharacterAdded:Connect(function()
                    if _G.ESP then task.wait(0.5) CreateESPForPlayer(p) end
                end)
            end)
            table.insert(ESPConnections, playerAddedConn)
            local updateConn = RunService.Heartbeat:Connect(function()
                if _G.ESP then
                    for _, p in pairs(Players:GetPlayers()) do
                        if p ~= LocalPlayer and p.Character then UpdateESPForPlayer(p) end
                    end
                end
            end)
            table.insert(ESPConnections, updateConn)
            Notify("Enabled", "ESP ON - Colors by role!", "Success")
        else
            _G.ESP = false
            for _, conn in pairs(ESPConnections) do if conn then conn:Disconnect() end end
            ESPConnections = {}
            for _, p in pairs(Players:GetPlayers()) do RemoveESPForPlayer(p) end
            Notify("Disabled", "ESP OFF", "Info")
        end
    end,
})

GameTab:New("Toggle")({
    Title = "Fullbright",
    Description = "Brighter environment",
    DefaultValue = false,
    Callback = function(v)
        if v then
            _G.OldBright = Lighting.Brightness
            _G.OldTime = Lighting.ClockTime
            _G.OldFog = Lighting.FogEnd
            _G.OldShadows = Lighting.GlobalShadows
            Lighting.Brightness = 2
            Lighting.ClockTime = 14
            Lighting.FogEnd = 100000
            Lighting.GlobalShadows = false
            Notify("Enabled", "Fullbright ON", "Success")
        else
            Lighting.Brightness = _G.OldBright or 1
            Lighting.ClockTime = _G.OldTime or 14
            Lighting.FogEnd = _G.OldFog or 100000
            Lighting.GlobalShadows = _G.OldShadows or true
            Notify("Disabled", "Fullbright OFF", "Info")
        end
    end,
})

GameTab:New("Title")({ Title = "⚡ Generator ESP" })

GameTab:New("Toggle")({
    Title = "Generator ESP",
    Description = "Incomplete=Orange, Complete=Green",
    DefaultValue = false,
    Callback = function(v)
        if v then
            _G.GenESP = true
            
            local generators = FindAllGenerators()
            local genCount = 0
            local completedCount = 0
            
            for _, gen in pairs(generators) do
                CreateGeneratorESP(gen)
                genCount = genCount + 1
                if IsGeneratorCompleted(gen) then completedCount = completedCount + 1 end
            end
            
            -- Start update loop
            spawn(function()
                while _G.GenESP do
                    task.wait(0.5)
                    UpdateGeneratorESP()
                end
            end)
            
            Notify("Enabled", genCount .. " generators (" .. completedCount .. " done, " .. (genCount - completedCount) .. " left)", "Success")
        else
            _G.GenESP = false
            RemoveAllGeneratorESP()
            Notify("Disabled", "Generator ESP OFF", "Info")
        end
    end,
})

GameTab:New("Button")({
    Title = "Refresh Generator ESP",
    Description = "Re-scan for generators",
    Callback = function()
        if not _G.GenESP then
            Notify("Warning", "Enable Generator ESP first!", "Warning")
            return
        end
        
        local generators = FindAllGenerators()
        local newCount = 0
        for _, gen in pairs(generators) do
            if not GenHighlights[gen] then
                CreateGeneratorESP(gen)
                newCount = newCount + 1
            end
        end
        Notify("Refreshed", newCount .. " new generators found", "Success")
    end,
})

GameTab:New("Button")({
    Title = "Debug: Print All Objects",
    Description = "Print workspace objects to console (F9)",
    Callback = function()
        print("=== FCAL HUB - Workspace Objects ===")
        
        local counted = {}
        for _, obj in pairs(Workspace:GetDescendants()) do
            if obj:IsA("Model") or obj:IsA("BasePart") then
                local name = obj.Name
                if not counted[name] then
                    counted[name] = 0
                end
                counted[name] = counted[name] + 1
            end
        end
        
        for name, count in pairs(counted) do
            print(name .. " (x" .. count .. ")")
        end
        
        Notify("Debug", "Check console (F9) for object list!", "Info")
    end,
})

GameTab:New("Title")({ Title = "🎯 Find Objects" })

GameTab:New("Button")({
    Title = "Find Generators",
    Description = "Highlight generators (Static)",
    Callback = function()
        local generators = FindAllGenerators()
        local c = 0
        local completed = 0
        
        for _, gen in pairs(generators) do
            local isComplete = IsGeneratorCompleted(gen)
            local hl = Instance.new("Highlight")
            
            if isComplete then
                hl.FillColor = Color3.fromRGB(0, 255, 100)
                completed = completed + 1
            else
                hl.FillColor = Color3.fromRGB(255, 170, 0)
            end
            
            hl.OutlineColor = Color3.fromRGB(255, 255, 255)
            hl.FillTransparency = 0.5
            hl.Adornee = gen
            hl.Parent = gen
            c = c + 1
        end
        
        Notify("Found", c .. " generators (" .. completed .. " done, " .. (c - completed) .. " left)", "Success")
    end,
})

GameTab:New("Button")({
    Title = "Find Exit Gates",
    Description = "Highlight exit gates",
    Callback = function()
        local c = 0
        for _, o in pairs(Workspace:GetDescendants()) do
            if (o.Name:lower():find("gate") or o.Name:lower():find("exit")) and (o:IsA("Model") or o:IsA("BasePart")) then
                local hl = Instance.new("Highlight")
                hl.FillColor = Color3.fromRGB(0, 255, 0)
                hl.OutlineColor = Color3.fromRGB(255, 255, 255)
                hl.FillTransparency = 0.5
                hl.Adornee = o
                hl.Parent = o
                c = c + 1
            end
        end
        Notify("Found", c .. " exit gates highlighted!", "Success")
    end,
})

GameTab:New("Button")({
    Title = "Clear Highlights",
    Description = "Remove all highlights",
    Callback = function()
        local count = 0
        for _, o in pairs(Workspace:GetDescendants()) do
            if o:IsA("Highlight") then 
                o:Destroy() 
                count = count + 1
            end
        end
        -- Also clear from CoreGui
        for _, o in pairs(game.CoreGui:GetChildren()) do
            if o.Name:find("ESP_") or o.Name:find("GenESP_") then
                o:Destroy()
            end
        end
        -- Clear tracking tables
        ESPHighlights = {}
        ESPLabels = {}
        GenHighlights = {}
        
        Notify("Cleared", count .. " highlights removed!", "Info")
    end,
})

-- SERVER TAB
ServerTab:New("Title")({ Title = "🌐 Server Info" })

ServerTab:New("Button")({
    Title = "Copy Job ID",
    Description = "Copy server JobId",
    Callback = function()
        if setclipboard then
            setclipboard(game.JobId)
            Notify("Copied", "Job ID copied!", "Success")
        else
            Notify("Job ID", game.JobId, "Info")
        end
    end,
})

ServerTab:New("Button")({
    Title = "Copy Place ID",
    Description = "Copy game PlaceId",
    Callback = function()
        if setclipboard then
            setclipboard(tostring(game.PlaceId))
            Notify("Copied", "Place ID copied!", "Success")
        else
            Notify("Place ID", tostring(game.PlaceId), "Info")
        end
    end,
})

ServerTab:New("Title")({ Title = "🚪 Actions" })

ServerTab:New("Button")({
    Title = "Rejoin",
    Description = "Rejoin current server",
    Callback = function() TeleportService:TeleportToPlaceInstance(game.PlaceId, game.JobId, LocalPlayer) end,
})

ServerTab:New("Button")({
    Title = "Server Hop",
    Description = "Join a different server",
    Callback = function() TeleportService:Teleport(game.PlaceId, LocalPlayer) end,
})

ServerTab:New("Title")({ Title = "👁️ Spectate" })

local SpecTarget = ""
local names = {}
for _, p in pairs(Players:GetPlayers()) do
    if p ~= LocalPlayer then table.insert(names, p.Name) end
end

ServerTab:New("Dropdown")({
    Title = "Select Player",
    Description = "Choose player to spectate",
    Options = #names > 0 and names or {"No Players"},
    Default = "",
    Callback = function(v) SpecTarget = v end,
})

ServerTab:New("Button")({
    Title = "Spectate",
    Description = "Watch selected player",
    Callback = function()
        if SpecTarget ~= "" then
            local t = GetPlayerByName(SpecTarget)
            if t and t.Character then
                Workspace.CurrentCamera.CameraSubject = t.Character:FindFirstChildOfClass("Humanoid") or t.Character
                Notify("Spectating", "Now watching " .. t.Name, "Info")
            end
        else
            Notify("Warning", "Select a player first!", "Warning")
        end
    end,
})

ServerTab:New("Button")({
    Title = "Stop Spectating",
    Description = "Return to your character",
    Callback = function()
        if LocalPlayer.Character then
            Workspace.CurrentCamera.CameraSubject = LocalPlayer.Character:FindFirstChildOfClass("Humanoid") or LocalPlayer.Character
            Notify("Stopped", "Returned to your view", "Info")
        end
    end,
})

-- SETTINGS TAB
SettingsTab:New("Title")({ Title = "🎨 Theme" })

SettingsTab:New("Dropdown")({
    Title = "Select Theme",
    Description = "Change UI theme",
    Options = {"Dark", "Light", "Midnight", "Rose", "Emerald"},
    Default = Config.Theme,
    Callback = function(v)
        Window:SetTheme(v)
        Notify("Theme", "Changed to " .. v, "Success")
    end,
})

SettingsTab:New("Title")({ Title = "⌨️ Keybind" })

local ToggleKey = "RightControl"
SettingsTab:New("Keybind")({
    Title = "Toggle UI",
    Description = "Key to hide/show",
    DefaultKeybind = ToggleKey,
    Callback = function(k) ToggleKey = k end,
})

SettingsTab:New("Title")({ Title = "❌ Exit" })

SettingsTab:New("Button")({
    Title = "Destroy UI",
    Description = "Close FCAL HUB",
    Callback = function()
        _G.InfJump = false; if _G.InfJumpCon then _G.InfJumpCon:Disconnect() end
        _G.NC = false; if _G.NCCon then _G.NCCon:Disconnect() end
        _G.Fly = false; if _G.FlyCon then _G.FlyCon:Disconnect() end
        _G.ESP = false; _G.GenESP = false
        for _, conn in pairs(ESPConnections) do if conn then conn:Disconnect() end end
        for _, p in pairs(Players:GetPlayers()) do RemoveESPForPlayer(p) end
        RemoveAllGeneratorESP()
        Window:Destroy()
    end,
})

-- Keybind Handler
UserInputService.InputBegan:Connect(function(input, processed)
    if processed then return end
    if Modal:IsCorrectInput(input, ToggleKey) then
        local gui = LocalPlayer:FindFirstChild("PlayerGui")
        if gui then
            local m = gui:FindFirstChild("Modal")
            if m then m.Enabled = not m.Enabled end
        end
    end
end)

-- Init
Notify("FCAL HUB", "Loaded successfully! v1.0.6", "Success")
print("FCAL HUB v1.0.6 - Loaded!")

Features & Information

Execute and enjoy this is under development so there’s gonna be bugs
#Keyless

Community Comments (1)

NotsotufftimmyNotsotufftimmyFeb 21, 2026

What are the features

More Scripts for Forsaken