Help regarding a smooth orientation alignment system

Hello, I am attempting to create a smoother “Orientation Alignment” behavior.

I whipped up this custom class for a NPC system I’m working on that allows me to have characters (and other things, really. This is a wide catch-all type thing.)

This is my Watching Method for my Alignment class. It gets the job done but I’m positive there are many better (and more effective ways) of doing this.

function AlignmentH:SetWatching(Target : BasePart | Vector3 | CFrame | nil)
	if self.Watching == Target then return false end
	self.Watching = Target

	-- Cleanup existing watcher thread
	if self.WatchThread then 
		self.WatchThread:Disconnect()
		self.WatchThread = nil
	end

	-- If Target is nil, remove AlignOrientation & invisible part
	if Target == nil then
		for _, v in {AOName, APName} do
			if self[v] then
				self[v]:Destroy()
				self[v] = nil
			end
		end
		return true
	end

	-- Ensure we have an AlignOrientation and an attachment part
	if not self[AOName] then 
		self[AOName] = self.Janitor:AddToCleanup(Instance.new("AlignOrientation", self.Rig.PrimaryPart))
		self[AOName].RigidityEnabled = true
		self[AOName].Name = AOName
		self[AOName].Attachment0 = self.Rig.PrimaryPart.RootAttachment

		self[APName] = self.Janitor:AddToCleanup(General.CreatePart({
			Name = APName,
			Size = Vector3.new(0,0,0),
			CanCollide = false,
			CanTouch = false,
			CanQuery = false,
			Transparency = 1,
			Anchored = true,
			Parent = self.Rig.PrimaryPart,
		}))
		self[AOName].Attachment1 = self[APName].Attachment
	end

	-- Handle different target types
	self.WatchThread = self.Janitor:AddToCleanup(RunS[if RunS:IsClient() then "RenderStepped" else "Heartbeat"]:Connect(function()
		local targetPosition

		if typeof(Target) == "Instance" and Target:IsA("BasePart") then
			targetPosition = Target.Position
		elseif typeof(Target) == "Vector3" then
			targetPosition = Target
		elseif typeof(Target) == "CFrame" then
			targetPosition = Target.Position
		else
			return
		end

		-- Ensure NPC looks at the target position while keeping the same Y height
		local newOrientation = CFrame.new(self.Rig.PrimaryPart.Position, Vector3.new(targetPosition.X, self.Rig.PrimaryPart.Position.Y, targetPosition.Z))
		self[APName].CFrame = newOrientation
	end))

	return true
end

I’m well aware Roblox’s physics objects (and just Roblox’s physics in general) run at 60 FPS, which is very noticeable on higher powered hardware. However, I haven’t found a smoother way to update the orientation of a character rig without it being completely stuck in the air without utilizing these instances.