local Bobbing = {} Bobbing.__index = Bobbing Bobbing.LeanMultiplier = 1.5 Bobbing.TurnAlpha = .05 Bobbing.SwayMultiplier = 1.7 type Euler = CFrame type AnimationsMap = {[string]: (tick: number, dt: number) -> Euler} local Animations: AnimationsMap = {} local Storage = game:GetService("ReplicatedStorage") local UIS = game:GetService("UserInputService") local Algebra = require(Storage:WaitForChild("AlgebraEasings")) local CN = CFrame.new local ANG = CFrame.Angles local CameraLean = CN() function Bobbing.constructor(HumanoidRootPart: BasePart, CurrentCamera: Camera, Humanoid: Humanoid) return setmetatable({ HumanoidRootPart = HumanoidRootPart, CurrentCamera = CurrentCamera, Humanoid = Humanoid }, Bobbing) end function Animations.Idle(t, dt) return ANG( math.rad(math.sin(t)/350), math.rad(math.sin(t)/150), math.rad(-math.cos(t)/50) ) end function Animations.Walk(t, dt) return ANG(0,0,0) end function Bobbing:Frame(dt: number) local Root = self.HumanoidRootPart local Camera = self.CurrentCamera local Humanoid = self.Humanoid local CameraCF = Camera.CFrame local Magnitude = Root:GetVelocityAtPosition(Root.Position).Magnitude local CurrentAnimation = Animations[Magnitude>1 and "Walk" or "Idle"](tick(), dt) --Lean the camera based on looking and moving direction(s) local MouseDelta = UIS:GetMouseDelta() local LeanDegree = -CameraCF.RightVector:Dot(Humanoid.MoveDirection)*Bobbing.LeanMultiplier local LeanMult = math.max(-Bobbing.SwayMultiplier, math.min(LeanDegree-MouseDelta.X, Bobbing.SwayMultiplier)) CameraLean = CameraLean:Lerp(ANG(0, 0, math.rad(LeanMult)), Bobbing.TurnAlpha) Camera.CFrame *= CurrentAnimation*CameraLean end return Bobbing