First Person Arm Stutter!

Hello. I have made custom first person arms using Viewport frames that are updated every heartbeat. All has been fine and dandy, except my arms stutter. Take a look:

As you can see, when moving, the arms have a vigorous stutter back and forth. It is quite annoying and I would love to know any remedies so they move smoother. Here is the code for the arm frame:

local player = game.Players.LocalPlayer
local char = player.Character
local humanoid = char.Humanoid
local runService = game:GetService("RunService")
local parts = {"LeftHand", "LeftLowerArm", "LeftUpperArm", "RightHand", "RightLowerArm", "RightUpperArm"}
local armCamera = workspace.Camera:Clone()
armCamera.CFrame = char.Head.CFrame * CFrame.new(0, 0, 0.7)
armCamera.Name = "ArmCamera"
runService.RenderStepped:Connect(function()
	armCamera.CFrame = armCamera.CFrame:Lerp((char.Head.CFrame * CFrame.new(0, 0.4, 0.7)), 0.5)
	local camera = game.Workspace.Camera
	camera.CameraType = Enum.CameraType.Follow
	local currentTime = tick()
	if camera.CameraType == Enum.CameraType.Follow and humanoid.MoveDirection.Magnitude > 0 and humanoid.WalkSpeed > 0 then
		local swayX = math.cos(currentTime * 10) * 0.3
		local swayY = math.abs(math.sin(currentTime * 10) * 0.3)
		local sway = Vector3.new(swayX, swayY)
		humanoid.CameraOffset = humanoid.CameraOffset:lerp(sway, 0.25)
	elseif camera.CameraType ~= Enum.CameraType.Follow or humanoid.MoveDirection.Magnitude == 0 or humanoid.WalkSpeed == 0 then
		local offsetStandard = Vector3.new(0, 0, 0)
		humanoid.CameraOffset = humanoid.CameraOffset:Lerp(offsetStandard, 0.25)
	end
	for i, v in pairs(player.PlayerGui.GameGui.ArmFrame:GetChildren()) do
		if v:IsA("MeshPart") then
			v:Destroy()
		end
	end
	player.PlayerGui.GameGui.ArmFrame.CurrentCamera = armCamera
	for i, part in pairs(parts) do
		local displayPart = char[part]:Clone()
		displayPart.Material = "SmoothPlastic"
		for i, v in pairs(displayPart:GetChildren()) do
			v:Destroy()
		end
		local weld = Instance.new("WeldConstraint")
		weld.Parent = displayPart
		weld.Part0 = displayPart
		weld.Part1 = char[part]
		displayPart.Parent = player.PlayerGui.GameGui.ArmFrame
		displayPart.CFrame = char[part].CFrame
	end
end)
1 Like

Going to do the forbidden bump because I have no solution yet but have narrowed it down:

The animations are not the cause. I thought it could have been an issue with animations resetting, but alas it is not. Removing all animations keeps it just as bad.

It is worse on studio than it is in the actual game. Perhaps it has something to do with client’s ability to update every frame?

Where is help when you need it.

Found the source: :lerp()

Without lerp, there is not sort of jitter. When I add lerp, it begins jittering.
I’m assuming this is due to how there might be slight deviations in time between frames? How do I account for this?
New code by the way:

local player = game.Players.LocalPlayer
local char = player.Character
local humanoid = char.Humanoid
local runService = game:GetService("RunService")
local bodyParts = {char["LeftHand"], char["LeftLowerArm"], char["LeftUpperArm"], char["RightHand"], char["RightLowerArm"], char["RightUpperArm"]}
local toolParts = {}
local armCamera = workspace.Camera:Clone()
armCamera.CFrame = char.Head.CFrame * CFrame.new(0, 0, 0.7)
armCamera.Name = "ArmCamera"
local camera = game.Workspace.Camera
camera.CameraType = Enum.CameraType.Follow
local parts = {}
local originParts = {}
for i, v in pairs(bodyParts) do
	local part = v:Clone()
	table.insert(parts, part)
	table.insert(originParts, v)
	part.Material = "SmoothPlastic"
	v.Transparency = 1
	part.Parent = player.PlayerGui.GameGui.ArmFrame
	for i, v in pairs(part:GetChildren()) do
		v:Destroy()
	end
end
runService.Heartbeat:Connect(function(deltaTime)
	local ratio = 60 / (1/deltaTime)
	armCamera.CFrame = armCamera.CFrame:Lerp((char.Head.CFrame * CFrame.new(0, 0.4, 0.7)), (0.5))
	local currentTime = tick()
	if camera.CameraType == Enum.CameraType.Follow and humanoid.MoveDirection.Magnitude > 0 and humanoid.WalkSpeed > 0 then
		local swayX = math.cos(currentTime * 10) * 0.5
		local swayY = math.abs(math.sin(currentTime * 10) * 0.5)
		local sway = Vector3.new(swayX, swayY)
		humanoid.CameraOffset = humanoid.CameraOffset:lerp(sway, 0.25)
	elseif camera.CameraType ~= Enum.CameraType.Follow or humanoid.MoveDirection.Magnitude == 0 or humanoid.WalkSpeed == 0 then
		local offsetStandard = Vector3.new(0, 0, 0)
		humanoid.CameraOffset = humanoid.CameraOffset:Lerp(offsetStandard, 0.25)
	end
	player.PlayerGui.GameGui.ArmFrame.CurrentCamera = armCamera
	for i, part in pairs(parts) do
		part.CFrame = originParts[i].CFrame
	end
end)

player.Character:WaitForChild("ToolAdd").Event:Connect(function(tool)
	print(tool.Name)
	table.insert(toolParts, tool.Handle)
	for i, v in pairs(tool.Model:GetChildren()) do
		table.insert(toolParts, v)
	end
	for i, v in pairs(toolParts) do
		local part = v:Clone()
		table.insert(parts, part)
		table.insert(originParts, v)
		v.Transparency = 1
		part.Parent = player.PlayerGui.GameGui.ArmFrame
		for i, v in pairs(part:GetChildren()) do
			v:Destroy()
		end
	end
end)