This for loop starts to get very laggy for no reason?

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve?
    I have a conversation module that I created that used a “typewriter” effect for when the npc is saying its dialogue

  2. What is the issue?
    After a little bit after the first conversation, the typewriting starts to slow down more and more until its basically not moving

  3. What solutions have you tried so far?
    I have tried to find loops or modules being required multiple times to see if something is causing lag based on other developer forum posts but nothing has worked so far

This is the typewrite module

local typetostop = nil

function module:Typewrite(object, text, speed, sound)
	for i = 1, #text, 1 do
		if typetostop ~= object then
		object.Text = string.sub(text, 1, i)
		if sound then
			local newsound = sound:Clone()
			newsound.Parent = script
			newsound:Play()
			Debris:AddItem(newsound, 5)
		end
			wait(speed)
		else
			object.Text = text
			break
		end
	end
	end
	
	function module:EndTypewrite(label)
	typetostop = label
	end

This is the whole conversation module

local module = {}

local tweenmodule = require(game.ReplicatedStorage:WaitForChild("Modules"):WaitForChild("TweenModule"))
local promptmodule = require(game.ReplicatedStorage:WaitForChild("Modules"):WaitForChild("TextPrompt"))
local sounds = script:WaitForChild("Sounds")

local convoended = false

local function endconvo()
	convoended = true
	local plr = game.Players.LocalPlayer

	local ischatting = plr.Character:WaitForChild("Values"):WaitForChild("IsChatting")
	ischatting.Value = false
	
	if not plr.PlayerGui:FindFirstChild("Conversation") then
		script:WaitForChild("Conversation"):Clone().Parent = plr.PlayerGui
	end
	
	local gui = plr.PlayerGui.Conversation.MainFrame
	
	tweenmodule:Tween(gui.Parent.Image, 0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 
		{
			Size = UDim2.new(0,0,0,0)
		}):Play()

	for i, obj in pairs(gui:GetChildren()) do
		if not obj:IsA("UIListLayout") then
			tweenmodule:Tween(obj, 0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 
				{
					Size = UDim2.new(0,0,0,0),
				}):Play()
			coroutine.resume(coroutine.create(function()
				wait(0.15)
				obj:Destroy()
			end))
		end
	end
end

function module:EndConversation()
	endconvo()
end

function module:StartConversation(module, num)	
	convoended = false
	local plr = game.Players.LocalPlayer
	
	if not plr.PlayerGui:FindFirstChild("Conversation") then
	script:WaitForChild("Conversation"):Clone().Parent = plr.PlayerGui
	end
	
	local ischatting = plr.Character:WaitForChild("Values"):WaitForChild("IsChatting")
	
	if ischatting.Value == false then
	local mouse = plr:GetMouse()
	
		local gui = plr.PlayerGui.Conversation.MainFrame
		local image = gui.Parent.Image
		print("hello")
	local loadedmodule = require(module)
	
	local function endit(textframe, buttonframe)
		tweenmodule:Tween(textframe, 0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 
			{
				Size = UDim2.new(0,0,0,0),
			}):Play()
		if buttonframe then
			tweenmodule:Tween(buttonframe, 0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 
				{
					Size = UDim2.new(0,0,0,0),
				}):Play()
			coroutine.resume(coroutine.create(function()
				wait(0.15)
				buttonframe:Destroy()
			end))
			end
				tweenmodule:Tween(image, 0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 
					{
						Size = UDim2.new(0,0,0,0)
					}):Play()
		coroutine.resume(coroutine.create(function()
			wait(0.15)
			textframe:Destroy()
		end))
	end
	
		local function loadtext(num)
			ischatting.Value = true
		local textgoing = true
		
			local tab = loadedmodule[num]
			if tab then
		local textframe = script.TextFrame:Clone()
		local ogsize = textframe.Size
		textframe.Size = UDim2.new(0,0,0,0)
				textframe.Frame.NPCName.Title.Text = module.Parent.Name
		
		local text = textframe.Frame.NPCText
		
		text.Text = ""
		
		textframe.Parent = gui
				
				if tab["Image"] then
					if image.Size ~= UDim2.new(0,0,0,0) and tab.Image.Id ~= image.Image then
						print("test")
						tweenmodule:Tween(image, 0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out, 
							{
								Size = UDim2.new(0,0,0,0)
							}):Play()
					end
					
					image.Image = tab.Image.Id
					tweenmodule:Tween(image, 0.4, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 
						{
							Size = tab.Image.Size
						}):Play()
				end
				
		tweenmodule:Tween(textframe, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 
			{
				Size = ogsize,
					}):Play()	
				
				sounds.Chat:Play()
				
				if module.Parent:IsA("BasePart") or module.Parent:IsA("Model") then
				coroutine.resume(coroutine.create(function()
					while wait(1) do
						local part = module.Parent
						
						if part:IsA("Model") then
							part = part.PrimaryPart
						end
						local magnitude = (plr.Character.HumanoidRootPart.Position - part.Position).magnitude
						if magnitude >= loadedmodule.Distance or textgoing == false then
							if magnitude >= loadedmodule.Distance then
								endconvo()
								promptmodule:AddText(plr, "Chat ended because you walked away", 3, {255, 0, 0}, game.ReplicatedStorage.Assets.Sounds.Error)
								end
							break
						end
					end
				end))
				end
				
				coroutine.resume(coroutine.create(function()
					while wait(0.1) do
						if textframe.Parent == nil then
							textgoing = false
							break
						end
					end
					end))
				
		coroutine.resume(coroutine.create(function()
			wait(0.2)
			
					if tab.RunFunctionAfterText == false then
						if tab["Function"] then
							tab["Function"]()
							end
					end
					
					mouse.Button1Down:Connect(function()
						if textgoing == true then
							tweenmodule:EndTypewrite(text)
						end
					end)
					
			tweenmodule:Typewrite(text, tab.Text, tab.Speed, tab.Sound)
			
					if tab.RunFunctionAfterText == true then
						if tab["Function"] then
							tab["Function"]()
							end
					end
			
					if #tab.Buttons > 0 then
						if convoended == false then
			local buttonframe = script.ButtonFrame:Clone()
			ogsize = buttonframe.Size
			buttonframe.Size = UDim2.new(0,0,0,0)
			
			for i, button in pairs(tab.Buttons) do
				if button then
					local guibutton = script.Button:Clone()
					guibutton.Text = button.Text
						guibutton.Parent = buttonframe
						tweenmodule:Button(guibutton, 8, {sounds.Hover, sounds.Click})
						
						guibutton.MouseButton1Click:Connect(function()
							textgoing = false
							endit(textframe, buttonframe)
							loadtext(button.Goto)
						end)
				end
				end
				
				buttonframe.Parent = gui
				
				tweenmodule:Tween(buttonframe, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 
					{
						Size = ogsize,
								}):Play()	
							end
					else
						mouse.Button1Down:Connect(function()
							if textgoing == true then
									textgoing = false
									sounds.Click:Play()
									endit(textframe)
									loadtext(tab.Goto)
							end
						end)
						
				coroutine.resume(coroutine.create(function()
					local tickframe = textframe.Frame.Tick
					repeat wait(0.3)
						tickframe.Visible = true
						wait(0.3)
						tickframe.Visible = false
					until textgoing == false
				end))
				end
				end))
			else
				print("test")
				ischatting.Value = false
			end
	end
		loadtext(num or 1)
		end
end

return module

Any help appreciated!