When tool is activated, the player gets visually deleted, the lighting changes, and the client freezes for a little bit

I am making a grappling tool. Everything works fine but I want to make it move towards the target gradually instead of it teleporting to make it look smooth. But whenever I try adding either a second part thats the visual rope or a align position, this weird bug happens where the client physics basically freeze. The character gets deleted, and the lighting changes.

When I tween just the one slinger part the player doesnt move on the server.

Grapple Module:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local CollectionService = game:GetService("CollectionService")
local TweenService = game:GetService("TweenService")

local player = Players.LocalPlayer
local mouse = player:GetMouse()
local camera = workspace.CurrentCamera

local matchRotation = true
local currentTilt = 0
local currentRotation = 0
local oldMouseHit = Vector3.zero

local module = {}

local grappleTemplate = ReplicatedStorage:WaitForChild("GrapplePart")

local placeCount = 0

local grappleTween = nil
local grapple = nil

local function roundToGrid(n, gridSize)
	gridSize = gridSize or 1
	return math.floor(n / gridSize + 0.5) * gridSize
end

local function getPlacementCFrame()
	local origin = camera.CFrame.Position
	local direction = (mouse.Hit.Position - origin).Unit * 1000
	oldMouseHit = mouse.Hit.Position

	local rayParams = RaycastParams.new()
	rayParams.FilterDescendantsInstances = {player.Character}
	rayParams.FilterType = Enum.RaycastFilterType.Exclude

	local result = workspace:Raycast(origin, direction, rayParams)
	if not result then return nil end

	local hitPos = result.Position
	local normal = result.Normal
	local target = result.Instance

	if CollectionService:HasTag(target.Parent, "IgnorePlacement") then
		return nil
	end

	local size = grappleTemplate.Size
	local up = normal.Unit
	local targetLook = target.CFrame.LookVector
	local targetRight = target.CFrame.RightVector

	local forward = (targetLook - up * targetLook:Dot(up))
	if forward.Magnitude < 0.001 then
		forward = (targetRight - up * targetRight:Dot(up))
	end
	forward = forward.Unit

	local right = forward:Cross(up).Unit
	local baseCFrame = CFrame.fromMatrix(Vector3.zero, right, up)
	local rotationCFrame = CFrame.Angles(currentTilt, currentRotation, 0)
	local partOrientationCFrame = matchRotation and (baseCFrame * rotationCFrame) or rotationCFrame

	local function getOffset(size, normal, cframe)
		local halfSize = size / 2
		local axisX = cframe.RightVector * halfSize.X
		local axisY = cframe.UpVector * halfSize.Y
		local axisZ = cframe.LookVector * halfSize.Z
		return math.abs(normal:Dot(axisX)) + math.abs(normal:Dot(axisY)) + math.abs(normal:Dot(axisZ))
	end

	local offset = getOffset(size, normal, partOrientationCFrame)
	local exactPos = hitPos + normal * offset
	local targetCFrame = target.CFrame
	local localPos = targetCFrame:PointToObjectSpace(exactPos)
	local localNormal = targetCFrame:VectorToObjectSpace(normal)

	local snapX = math.abs(localNormal.X) < 0.9 and roundToGrid(localPos.X) or localPos.X
	local snapY = math.abs(localNormal.Y) < 0.9 and roundToGrid(localPos.Y) or localPos.Y
	local snapZ = math.abs(localNormal.Z) < 0.9 and roundToGrid(localPos.Z) or localPos.Z
	local snappedLocalPos = Vector3.new(snapX, snapY, snapZ)
	local snappedWorldPos = targetCFrame:PointToWorldSpace(snappedLocalPos)

	local finalBaseCFrame = CFrame.fromMatrix(snappedWorldPos, right, up)
	return finalBaseCFrame * rotationCFrame
end

function DeleteSlinger()
	if grapple then
		grapple:Destroy()
		grapple = nil
	end
	if grappleTween then
		grappleTween:Cancel()
		grappleTween = nil
	end
end

function module:RegisterToolInput(tool, grappleAttachment)
	assert(tool and tool:IsA("Tool"), "Expected a Tool instance")

	local char = player.Character or player.CharacterAdded:Wait()
	local root = char:WaitForChild("HumanoidRootPart")
	local rootAttach = root:WaitForChild("RootAttachment")

	local handle = tool:WaitForChild("Handle")

	local function playSound(sound)
		if not sound then return end
		local soundClone = sound:Clone()
		soundClone.Parent = handle
		soundClone:Play()
		soundClone.Ended:Connect(function()
			soundClone:Destroy()
		end)
	end

	local equipSound = handle:FindFirstChild("Connect")
	local fireSound = handle:FindFirstChild("Fire")
	local hitSound = handle:FindFirstChild("Hit")
	
	if not equipSound or not fireSound or not hitSound then return end

	player.CharacterAdded:Connect(function(character)
		DeleteSlinger()
	end)

	tool.Unequipped:Connect(function()
		DeleteSlinger()
	end)

	tool.Equipped:Connect(function()
		playSound(equipSound)
	end)

	tool.Activated:Connect(function()
		local placementCFrame = getPlacementCFrame()
		if not placementCFrame then return end

		DeleteSlinger()

		grapple = grappleTemplate:Clone()
		grapple.Name = "Slinger"
		grapple.CFrame = grappleAttachment.WorldCFrame
		grapple.AlignPosition.Position = getPlacementCFrame().Position
		grapple.Parent = workspace
		if grappleAttachment then
			grapple.RopeConstraint.Attachment0 = grappleAttachment
		else
			grapple.RopeConstraint.Attachment0 = rootAttach
		end

		placeCount += 1
		local currentCount = placeCount

		if grappleTween then
			grappleTween:Cancel()
			grappleTween = nil
		end
		
		playSound(fireSound)
	end)
end

return module

I never came across this issue before and it seems really weird why this would even happen.