Framework Module with a lot of memory usage

Hey, I am making a framework involving movement and viewmodels. I finished the movement part of it but viewmodel is unfinished. No errors, just checking if I could have done anything better in this module / local script

Framework

-- Thanks to @SnarlyZoo for the original script (I just added mobile support and changed it into a module)
-- Variables

-- Settings
local HOLD_JUMP_TO_BHOP = false
local DEBOUNCE = false

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")
local RunService = game:GetService('RunService')
local UserInputService = game:GetService("UserInputService")

local LocalPlayer = Players.LocalPlayer

local CharacterConnections: {RBXScriptConnection} = {}
local PlayerConnections: {RBXScriptConnection} = {}

local PlayerVelocity = Vector3.zero

local InputVelocity = Vector3.zero
local Humanoid: Humanoid?

local WishJump = false
local CanJump = true

-- TODO: Movement.
LocalPlayer:SetAttribute("MOVE_SPEED",24)
LocalPlayer:SetAttribute("RUN_ACCELERATION",3.2)
LocalPlayer:SetAttribute("RUN_DEACCELERATION",0.2)
LocalPlayer:SetAttribute("AIR_ACCELERATION",6)
LocalPlayer:SetAttribute("AIR_DEACCELERATION",2)
LocalPlayer:SetAttribute("SIDE_STRAFE_ACCELERATION",100)
LocalPlayer:SetAttribute("SIDE_STRAFE_SPEED",1)
LocalPlayer:SetAttribute("AIR_FRICTION",1)
LocalPlayer:SetAttribute("MAX_SPEED",46)
LocalPlayer:SetAttribute("JUMP_BUFFER",0.4)
LocalPlayer:SetAttribute("FRICTION",3)

local MOVE_SPEED = LocalPlayer:GetAttribute("MOVE_SPEED")
local RUN_ACCELERATION = LocalPlayer:GetAttribute("RUN_ACCELERATION")
local RUN_DEACCELERATION = LocalPlayer:GetAttribute("RUN_DEACCELERATION")
local AIR_ACCELERATION = LocalPlayer:GetAttribute("AIR_ACCELERATION")
local AIR_DEACCELERATION = LocalPlayer:GetAttribute("AIR_DEACCELERATION")
local SIDE_STRAFE_ACCELERATION = LocalPlayer:GetAttribute("SIDE_STRAFE_ACCELERATION")
local SIDE_STRAFE_SPEED = LocalPlayer:GetAttribute("SIDE_STRAFE_SPEED")
local FRICTION = LocalPlayer:GetAttribute("FRICTION")
local AIR_FRICTION = LocalPlayer:GetAttribute("AIR_FRICTION")
local MAX_SPEED = LocalPlayer:GetAttribute("MAX_SPEED")
local JUMP_BUFFER = LocalPlayer:GetAttribute("JUMP_BUFFER")


-- MODULES
local Modules = ReplicatedStorage.Modules
local ExtraModules = Modules.Extra
local ExtraFunctions = require(ExtraModules.ExtraFunctions)

local PlayerScripts = ExtraFunctions:WaitForChildWhichIsA(LocalPlayer, "PlayerScripts") :: PlayerScripts
local PlayerModule = require(PlayerScripts:WaitForChild("PlayerModule")) :: any

local Controls = PlayerModule:GetControls()

local Framework = {}
local FH = { __index = Framework }


-- Functions
local function bobbing(addition, speed, modifier)
	return math.sin(tick() * addition * speed) * modifier
end

local function ThumbstickCurve(X: number): number
	local K_CURVATURE = 2.0
	local K_DEADZONE = 0.15

	local function FCurve(X: number): number
		return (math.exp(K_CURVATURE * X) - 1) / (math.exp(K_CURVATURE) - 1)
	end

	local function FDeadzone(X: number): number
		return FCurve((X - K_DEADZONE) / (1 - K_DEADZONE))
	end

	return math.sign(X) * math.clamp(FDeadzone(math.abs(X)), 0, 1)
end

local function OnCharacterAdded(Character: Model)
	local NewHumanoid = ExtraFunctions:WaitForChildWhichIsA(Character, "Humanoid", 5) :: Humanoid
	if NewHumanoid then
		table.insert(CharacterConnections, NewHumanoid:GetPropertyChangedSignal("Jump"):Connect(function()
			if not CanJump then
				NewHumanoid.Jump = false
			end
		end))
		Humanoid = NewHumanoid
	end
end

local function OnCharacterRemoving(_: Model)
	Humanoid = nil
	if #(CharacterConnections) > 0 then
		for _, Connection in ipairs(CharacterConnections) do
			if Connection.Connected then
				Connection:Disconnect()
			end
		end
		table.clear(CharacterConnections)
	end
end


local function QueueJump()
	if Humanoid then
		local IsJumping = if (Controls.activeController and Controls.activeController.enabled and Controls.humanoid) 
			then (if (Controls.activeController:GetIsJumping() or (Controls.touchJumpController and Controls.touchJumpController:GetIsJumping())) 
				then true 
				else false) 
			else false
		if not Humanoid:GetStateEnabled(Enum.HumanoidStateType.Jumping) and IsJumping then
			IsJumping = false
		end

		local IsMobile = UserInputService.TouchEnabled

		if HOLD_JUMP_TO_BHOP then
			WishJump = IsJumping
		else
			if IsJumping and not WishJump then
				WishJump = true
				if Controls.activeController then
					Controls.activeController.isJumping = false
				elseif Controls.touchJumpController then
					Controls.touchJumpController.isJumping = false
				end
			end
			if not IsJumping then
				WishJump = false
			end
		end
	end
end

local function ApplyFriction(Time: number, InAir: boolean)
	local Vector = Vector3.new(PlayerVelocity.X, 0, PlayerVelocity.Z)
	local Speed = Vector.Magnitude
	local Control = if Speed < RUN_DEACCELERATION then RUN_DEACCELERATION else Speed
	local NewFriction = if InAir then AIR_FRICTION else FRICTION
	local Drop = Control * NewFriction * RunService.Heartbeat:Wait() * Time
	local NewSpeed = Speed - Drop

	if NewSpeed < 0 then
		NewSpeed = 0
	end

	if Speed > 0 then
		NewSpeed /= Speed
	end

	local X = PlayerVelocity.X * NewSpeed
	local Z = PlayerVelocity.Z * NewSpeed
	PlayerVelocity = Vector3.new(X, 0, Z)
end

local function Accelerate(WishDirection: Vector3, WishSpeed: number, Acceleration: number)
	local Currentspeed = PlayerVelocity:Dot(WishDirection)
	local AddSpeed = WishSpeed - Currentspeed
	if AddSpeed > 0 then 
		local AccelerationSpeed = Acceleration * RunService.Heartbeat:Wait() * WishSpeed
		if AccelerationSpeed > AddSpeed then
			AccelerationSpeed = AddSpeed 
		end

		local X = PlayerVelocity.X + AccelerationSpeed * WishDirection.X
		local Z = PlayerVelocity.Z + AccelerationSpeed * WishDirection.Z
		PlayerVelocity = Vector3.new(X, 0, Z)
	end
end

local function GroundMove(RelativeToCamera: boolean)
	if not WishJump and CanJump then
		ApplyFriction(1, false)
	else
		ApplyFriction(0, false)
	end

	local CoordinateFrame = if workspace.CurrentCamera 
		then workspace.CurrentCamera.CFrame
		else CFrame.new()

	local WishDirection = CoordinateFrame:VectorToWorldSpace(InputVelocity)
	WishDirection = if RelativeToCamera 
		then Vector3.new(WishDirection.X, 0, WishDirection.Z)
		else InputVelocity

	if WishDirection ~= Vector3.zero then
		WishDirection = WishDirection.Unit
	end

	local WishSpeed = WishDirection.Magnitude
	WishSpeed *= MOVE_SPEED

	Accelerate(
		WishDirection, 
		WishSpeed, 
		RUN_ACCELERATION
	)

	PlayerVelocity = Vector3.new(
		PlayerVelocity.X, 
		0, 
		PlayerVelocity.Z
	)

	if Humanoid and WishJump and CanJump then
		Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
		WishJump = false
		CanJump = false

		task.spawn(function()
			local Begin = tick()
			while tick() - Begin < JUMP_BUFFER do
				RunService.Heartbeat:Wait()
			end
			CanJump = true
		end)
	end
end

local function AirMove(RelativeToCamera: boolean)
	if InputVelocity.Z ~= 0 then
		ApplyFriction(1, true)
	end

	local CoordinateFrame = if workspace.CurrentCamera 
		then workspace.CurrentCamera.CFrame
		else CFrame.new()

	local WishDirection = CoordinateFrame:VectorToWorldSpace(InputVelocity)
	WishDirection = if RelativeToCamera 
		then Vector3.new(WishDirection.X, 0, WishDirection.Z)
		else InputVelocity

	local WishSpeed = WishDirection.Magnitude
	WishSpeed *= MOVE_SPEED

	if WishDirection ~= Vector3.zero then
		WishDirection = WishDirection.Unit
	end

	local Acceleration: number = if PlayerVelocity:Dot(WishDirection) < 0 
		then AIR_DEACCELERATION
		else AIR_ACCELERATION

	if InputVelocity.Z == 0 and InputVelocity.X ~= 0 then
		if WishSpeed > SIDE_STRAFE_SPEED then
			WishSpeed = SIDE_STRAFE_SPEED
		end
		Acceleration = SIDE_STRAFE_ACCELERATION
	end

	Accelerate(WishDirection, WishSpeed, Acceleration)
end

--local Directions = {
--	[Vector3.new(0, 0, 0)] = "Not Moving";
--	[Vector3.new(0, 0, -1)] = "Foward";
--	[Vector3.new(0, 0, 1)] = "Backward";
--	[Vector3.new(-1, 0, 0)] = "Left";
--	[Vector3.new(1, 0, 0)] = "Right";
--	[Vector3.new(-1, 0, -1)] = "FowardLeft";
--	[Vector3.new(1, 0, -1)] = "FowardRight";
--	[Vector3.new(-1, 0, 1)] = "BackwardLeft";
--	[Vector3.new(1, 0, 1)] = "BackwardRight";
--}


if LocalPlayer.Character then
	task.spawn(OnCharacterAdded, LocalPlayer.Character)
end
table.insert(PlayerConnections, LocalPlayer.CharacterAdded:Connect(OnCharacterAdded))
table.insert(PlayerConnections, LocalPlayer.CharacterRemoving:Connect(OnCharacterRemoving))

-- Framework
function Framework.new()
	local self = {}

	self.LoadingAnimations = {}
	self.LerpValues = {}

	self.LerpValues.Equip = Instance.new("NumberValue")
	self.LerpValues.Equip.Value = 1

	self.SwayCFrame = CFrame.new()
	self.SwayAmount = -0.4

	self.LastCameraCFrame = CFrame.new()
	return setmetatable(self, FH)
end

function Framework:Equip()
	if LocalPlayer and LocalPlayer.Character then
		self.Viewmodel = ReplicatedStorage.Viewmodel:Clone() -- viewmodel
		self.Camera = workspace.CurrentCamera
		self.Character = Players.LocalPlayer.Character

		self.Viewmodel["Left Arm"].Color = self.Character.Head.Color -- change left arm color
		self.Viewmodel["Right Arm"].Color = self.Character.Head.Color -- change right arm color

		self.Viewmodel.Parent = workspace.Camera

		self.Settings = require(self.Viewmodel.Settings) -- settings gathered

		self.LoadingAnimations.Walk = self.Viewmodel.AnimationController:LoadAnimation(
			self.Settings.Animations.Viewmodel.Walk
		)

		local EquipTween = TweenInfo.new(0.5, Enum.EasingStyle.Quart, Enum.EasingDirection.Out) -- tween equip
		TweenService:Create(self.LerpValues.Equip, EquipTween, { Value = 0 }):Play()
		
		self.Equipped = true
	end
end

function Framework:PlayerRemoving(Player: Player)
	if Player == LocalPlayer then
		LocalPlayer = nil

		if #(PlayerConnections) > 0 then
			for _, Connection in ipairs(PlayerConnections) do
				if Connection.Connected then
					Connection:Disconnect()
				end
			end
			table.clear(PlayerConnections)
		end
		if Player.Character then
			OnCharacterRemoving(Player.Character)
		end
	end
end

function Framework:PlayerMoved(Player: Player, WalkDirection: Vector3, RelativeToCamera: boolean)
	RelativeToCamera = if Controls.activeController
		then Controls.activeController:IsMoveVectorCameraRelative()
		else RelativeToCamera

	if Player == LocalPlayer then
		local MoveVector = Controls:GetMoveVector()
		MoveVector = Vector3.new(
			ThumbstickCurve(MoveVector.X),
			ThumbstickCurve(MoveVector.Y),
			ThumbstickCurve(MoveVector.Z)
		)

		if MoveVector ~= InputVelocity then
			InputVelocity = MoveVector
		end

		if Humanoid then
			QueueJump()
			local Grounded = Humanoid.FloorMaterial ~= Enum.Material.Air or Humanoid:GetState() == Enum.HumanoidStateType.Climbing
			if Grounded then
				GroundMove(RelativeToCamera)
			else
				AirMove(RelativeToCamera)
			end


			local NewDirection = Vector3.zero
			if PlayerVelocity ~= Vector3.zero then 
				NewDirection = PlayerVelocity.Unit 
			end


			local NewSpeed = PlayerVelocity.Magnitude
			NewSpeed = math.clamp(NewSpeed, 0, MAX_SPEED)

			if Humanoid and math.ceil(InputVelocity.Z) ~= 1 then
				Humanoid.WalkSpeed = NewSpeed
				Humanoid:Move(NewDirection, false)
			elseif Humanoid and math.ceil(InputVelocity.Z) == 1 then
				Humanoid.WalkSpeed = NewSpeed / 2
				Humanoid:Move(NewDirection, false)
			end
		end
	end
end

function Framework:Update(DT)
	if self.Viewmodel then
		local rotation = self.Camera.CFrame:ToObjectSpace(self.LastCameraCFrame)
		local x,y,z = rotation:ToOrientation()
		self.SwayCFrame = self.SwayCFrame:Lerp(CFrame.Angles(math.sin(x) * self.SwayAmount, math.sin(y) * self.SwayAmount,0),0.1)

		self.LastCameraCFrame = self.Camera.CFrame

		if self.Character:FindFirstChild("Humanoid") then
			local Humanoid = self.Character.Humanoid
			--local MoveVector = Controls:GetMoveVector()

			--MoveVector = Vector3.new(
			--	ThumbstickCurve(MoveVector.X),
			--	ThumbstickCurve(MoveVector.Y),
			--	ThumbstickCurve(MoveVector.Z)
			--)

			--print(MoveVector)

			local Speed = Humanoid.WalkSpeed
			self.Viewmodel:SetPrimaryPartCFrame(self.Camera.CFrame * self.SwayCFrame)
			--TODO: Animations depending on your speed.
			if Speed >= 8 and Speed <= 15 then -- walking
				if not self.LoadingAnimations.Walk.IsPlaying then
					self.LoadingAnimations.Walk:AdjustWeight(10,5)
					self.LoadingAnimations.Walk:Play()
				end
			end

			if Speed >= 16 then	-- sprinting
				if self.LoadingAnimations.Walk.IsPlaying then
					self.LoadingAnimations.Walk:Stop()
				end
			end

			if Speed < 3 then -- stopped moving
				if self.LoadingAnimations.Walk.IsPlaying then
					self.LoadingAnimations.Walk:Stop()
				end
			end
			
			-- TODO: add walk cycle to viewmodel
		end
	end
end

return Framework

Framework_Client

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local Modules = ReplicatedStorage.Modules
local Framework = require(Modules.Framework)
local ExtraFunctions = require(Modules.Extra.ExtraFunctions)

local LocalPlayer = Players.LocalPlayer
if not LocalPlayer then
	Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
	LocalPlayer = Players.LocalPlayer
end


local PlayerScripts = ExtraFunctions:WaitForChildWhichIsA(LocalPlayer, "PlayerScripts") :: PlayerScripts
local PlayerModule = require(PlayerScripts:WaitForChild("PlayerModule")) :: any

local Controls = PlayerModule:GetControls()

LocalPlayer.CharacterAdded:Wait()
repeat wait() until LocalPlayer.Character

local Viewmodel = Framework.new()

Viewmodel:Equip()

local function Update(DeltaTime)
	Viewmodel:Update(DeltaTime)
end

RunService.RenderStepped:Connect(Update)
Players.PlayerRemoving:Connect(Framework.PlayerRemoving)
Controls.moveFunction = Framework.PlayerMoved