Camera Stuttering for Objects Moved with Physics


I have a rather odd issue that I have been trying to solve for the past month. I have talked to many different people about the issue, but no one yet has seemed to provide a solution. I have also searched the DevForum quite a lot trying to see if someone has a similar issue, which they did, but the solutions given to them simply did not work for me.

In my game, I am trying to make an object move via BodyMovers which is controlled by user input. This system works fine, however, I started to notice that the object looked like it was stuttering. After doing more investigation into this, I realized the issue was with the Camera and not the object.

Now if I were to just set the camera to a defined position offset from the object, the stuttering is solved. However, I want my camera to smoothly follow the object, which introduced the stuttering issue. I am using a SmoothDamp function to move the camera, and yes the SmoothDamp function works as it is expected to in other situations (no issue with the function).

[Vector3] SmoothDamp(current: Vector3, target: Vector3, velocity: Vector3, smoothTime: number, maxSpeed: number, deltaTime: number)

For the purposes of this post, I have set up a reproduction place where I move a single Part via BodyVelocity. The network owner of the Part is set to the client and all works as expected minus the horrible stuttering.

Another important thing to note is I am linearly interpolating the values that are fed into the BodyVelocity.

function module.Lerpf(a, b, c)
	return clamp(a + (b - a) * c, min(a,b), max(a,b))

Failed Solutions

These appeared to be the best posts that matched my specific issue, however the solutions given did not solve my issue even though it seemed to solve other’s issues.

My Code

local UserInput = game:GetService("UserInputService")
local RunService = game:GetService("RunService")

local Util = require(script:WaitForChild("Util"))

local Player = game:GetService("Players").LocalPlayer
local RootPart = workspace:WaitForChild("Root")

local Camera = workspace.CurrentCamera


local moveDir = 0
local activeSpeed = 0
local maxSpeed = 20
local speedAcc = 4

local BV = nil
local lastPhysicsDt, lastRenderDt = 0, 0
local lastCFrame = nil

local Controller = {Active = false, CONN_KeyPress = nil, CONN_KeyRelease = nil}

function Controller.Start()
	if Controller.Active then return end
	Controller.Active = true
	Camera.CameraType = Enum.CameraType.Scriptable
	Camera.CameraSubject = RootPart
	Camera.Focus = RootPart.CFrame
	BV = RootPart:WaitForChild("BodyVelocity")
	Controller.CONN_KeyPress = UserInput.InputBegan:Connect(function(input, gpe)
		if gpe then return end
		if input.UserInputType == Enum.UserInputType.Keyboard then
			if input.KeyCode == Enum.KeyCode.A then
				moveDir -= 1
			elseif input.KeyCode == Enum.KeyCode.D then
				moveDir += 1
	Controller.CONN_KeyRelease = UserInput.InputEnded:Connect(function(input, gpe)
		if gpe then return end
		if input.UserInputType == Enum.UserInputType.Keyboard then

			if input.KeyCode == Enum.KeyCode.A then
				moveDir += 1
			elseif input.KeyCode == Enum.KeyCode.D then
				moveDir -= 1

	Controller.CONN_Stepped = RunService.Stepped:Connect(function(_, deltaTime)
		lastPhysicsDt = deltaTime
	RunService:BindToRenderStep("Control", Enum.RenderPriority.Camera.Value + 3, Controller.Update)

function Controller.Stop()
	if not Controller.Active then return end
	Controller.CONN_KeyPress = nil
	Controller.CONN_KeyRelease = nil
	Controller.Active = false

function Controller.Update(deltaTime)
	local sumDelta = lastRenderDt + lastPhysicsDt
	activeSpeed = Util.Lerpf(activeSpeed, moveDir * maxSpeed, speedAcc * lastPhysicsDt)
	BV.Velocity =, 0, activeSpeed)
	if not lastCFrame or not (lastCFrame == RootPart.CFrame) then
		local target = (RootPart.CFrame *, 0, 0)).Position
		local pos = Util.SmoothDamp(Camera.CFrame.Position, target,, 0.04, math.huge, sumDelta)
		Camera.CFrame = * CFrame.Angles(0, -math.pi / 2, 0)
		lastCFrame = RootPart.CFrame
		lastRenderDt = 0
		lastRenderDt = deltaTime

return Controller


Reproduction File

StutterIssue.rbxl (29.6 KB)

Camera.CFrame =*deltaTime) * CFrame.Angles(0, -math.pi / 2, 0)

That completely broke it, as shown in the video: