Camera bobbing is jittering

I’m using a Spring Module to create a realistic camera bob when the player jumps. For some reason, the camera jitters whenever the spring has velocity added to it. Here’s the code,

--!strict

-- Services
local UserInputService = game:GetService('UserInputService')
local ReplicatedStorage = game:GetService('ReplicatedStorage')
local RunService = game:GetService('RunService')
local Players = game:GetService('Players')

-- Types
type BobberImp = {
	__index: BobberImp,
	new: (Camera: Camera) -> Bobber,
	StartBobber: (Bobber) -> (),
	Jump: (Bobber) -> (),
	Destroy: (Bobber) -> (),
}

type Bobber = {
	Camera: Camera,
	BobTick: number,
	Connection: RBXScriptConnection?,
	StartBobber: (Bobber: Bobber) -> (),
	Jump: (Bobber) -> (),
	Destroy: (Bobber: Bobber) -> (),
	SpringX: Spring.SpringObject,
	SpringY: Spring.SpringObject,
	SpringZ: Spring.SpringObject,
	LastStep: number,
	OldCamCF: CFrame,
	Character: Model?,
	Humanoid: Humanoid,
}

-- Constants
local Player = Players.LocalPlayer :: Player

local Common = ReplicatedStorage.Common

local Spring = require(Common.Spring)

-- Main

local CameraBobber = {} :: BobberImp
CameraBobber.__index = CameraBobber

function CameraBobber.new(camera: Camera) : Bobber
	local self = setmetatable({}, CameraBobber) :: Bobber

	self.Camera = camera
	
	self.Character = Player.Character
	self.Humanoid = self.Character.Humanoid :: Humanoid

	self.Connection = nil
	
	self.LastStep = tick()
	
	self.OldCamCF = camera.CFrame
	
	self.SpringX = Spring.new(3, 2, 16, 0, 0, 1) :: Spring.SpringObject
	self.SpringY = Spring.new(3, 2, 16, 0, 0, 1) :: Spring.SpringObject
	self.SpringZ = Spring.new(3, 2, 16, 0, 0, 1) :: Spring.SpringObject
	
	self:StartBobber()

	return self
end

function CameraBobber.Jump(self: Bobber)
	self.SpringX:AddVelocity(-12)
	self.SpringZ:AddVelocity(75)
end

function CameraBobber.StartBobber(self: Bobber)
	
	UserInputService.JumpRequest:Connect(function()
		self:Jump()
	end)
	
	self.Connection = RunService.RenderStepped:Connect(function(deltaTime: number)
		
		if self.Humanoid.MoveDirection.Magnitude > 0 then
			if tick() - self.LastStep >= 1 then
				
				self.LastStep = tick()
			end
		end
		
		local offsetX = math.rad(self.SpringX.Offset)
		local offsetY = math.rad(self.SpringY.Offset)
		local offsetZ = math.rad(self.SpringZ.Offset)
		
		local newCamCF = CFrame.Angles(offsetX, offsetY, offsetZ)
		local goalCF = newCamCF:ToObjectSpace(self.OldCamCF)
		self.Camera.CFrame *= goalCF
		self.OldCamCF = newCamCF
	end)
end

function CameraBobber.Destroy(self: Bobber)
	if self.Connection then
		self.Connection:Disconnect()
		self.Connection = nil
	end
end

return CameraBobber

If you have anything to share, please do. Thanks for reading! :happy4:

1 Like

Hey, your camera bob script looks solid, but the jittering might be coming from how the camera’s CFrame is being updated. In the RenderStepped loop, you’re multiplying the camera’s CFrame with goalCF, which is derived from ToObjectSpace. This cna cause compounding transformations, leading to jitters, especially if the spring’s velocity updates are out of sync with the frame rate. Also, self.OldCamCF is being set to newCamCF, which only contains the spring offsets, so it might not properly track the camera’s full orientation. Try resetting self.OldCamCF to the camera’s actual CFrame each frame or simplifying the CFrame math to avoid cumulative errors.
Hope that helps!

Maybe you could cache the unmodified base once at start:

self.BaseCamCF = camera.CFrame

Then in the render step:

local offsetX = math.rad(self.SpringX.Offset)
local offsetY = math.rad(self.SpringY.Offset)
local offsetZ = math.rad(self.SpringZ.Offset)
self.Camera.CFrame = self.BaseCamCF * CFrame.Angles(offsetX, offsetY, offsetZ)

This may avoid jitter by not accumulating small floating-point errors.

Sorry if I’m wrong but, is this AI?

I ended up changing the settings when initializing the springs in this section,

	self.SpringX = Spring.new(3, 2, 16, 0, 0, 1) :: Spring.SpringObject
	self.SpringY = Spring.new(3, 2, 16, 0, 0, 1) :: Spring.SpringObject
	self.SpringZ = Spring.new(3, 2, 16, 0, 0, 1) :: Spring.SpringObject

I ended up just changing the settings and the jitter seems to at least be less noticeable.

2 Likes

I just tried to help. what AI are you talking about :broken_heart:

1 Like

Sorry if you weren’t using AI but it just looks AI generated. Whenever I use ChatGPT for small bugs the AI writes similar to you.

1 Like

I’ll take that as a compliment lol

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.