How would I go about optimizing a 2D drawing system?

I made my own drawing system for fun and I want to use this for a slightly bigger project since I really enjoy this, but I’m afraid it will cause lag.

This sketch I drew using this demo I threw together uses 2149 frames in total, a lot more than I was hoping it would use.
My only idea/solution is to find a way to detect straight lines, but since drawing systems have existed on Roblox for a while I wanted to ask for help.

“new canvas” module code:

	local canvas = Instance.new('ImageButton')
	canvas.Size = UDim2.fromOffset(w,h)
	canvas.BackgroundColor3=Color3.new(1,1,1)
	canvas.AutoButtonColor=false
	local down = false
	canvas.MouseButton1Down:Connect(function()down = true;end)
	canvas.MouseButton1Up:Connect(function()down = false;end)
	canvas.BorderSizePixel = 0
	local commands = {}
	--[[
			-->> drawing system
	]]
	local history,redo = {},{}-- make stacks
	local historysnapshotitems = {}
	-- stack functions
	local function snapshot(items)
		history[#history+1] = items

		for _,t in pairs(redo) do for i,v in pairs(t) do
				v:Destroy()
			end end
		redo = {}

		-- Limit undo size
		while #history > 50 do
			table.remove(history,1)
		end
	end
	--
	local dragging = false
	local lp:Vector2 --last position
	-- dragging toggle
	canvas.InputBegan:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
			historysnapshotitems = {}
			lp = Vector2.new(input.Position.X,input.Position.Y) - canvas.AbsolutePosition
			dragging = true end end)
	canvas.InputEnded:Connect(function(input)
		if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
			dragging = false
			snapshot(historysnapshotitems)
		end end)
	-- drawing function
	local linethickness,color  =  3,Color3.new()
	commands.LineThickness = linethickness
	commands.Color = color
	local gap = math.ceil(linethickness/2)
	local function draw(input)
		local position = Vector2.new(input.Position.X,input.Position.Y) - canvas.AbsolutePosition
		local point = Instance.new("Frame")
		historysnapshotitems[#historysnapshotitems+1] = point
		point.BackgroundColor3=color;point.BorderSizePixel=0
		point.AnchorPoint = Vector2.new(.5,.5)
		point.Size = UDim2.fromOffset(
			math.sqrt(math.pow(position.X-lp.X, 2) + math.pow(position.Y-lp.Y, 2)) + gap
			,
			linethickness
		)
		local c = Vector2.new((position.X + lp.X)/2, (position.Y + lp.Y)/2)	
		point.Position = UDim2.fromOffset(c.X,c.Y)
		point.Rotation = math.deg(math.atan2(position.Y - lp.Y, position.X - lp.X))
		--point.Name = ' '
		point.Parent = canvas
		lp = position
	end
	canvas.InputChanged:Connect(function(input)
		if dragging then
			draw(input)
		end
	end)

	--[[
			<<--
	]]

	function commands.Clear()
		for i,v in pairs(history:GetChildren()) do
			v:Destroy()
		end
		for i,v in pairs(redo:GetChildren()) do
			v:Destroy()
		end
		history,redo = {},{}
	end

	function commands.Undo()
		if #history > 0 then
			for i,v in pairs(history[#history]) do
				v.Parent = nil
			end
			redo[#redo + 1] = history[#history]
			history[#history] = nil
		end
	end

	function commands:Redo()
		if #redo > 0 then
			local redoindex = redo[#redo]
			for i,v in pairs(redoindex) do
				v.Parent = canvas
			end

			history[#history + 1] = redoindex
			redo[#redo] = nil
		end
	end

	function commands.ChangeLineThickness(n:number)
		if not n then return end
		linethickness  =  n
		gap = math.ceil(linethickness/2)
		commands.LineThickness = n
	end
	function commands.ChangeColor(c:Color3)
		if not c then return end
		color  =  c
		commands.Color = c
	end
	return canvas,commands
end
return newcanvas

How I used this in the demo:

w,h,color=600,600,Color3.new()
local uis = game:GetService('UserInputService')
local nc = require(script["new canvas"])
local holder = script.Parent

local canvas,cmds = nc(w,h);holder.Size = UDim2.fromOffset(w,h);canvas.Parent = holder
cmds.ChangeColor(color)
uis.InputBegan:Connect(function(input)
	if not uis:IsKeyDown(Enum.KeyCode.LeftControl) then return end
	if input.KeyCode == Enum.KeyCode.Z then
		cmds.Undo()
	elseif input.KeyCode == Enum.KeyCode.Y then
		cmds.Redo()
	end
end)