Further enhance and add in lock-on.

```
--[[
    Enhanced Lock-On and ESP Script with ShiftLock Support and Improved Predictive Algorithm
    - Always targets the closest torso (UpperTorso for R15, Torso for R6).
    - Implements an advanced prediction algorithm using Exponential Moving Average (EMA).
    - Includes hitbox detection to ensure ESP accuracy.
    - Track layering to prioritize the closest target.
    - Adds ShiftLock support to toggle between normal camera control and Lock-On mode.
    - Removes the Target Selection GUI for streamlined functionality.
    - Maintains comprehensive debugging for easier troubleshooting.
--]]

-- Services
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local GuiService = game:GetService("GuiService")
local ContextActionService = game:GetService("ContextActionService")
local TweenService = game:GetService("TweenService")
local Workspace = game:GetService("Workspace")
local CurrentCamera = Workspace.CurrentCamera

-- Configuration
local DEBUG = true  -- Toggle debug logs
local ROTATION_SPEED = 25       -- Smooth rotation speed multiplier
local ESP_TEXT_PREFIX = "Targeted:"      -- Prefix Text displayed in ESP
local ESP_COLOR = Color3.fromRGB(255, 0, 0)  -- Color of the ESP text
local PREDICTION_TIME_BASE = 1.1 -- Base time in seconds to predict target movement
local PREDICTION_TIME_ADJUSTMENT_FACTOR = 0.5 -- Factor to adjust prediction time based on velocity and distance
local VELOCITY_ALPHA = 0.8 -- Alpha value for Exponential Moving Average
local LOCK_ON_KEY = Enum.KeyCode.E -- Key to toggle lock-on
local SHIFT_LOCK_TOGGLE_KEY = Enum.KeyCode.LeftShift -- Key to toggle ShiftLock mode

-- Debug Function
local function debugLog(message)
    if DEBUG then
        print("[LockOnScript]: " .. message)
    end
end

-- Variables
local player = Players.LocalPlayer
if not player then
    error("LocalPlayer not found!")
    return
end

local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local trackedTarget = nil          -- Currently tracked target (another player)
local espIndicator = nil           -- BillboardGui for ESP
local shiftLockMode = false        -- ShiftLock mode toggle
local lockOnMode = false           -- Lock-On mode toggle
local velocityEMA = Vector3.new(0, 0, 0) -- Exponential Moving Average for target velocity

-- Determine Rig Type and set the torso part name
local isR15 = humanoid.RigType == Enum.HumanoidRigType.R15
local torsoPartName = isR15 and "UpperTorso" or "Torso"
debugLog("Rig type determined: " .. (isR15 and "R15" or "R6"))
debugLog("Torso part set to: " .. torsoPartName)

-- Helper Function: Check if a model has a Humanoid
local function hasHumanoid(model)
    return model and model:FindFirstChildOfClass("Humanoid") ~= nil
end

-- Helper Function: Find the closest player to the local player
local function findClosestPlayer()
    local closestPlayer = nil
    local shortestDistance = math.huge

    for _, otherPlayer in ipairs(Players:GetPlayers()) do
        if otherPlayer ~= player and otherPlayer.Character and otherPlayer.Character:FindFirstChild(torsoPartName) then
            local otherTorso = otherPlayer.Character:FindFirstChild(torsoPartName)
            if otherTorso and otherTorso:IsA("BasePart") then
                local distance = (otherTorso.Position - humanoidRootPart.Position).Magnitude
                if distance < shortestDistance then
                    shortestDistance = distance
                    closestPlayer = otherPlayer
                end
            end
        end
    end

    if closestPlayer then
        debugLog("Closest player found: " .. closestPlayer.Name .. " with distance " .. string.format("%.2f", shortestDistance))
    else
        debugLog("No closest player found.")
    end

    return closestPlayer
end

-- Function: Toggle Lock-On to the Closest Player when LOCK_ON_KEY is pressed
local function toggleLockOn()
    if lockOnMode then
        -- Deselect the current target
        debugLog("Deselecting current target: " .. (trackedTarget and trackedTarget.Name or "None"))
        trackedTarget = nil
        lockOnMode = false
        if espIndicator then
            espIndicator:Destroy()
            espIndicator = nil
            debugLog("ESP indicator destroyed.")
        end
    else
        -- Find and select the closest player
        local closestPlayer = findClosestPlayer()
        if closestPlayer and closestPlayer.Character then
            trackedTarget = closestPlayer.Character
            lockOnMode = true
            debugLog("Tracking new target: " .. closestPlayer.Name)
            -- Create ESP indicator
            local targetTorso = trackedTarget:FindFirstChild(torsoPartName)
            if targetTorso then
                -- Ensure previous ESP is removed
                if espIndicator then
                    espIndicator:Destroy()
                    espIndicator = nil
                    debugLog("Previous ESP indicator destroyed.")
                end

                -- Create BillboardGui for ESP
                espIndicator = Instance.new("BillboardGui")
                espIndicator.Adornee = targetTorso
                espIndicator.Size = UDim2.new(0, 100, 0, 50)
                espIndicator.StudsOffset = Vector3.new(0, 2, 0)
                espIndicator.AlwaysOnTop = true
                espIndicator.Name = "TargetESP"

                -- Create TextLabel for ESP
                local textLabel = Instance.new("TextLabel")
                textLabel.Parent = espIndicator
                textLabel.Size = UDim2.new(1, 0, 1, 0)
                textLabel.BackgroundTransparency = 1
                textLabel.Text = ESP_TEXT_PREFIX .. " " .. closestPlayer.Name
                textLabel.TextColor3 = ESP_COLOR
                textLabel.Font = Enum.Font.SourceSansBold
                textLabel.TextScaled = true
                textLabel.TextStrokeTransparency = 0.8

                -- Parent the ESP to the player's PlayerGui
                local playerGui = player:WaitForChild("PlayerGui")
                espIndicator.Parent = playerGui
                debugLog("ESP indicator created for " .. closestPlayer.Name)
            else
                debugLog("Torso part '" .. torsoPartName .. "' not found on " .. closestPlayer.Name)
                trackedTarget = nil
            end
        else
            debugLog("No valid closest player to track.")
        end
    end
end

-- Function: Predict Future Position Based on Target's Velocity using EMA
local function getPredictedPosition(targetCharacter)
    local targetTorso = targetCharacter:FindFirstChild(torsoPartName)
    if not targetTorso then
        debugLog("Target does not have " .. torsoPartName .. ".")
        return nil
    end

    -- Get current velocity
    local currentVelocity = targetTorso.Velocity

    -- Update Exponential Moving Average (EMA) for velocity
    velocityEMA = (currentVelocity * VELOCITY_ALPHA) + (velocityEMA * (1 - VELOCITY_ALPHA))

    -- Calculate dynamic prediction time based on velocity magnitude and distance
    local distance = (targetTorso.Position - humanoidRootPart.Position).Magnitude
    local velocityMagnitude = velocityEMA.Magnitude
    local predictionTime = PREDICTION_TIME_BASE + (velocityMagnitude * PREDICTION_TIME_ADJUSTMENT_FACTOR) + (distance * PREDICTION_TIME_ADJUSTMENT_FACTOR)
    predictionTime = math.clamp(predictionTime, 0.2, 0.8) -- Clamp prediction time between 0.2 and 0.8 seconds

    -- Calculate predicted position
    local futurePosition = targetTorso.Position + (velocityEMA * predictionTime)
    debugLog(string.format("Predicted position: (%.2f, %.2f, %.2f); Prediction Time: %.2f", 
        futurePosition.X, futurePosition.Y, futurePosition.Z, predictionTime))
    
    return futurePosition
end

-- Function: Instantly rotate to face the predicted target position
local function instantRotateToPosition(targetPosition)
    if not targetPosition then return end

    local desiredCFrame = CFrame.new(humanoidRootPart.Position, targetPosition)
    humanoidRootPart.CFrame = desiredCFrame
    debugLog("Instantly rotated to face predicted position.")
end

-- Function: Smoothly rotate to face the predicted target position
local function smoothRotateToPosition(targetPosition, deltaTime)
    if not targetPosition then return end

    local direction = (Vector3.new(targetPosition.X, humanoidRootPart.Position.Y, targetPosition.Z) - humanoidRootPart.Position).Unit
    local desiredCFrame = CFrame.new(humanoidRootPart.Position, humanoidRootPart.Position + direction)

    -- Smoothly interpolate the CFrame
    humanoidRootPart.CFrame = humanoidRootPart.CFrame:Lerp(desiredCFrame, ROTATION_SPEED * deltaTime)
    debugLog("Smoothly rotated to face predicted position.")
end

-- Function: Rotate to Target (Instant or Smooth based on toggle)
local function rotateToTarget(deltaTime)
    if not trackedTarget then return end

    local targetTorso = trackedTarget:FindFirstChild(torsoPartName)
    if targetTorso and targetTorso:IsA("BasePart") then
        local predictedPosition = getPredictedPosition(trackedTarget)
        if predictedPosition then
            if shiftLockMode then
                instantRotateToPosition(predictedPosition)
            else
                smoothRotateToPosition(predictedPosition, deltaTime)
            end

            -- Hitbox Detection: Ensure predicted position is within torso bounds
            local torsoSize = targetTorso.Size
            local torsoPosition = targetTorso.Position
            local deltaPosition = predictedPosition - torsoPosition

            local withinX = math.abs(deltaPosition.X) <= (torsoSize.X / 2)
            local withinY = math.abs(deltaPosition.Y) <= (torsoSize.Y / 2)
            local withinZ = math.abs(deltaPosition.Z) <= (torsoSize.Z / 2)

            if withinX and withinY and withinZ then
                debugLog("Predicted position is within the torso hitbox.")
            else
                debugLog("Predicted position is outside the torso hitbox.")
            end
        else
            debugLog("Failed to get predicted position.")
        end
    else
        debugLog("Torso part '" .. torsoPartName .. "' is invalid or missing.")
    end
end

-- Function: Handle ShiftLock Toggle
local function toggleShiftLock()
    if shiftLockMode then
        -- Disable ShiftLock Mode
        shiftLockMode = false
        CurrentCamera.CameraType = Enum.CameraType.Custom
        debugLog("ShiftLock mode disabled.")
    else
        if lockOnMode then
            -- Disable Lock-On before enabling ShiftLock to prevent conflicts
            toggleLockOn()
        end
        -- Enable ShiftLock Mode
        shiftLockMode = true
        CurrentCamera.CameraType = Enum.CameraType.Scriptable
        -- Lock the camera to look at the target
        if trackedTarget then
            local targetTorso = trackedTarget:FindFirstChild(torsoPartName)
            if targetTorso then
                CurrentCamera.CFrame = CFrame.new(humanoidRootPart.Position, targetTorso.Position)
                debugLog("ShiftLock mode enabled and camera locked onto target.")
            end
        end
    end
end

-- Function: Clean up ESP when the tracked target dies or leaves
local function onTrackedTargetRemoved()
    if not trackedTarget then return end
    debugLog("Tracked target removed or died: " .. (trackedTarget.Name or "Unknown"))
    trackedTarget = nil
    lockOnMode = false
    if espIndicator then
        espIndicator:Destroy()
        espIndicator = nil
        debugLog("ESP indicator destroyed due to target removal.")
    end
    velocityEMA = Vector3.new(0, 0, 0) -- Reset velocity EMA
    -- Reset camera if ShiftLock was active
    if shiftLockMode then
        toggleShiftLock()
    end
end

-- Function: Monitor Tracked Target for Removal or Death
local function monitorTrackedTarget(targetCharacter)
    if not targetCharacter then return end

    local humanoid = targetCharacter:FindFirstChildOfClass("Humanoid")
    if humanoid then
        humanoid.Died:Connect(function()
            debugLog("Tracked target " .. (targetCharacter.Name or "Unknown") .. " has died.")
            onTrackedTargetRemoved()
        end)
    end

    targetCharacter.AncestryChanged:Connect(function()
        if not targetCharacter:IsDescendantOf(game) then
            debugLog("Tracked target " .. (targetCharacter.Name or "Unknown") .. " has left the game.")
            onTrackedTargetRemoved()
        end
    end)
end

-- Modify toggleLockOn to monitor the tracked target
local originalToggleLockOn = toggleLockOn
toggleLockOn = function()
    originalToggleLockOn()
    if trackedTarget then
        monitorTrackedTarget(trackedTarget)
    end
end

-- Function: Handle Character Respawn
player.CharacterAdded:Connect(function(newCharacter)
    debugLog("Character respawned.")
    character = newCharacter
    humanoid = character:WaitForChild("Humanoid")
    humanoidRootPart = character:WaitForChild("HumanoidRootPart")
    
    -- Determine rig type using RigType property
    isR15 = humanoid.RigType == Enum.HumanoidRigType.R15
    torsoPartName = isR15 and "UpperTorso" or "Torso"
    debugLog("New rig type determined: " .. (isR15 and "R15" or "R6"))
    
    -- Reset tracking and ESP on respawn
    onTrackedTargetRemoved()
end)

-- Function: Update Camera during ShiftLock Mode
local function updateCamera(deltaTime)
    if shiftLockMode and trackedTarget then
        local targetTorso = trackedTarget:FindFirstChild(torsoPartName)
        if targetTorso then
            -- Smoothly move the camera to follow the target
            local desiredCFrame = CFrame.new(humanoidRootPart.Position, targetTorso.Position)
            CurrentCamera.CFrame = CurrentCamera.CFrame:lerp(desiredCFrame, ROTATION_SPEED * deltaTime)
            debugLog("Camera updated to follow target in ShiftLock mode.")
        end
    end
end

-- Setup ShiftLock and Lock-On Toggles
local function setupShiftLockToggle()
    UserInputService.InputBegan:Connect(function(input, gameProcessed)
        if gameProcessed then return end

        if input.KeyCode == LOCK_ON_KEY then
            toggleLockOn()
        elseif input.KeyCode == SHIFT_LOCK_TOGGLE_KEY then
            toggleShiftLock()
        end
    end)
end

-- Event Listeners

-- Setup ShiftLock and Lock-On Toggles
setupShiftLockToggle()

-- Render Step: Continuously update rotation and camera if a target is tracked
RunService.RenderStepped:Connect(function(deltaTime)
    if lockOnMode and trackedTarget then
        pcall(function()
            rotateToTarget(deltaTime)
            updateCamera(deltaTime)
        end)
    end

    -- Close Proximity Check Removed
    -- The handleCloseProximity function and related checks have been removed as per the latest request.
end)
```

Reference Script (REFERENCE ONLY):

```
-- LocalScript: Player Tracking and ESP Tool
-- Place this script in StarterPlayer > StarterPlayerScripts

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

-- Configuration Table
local CONFIG = {
    ROTATION = {
        Kp = 15,                 -- Proportional gain
        Ki = 5,                  -- Integral gain
        Kd = 3,                  -- Derivative gain
        MaxTorque = 50,          -- Maximum rotational force
        MinThreshold = 0.01      -- Minimum angle threshold to apply torque
    },
    ESP = {
        Text = "Targeted",
        Color = Color3.fromRGB(255, 0, 0),
        Size = UDim2.new(0, 100, 0, 50),
        Offset = Vector3.new(0, 2, 0)
    },
    TRACKING = {
        PredictionFactor = 0.3,  -- Seconds ahead to predict
        MaxDistance = 100,       -- Maximum distance to track a target
        RefreshInterval = 1      -- Seconds between target searches
    },
    DEBUG = {
        Enabled = true,
        Verbose = true
    }
}

-- Variables
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
local playerGui = player:WaitForChild("PlayerGui")

local trackedTarget = nil
local espIndicator = nil

-- PID Controller State
local pidState = {
    integral = 0,
    previousError = 0
}

-- External table to store Kalman data for each target
local kalmanData = {}

-- Debug Functions
local function debugLog(message, level)
    level = level or "INFO"
    if CONFIG.DEBUG.Enabled then
        if CONFIG.DEBUG.Verbose or level ~= "DEBUG" then
            print(string.format("[TrackerDebug][%s]: %s", level, message))
        end
    end
end

-- Helper Functions
local function hasHumanoid(model)
    return model and model:FindFirstChildOfClass("Humanoid") ~= nil
end

local function squaredDistance(pos1, pos2)
    local diff = pos1 - pos2
    return diff.X * diff.X + diff.Y * diff.Y + diff.Z * diff.Z
end

-- Advanced Prediction Function: Basic Kalman Filter Implementation
local function predictPosition(target)
    local hrp = target:FindFirstChild("HumanoidRootPart")
    local humanoid = target:FindFirstChildOfClass("Humanoid")
    
    if not hrp or not humanoid then
        debugLog("Target missing HumanoidRootPart or Humanoid.", "ERROR")
        return nil
    end

    -- Initialize Kalman data for the target if not already present
    if not kalmanData[target] then
        kalmanData[target] = {
            Position = hrp.Position,
            Velocity = Vector3.new(0, 0, 0),
            LastUpdate = tick()
        }
    end

    local data = kalmanData[target]
    local currentTick = tick()
    local timeElapsed = currentTick - data.LastUpdate

    if timeElapsed >= 1/60 then -- Update at ~60Hz
        local newVelocity = (hrp.Position - data.Position) / timeElapsed
        data.Velocity = newVelocity
        data.Position = hrp.Position
        data.LastUpdate = currentTick
    end

    -- Predict future position
    local predictedPos = hrp.Position + (data.Velocity * CONFIG.TRACKING.PredictionFactor)
    debugLog(string.format("Predicted Position for %s: %s", target.Parent.Name, tostring(predictedPos)), "DEBUG")
    return predictedPos
end

-- Target Finding Function with Refresh Interval
local function findClosestPlayer()
    local closestPlayer = nil
    local shortestDistanceSq = CONFIG.TRACKING.MaxDistance * CONFIG.TRACKING.MaxDistance

    for _, otherPlayer in ipairs(Players:GetPlayers()) do
        if otherPlayer ~= player and otherPlayer.Character and hasHumanoid(otherPlayer.Character) then
            local otherHRP = otherPlayer.Character:FindFirstChild("HumanoidRootPart")
            if otherHRP then
                local distanceSq = squaredDistance(otherHRP.Position, humanoidRootPart.Position)
                if distanceSq < shortestDistanceSq then
                    shortestDistanceSq = distanceSq
                    closestPlayer = otherPlayer
                end
            end
        end
    end

    if closestPlayer then
        debugLog("Closest player found: " .. closestPlayer.Name, "INFO")
    else
        debugLog("No players within tracking range.", "INFO")
    end

    return closestPlayer
end

-- ESP Management Functions
local function createESP(target)
    if not target or not target:FindFirstChild("Head") then
        debugLog("Cannot create ESP: Target does not have a Head.", "ERROR")
        return nil
    end

    -- Create BillboardGui
    local billboard = Instance.new("BillboardGui")
    billboard.Adornee = target.Head
    billboard.Size = CONFIG.ESP.Size
    billboard.StudsOffset = CONFIG.ESP.Offset
    billboard.AlwaysOnTop = true
    billboard.Name = "TargetESP"

    -- Create TextLabel
    local textLabel = Instance.new("TextLabel")
    textLabel.Parent = billboard
    textLabel.Size = UDim2.new(1, 0, 1, 0)
    textLabel.BackgroundTransparency = 1
    textLabel.Text = CONFIG.ESP.Text
    textLabel.TextColor3 = CONFIG.ESP.Color
    textLabel.Font = Enum.Font.SourceSansBold
    textLabel.TextScaled = true
    textLabel.TextStrokeTransparency = 0.8

    -- Parent to PlayerGui
    billboard.Parent = playerGui
    debugLog("ESP Indicator created for " .. target.Parent.Name, "DEBUG")

    return billboard
end

local function removeESP()
    if espIndicator then
        espIndicator:Destroy()
        espIndicator = nil
        debugLog("ESP Indicator removed.", "DEBUG")
    end
end

-- PID Controller Function
local function pidController(targetCFrame, deltaTime)
    -- Desired look vector
    local desiredLook = (targetCFrame.Position - humanoidRootPart.Position).Unit
    local currentLook = humanoidRootPart.CFrame.LookVector.Unit

    -- Calculate the angle between current and desired directions
    local dotProduct = math.clamp(currentLook:Dot(desiredLook), -1, 1) -- Ensure within acos range
    local angle = math.acos(dotProduct)

    -- Calculate the rotation direction
    local cross = currentLook:Cross(desiredLook)
    local rotationDirection = (cross.Y >= 0) and 1 or -1 -- Assuming Y-axis is up

    -- Error terms
    local error = angle
    pidState.integral = pidState.integral + error * deltaTime
    local derivative = (error - pidState.previousError) / deltaTime

    -- PID Output
    local output = (CONFIG.ROTATION.Kp * error) + (CONFIG.ROTATION.Ki * pidState.integral) + (CONFIG.ROTATION.Kd * derivative)
    output = math.clamp(output, 0, CONFIG.ROTATION.MaxTorque)

    -- Apply rotation if error is significant
    if error > CONFIG.ROTATION.MinThreshold then
        humanoidRootPart.CFrame = humanoidRootPart.CFrame * CFrame.Angles(0, rotationDirection * math.rad(output), 0)
        debugLog(string.format("Applying PID Output: %f", output), "DEBUG")
    end

    -- Update previous error
    pidState.previousError = error
end

-- Rotation and ESP Update Function
local function updateTracking(deltaTime)
    if not trackedTarget or not trackedTarget.Parent or not trackedTarget:FindFirstChild("HumanoidRootPart") then
        debugLog("Tracked target is invalid. Removing tracking.", "WARN")
        trackedTarget = nil
        removeESP()
        return
    end

    -- Predict target position
    local predictedPos = predictPosition(trackedTarget)
    if not predictedPos then
        debugLog("Failed to predict target position. Removing tracking.", "ERROR")
        trackedTarget = nil
        removeESP()
        return
    end

    -- Rotate towards predicted position using PID controller
    local targetCFrame = CFrame.new(humanoidRootPart.Position, predictedPos)
    pidController(targetCFrame, deltaTime)

    -- Update ESP
    if espIndicator and trackedTarget:FindFirstChild("Head") then
        espIndicator.Adornee = trackedTarget.Head
    else
        debugLog("Target lost Head. Removing ESP.", "WARN")
        removeESP()
        trackedTarget = nil
    end
end

-- Target Selection Toggle Function
local function toggleLockOn()
    if trackedTarget then
        -- Deselect current target
        debugLog("Deselecting target: " .. trackedTarget.Parent.Name, "INFO")
        trackedTarget = nil
        removeESP()
    else
        -- Find and select the closest target
        local closestPlayer = findClosestPlayer()
        if closestPlayer and closestPlayer.Character then
            trackedTarget = closestPlayer.Character
            espIndicator = createESP(trackedTarget)
            debugLog("Tracking target: " .. trackedTarget.Parent.Name, "INFO")
        else
            debugLog("No valid target found to track.", "INFO")
        end
    end
end

-- Event Connections
local inputConnection
local characterAddedConnection
local heartbeatConnection

-- Function to handle player removal
local function onPlayerRemoving(player)
    if player.Character and kalmanData[player.Character] then
        kalmanData[player.Character] = nil
        debugLog("Kalman data cleaned up for " .. player.Name, "DEBUG")
    end
end

-- Function to handle character removal
local function onCharacterRemoving(character)
    if kalmanData[character] then
        kalmanData[character] = nil
        debugLog("Kalman data cleaned up for character.", "DEBUG")
    end
end

-- Initialize Function
local function initialize()
    -- External table for kalman data is already initialized above

    -- Input Listener for E key
    inputConnection = UserInputService.InputBegan:Connect(function(input, gameProcessed)
        if gameProcessed then return end
        if input.KeyCode == Enum.KeyCode.E then
            toggleLockOn()
        end
    end)
    debugLog("Input connection established for toggleLockOn.", "DEBUG")

    -- Character Respawn Listener
    characterAddedConnection = player.CharacterAdded:Connect(function(newCharacter)
        character = newCharacter
        humanoidRootPart = character:WaitForChild("HumanoidRootPart")
        pidState = { integral = 0, previousError = 0 }
        trackedTarget = nil
        removeESP()
        debugLog("Character respawned. Resetting tracking.", "INFO")
    end)

    -- Heartbeat Listener for Smooth Updates
    heartbeatConnection = RunService.Heartbeat:Connect(function(deltaTime)
        if trackedTarget then
            updateTracking(deltaTime)
        end
    end)
    debugLog("Heartbeat connection established for tracking updates.", "DEBUG")

    -- Connect to PlayerRemoving
    Players.PlayerRemoving:Connect(onPlayerRemoving)

    -- Connect to existing players' character removal
    for _, p in ipairs(Players:GetPlayers()) do
        if p.Character then
            p.Character.AncestryChanged:Connect(function(_, parent)
                if not parent then
                    onCharacterRemoving(p.Character)
                end
            end)
        end
    end

    -- Connect to future players' character removal
    Players.PlayerAdded:Connect(function(p)
        p.CharacterAdded:Connect(function(c)
            c.AncestryChanged:Connect(function(_, parent)
                if not parent then
                    onCharacterRemoving(c)
                end
            end)
        end)
    end)
end

-- Cleanup Function
local function cleanup()
    if inputConnection then
        inputConnection:Disconnect()
        debugLog("Input connection disconnected.", "DEBUG")
    end
    if characterAddedConnection then
        characterAddedConnection:Disconnect()
        debugLog("CharacterAdded connection disconnected.", "DEBUG")
    end
    if heartbeatConnection then
        heartbeatConnection:Disconnect()
        debugLog("Heartbeat connection disconnected.", "DEBUG")
    end
    removeESP()
    -- Clear all Kalman data
    for k in pairs(kalmanData) do
        kalmanData[k] = nil
    end
    debugLog("Cleanup complete. All connections disconnected and resources freed.", "INFO")
end

-- Monitor Ancestry Changes for Cleanup
script.AncestryChanged:Connect(function(_, parent)
    if not parent then
        -- Script is being removed
        cleanup()
    end
end)

-- Initialize Script
initialize()
debugLog("Tracking script initialized successfully.", "INFO")