Need help with this specific scenario

so, I am working on a sort of custom physics, that allow for different methods of movement, using attributes to change what it is (e.g the crouch attribute when activated at any point will make the player crouch) I am using Run service to achieve this, but this means that I cannot play the appropriate animations when I want to, what should I do?

Instance:GetAttributeChangedSignal() exactly does your job.

local function CrouchPlayer(plr, isCrouching) -- An example function.
	print(plr)
	print(isCrouching)
end

game.Players.PlayerAdded:Connect(function(plr)

	plr:SetAttribute("Crouching", false) -- Creates an attribute if doesn't exists, then sets it to false.

	plr:GetAttributeChangedSignal("Crouching"):Connect(function() -- Function to execute when the attribute changes.
		-- Do whatever you want here, the following is an example.
		CrouchPlayer(plr, plr:GetAttribute("Crouching"))
	end)

	task.spawn(function()
		while true do
			task.wait(1)
			plr:SetAttribute("Crouching", not plr:GetAttribute("Crouching")) -- Sets the attribute to the opposite every second for testing purposes.
		end
	end)

end)

plr:SetAttribute("Crouching", false):

Docs: