Voxel Destruction System is laggy?

Hi everyone, recently I’ve been trying to make a Voxel Destruction System. Atm it works so that when you click on a part, a Hitbox spawns at the Hit’s CFrame and destroys the part it hit, but it’s really laggy.

Here’s the code: (completely client sided for testing purposes and a little unorganized :frowning: )

local pars = OverlapParams.new() 
pars.FilterType = Enum.RaycastFilterType.Include

local children = {}
for _, Part in workspace.VoxelsFolder:GetDescendants() do
	table.insert(children, Part)
end
pars.FilterDescendantsInstances = children

local MAX_SIZE = 5
local HALF_THRESHOLD = 1.5
local DESTROY_THRESHOLD = 1

local function IsSmaller(Part: Part)
	if (Part.Size.X < (MAX_SIZE * DESTROY_THRESHOLD)) and (Part.Size.Y < (MAX_SIZE * DESTROY_THRESHOLD)) and (Part.Size.Z < (MAX_SIZE * DESTROY_THRESHOLD)) then
		return true
	end
	return false
end

local function Destroy(Part: Part)
	if IsSmaller(Part) == true then
		Part:Destroy()
	end
end

function GetCorner(part: Part)	
	local cf = part.CFrame
	local size = part.Size

	local corner

	local frontFaceCenter = (cf + cf.LookVector * size.Z/2)
	local bottomFrontEdgeCenter = frontFaceCenter - frontFaceCenter.UpVector * size.Y/2
	corner = (bottomFrontEdgeCenter - bottomFrontEdgeCenter.RightVector * size.X/2)

	return corner 
end

local function ToHalf(Part: Part)
	local SizeX = Part.Size.X
	local SizeY = Part.Size.Y
	local SizeZ = Part.Size.Z
	local n = 2

	local BiggestSide = math.max(SizeX, SizeY, SizeZ)
	local Corner = GetCorner(Part)

	if BiggestSide == SizeX then
		for i = 1, n, 1 do
			local PosX = SizeX / (2 * n) + (SizeX / n) * (i - 1)
			local PosY = SizeY / 2
			local PosZ = SizeZ / 2
			local Position = Vector3.new(PosX, PosY, PosZ)

			local NewPart = Part:Clone()
			NewPart.Name = "Voxel"
			NewPart.Parent = Part.Parent
			NewPart.Size = Vector3.new(SizeX / n, SizeY, SizeZ)
			NewPart.CFrame = Corner * CFrame.new(Position)
			NewPart.Orientation = Part.Orientation
			--NewPart.Color = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
			table.insert(children, NewPart)
			pars.FilterDescendantsInstances = children
		end
	elseif BiggestSide == SizeY then
		for i = 1, n, 1 do
			local PosX = SizeX / 2
			local PosY = SizeY / (2 * n) + (SizeY / n) * (i - 1)
			local PosZ = SizeZ / 2
			local Position = Vector3.new(PosX, PosY, PosZ)

			local NewPart = Part:Clone()
			NewPart.Name = "Voxel"
			NewPart.Parent = Part.Parent
			NewPart.Size = Vector3.new(SizeX, SizeY / n, SizeZ)
			NewPart.CFrame = Corner * CFrame.new(Position)
			NewPart.Orientation = Part.Orientation
			--NewPart.Color = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
			table.insert(children, NewPart)
			pars.FilterDescendantsInstances = children
		end
	elseif BiggestSide == SizeZ then
		for i = 1, n, 1 do
			local PosX = SizeX / 2
			local PosY = SizeY / 2
			local PosZ = SizeZ / (2 * n) + (SizeZ / n) * (i - 1)
			local Position = Vector3.new(PosX, PosY, PosZ)

			local NewPart = Part:Clone()
			NewPart.Name = "Voxel"
			NewPart.Parent = Part.Parent
			NewPart.Size = Vector3.new(SizeX, SizeY, SizeZ / n)
			NewPart.CFrame = Corner * CFrame.new(Position)
			NewPart.Orientation = Part.Orientation
			--NewPart.Color = Color3.fromRGB(math.random(0,255),math.random(0,255),math.random(0,255))
			table.insert(children, NewPart)
			pars.FilterDescendantsInstances = children
		end
	end
	Part:Destroy()
end

local function Voxelize(Part: Part, Hitbox: Part)
	ToHalf(Part)
	
	local TouchingParts = workspace:GetPartsInPart(Hitbox, pars)
	if #TouchingParts > 0 then
		for _, Part in TouchingParts do
			if IsSmaller(Part) then
				Destroy(Part)
				continue
			end
			Voxelize(Part, Hitbox)
		end
	end
end

local RunService = game:GetService("RunService")
local plr = game.Players.LocalPlayer
local char = plr.Character or plr.CharacterAdded:Wait()
local rootPart = char:WaitForChild("HumanoidRootPart")
local Mouse = plr:GetMouse()

local function CreateHitbox(cf: CFrame)
	local Hitbox = Instance.new("Part")
	Hitbox.Parent = workspace
	Hitbox.Shape = Enum.PartType.Ball
	Hitbox.Transparency = 0.7
	Hitbox.Size = Vector3.new(15,15,15)
	Hitbox.CanCollide = false
	Hitbox.Anchored = true
	Hitbox.Material = Enum.Material.SmoothPlastic
	Hitbox.CFrame = cf
	return Hitbox
end

Mouse.Button1Down:Connect(function()
	local Target = Mouse.Target
	if Target then
		local TargetCFrame = Mouse.Hit
		local Hitbox = CreateHitbox(TargetCFrame)
		local TouchingParts = workspace:GetPartsInPart(Hitbox, pars)
		if #TouchingParts > 0 then
			for _, Part in TouchingParts do
				if IsSmaller(Part) then
					Destroy(Part)
					continue
				end
				Voxelize(Part, Hitbox)
			end
		end
		Hitbox:Destroy()
	end
end)

Basically, when you click on a part, it gets subdivided in half based on the longest side, and it gets recursively subdivided again until it reaches MAX_SIZE and gets destroyed. I’ve also tried Octree Partitioning, but it gave me the same result as this “Half Partitioning”. Am I doing something wrong?
Any help is highly appreciated, thanks!

Ok I found a fix for this much lag, basically I removed the OverlapParams and every table.insert function, that was lagging the game a lot. But still, would there be any optimization or more efficient way of doing this? I still notice some lag spikes with medium range voxelizations.