the first idea i had was to make a stationary point/attachment infront of the head and the gui would be updated constantly in a loop to that position. i know its a wacky solution but im not good with reading math head bob and yes i did took it from someone
-- CONSTANTS -- -- Camera position offset from HumanoidRootPart: local OFFSET = Vector3.new(0, 3, 0) local RAY_DISTANCE = 100 -- Mouse sensitivity multiplier local SENSITIVITY = 0.006 -- Verticle angle limits (how far you can look up and down): local UPPER_ANGLE_LIMIT = math.rad(85) local LOWER_ANGLE_LIMIT = math.rad(-85) -- How many bobs per second horizontally and vertically: local BOB_FREQUENCY_Y = 4 local BOB_FREQUENCY_X = 2 -- How intense the horizontal and vertical bobs are: local BOB_AMPLITUDE_X = 0.6 local BOB_AMPLITUDE_Y = 0.4 -- The maximum velocity that affects the intensity of the bob: local MAX_VELOCITY = 16 -- How fast it takes for bobbing to start/stop when you start/stop moving: local RECENTER_SPEED = 4 -- SERVICES -- local RunService = game:GetService("RunService") local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") -- REFERENCES -- local localPlayer = Players.LocalPlayer local character = localPlayer.Character or localPlayer.CharacterAdded:Wait() local currentCamera = workspace.CurrentCamera local rad = math.rad local Rot = CFrame.new() local Tilt = CFrame.new() -- VARIABLES -- local cameraAngle = Vector2.new(0, 0) local currentTime = 0 local velocityMultiplier = 0 local MaxTilt = 85 -- FUNCTIONS -- local function GetRollAngle() local Character = localPlayer.Character if not Character then return end local Cf = currentCamera.CFrame return -Cf.RightVector:Dot(Character.Humanoid.MoveDirection) end local function scalarLerp(a, b, c) c = math.clamp(c, 0, 1) return a + c * (b - a) end function MouseRay(filterTable, filterType, mousePosition) local rayData = currentCamera:ScreenPointToRay(mousePosition.X, mousePosition.Y, 0) local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = filterTable raycastParams.FilterType = filterType return workspace:Raycast(rayData.Origin, rayData.Direction * RAY_DISTANCE, raycastParams) end local function InitOffsetAttachment(Char) local Attachment = Instance.new("Attachment") Attachment.Name = "OFFSET" Attachment.Parent = character:WaitForChild("HumanoidRootPart") Attachment.WorldPosition = character:WaitForChild("Head").Position return Attachment.Position end local function MakeBodyVisible(Char,Match) for _,v in pairs(Char:GetDescendants()) do if v:IsA("BasePart") then v.LocalTransparencyModifier = 1 end end end local function renderStepped(deltaTime) local humanoidRootPart = character:FindFirstChild("HumanoidRootPart") local mouseDelta = UserInputService:GetMouseDelta() * SENSITIVITY local MouseDeltaX = UserInputService:GetMouseDelta().X -- Calculate bob offsets currentTime += deltaTime local bobOffsetY = (math.sin(currentTime * math.pi * BOB_FREQUENCY_Y) - 0.5) * BOB_AMPLITUDE_Y local bobOffsetX = (math.sin(currentTime * math.pi * BOB_FREQUENCY_X) - 0.5) * BOB_AMPLITUDE_X -- Smooth between bobbing and neutral based on horizontal velocity local velocityMagnitude = (humanoidRootPart.Velocity * Vector3.new(1,0,1)).Magnitude local targetVelocityMultiplier = math.clamp(velocityMagnitude, 0, MAX_VELOCITY) / MAX_VELOCITY velocityMultiplier = scalarLerp(velocityMultiplier, targetVelocityMultiplier, RECENTER_SPEED * deltaTime) bobOffsetX *= velocityMultiplier bobOffsetY *= velocityMultiplier -- Update the camera angle, clamp it to angle limits cameraAngle -= mouseDelta cameraAngle = Vector2.new( cameraAngle.X, math.clamp(cameraAngle.Y, LOWER_ANGLE_LIMIT, UPPER_ANGLE_LIMIT) ) -- Set the cframe of the camera local Roll = GetRollAngle() * 4 Rot = Rot:Lerp(CFrame.Angles(0, 0, rad(Roll)),0.075) localPlayer.Character:WaitForChild("Humanoid").AutoRotate = false local RootPos, MousePos = humanoidRootPart.Position, localPlayer:GetMouse().Hit.Position humanoidRootPart.CFrame = CFrame.new(RootPos, Vector3.new(MousePos.X, RootPos.Y, MousePos.Z))-- Temp solution Tilt = Tilt:Lerp(CFrame.Angles(0,0, rad(math.clamp(math.round(MouseDeltaX),-MaxTilt,MaxTilt)),0),0.075) currentCamera.CFrame = CFrame.new(humanoidRootPart.Position+OFFSET) * CFrame.new(0, bobOffsetY, 0) * CFrame.Angles(0, cameraAngle.X, 0) * CFrame.Angles(cameraAngle.Y, 0, 0) * CFrame.new(bobOffsetX, 0, 0) * (Rot * Tilt) end RunService.RenderStepped:Connect(renderStepped) OFFSET = InitOffsetAttachment(character)
and heres my prototype ik its very ugly
local runS = game:GetService("RunService") local Cam = workspace.CurrentCamera local LocalPlayer = game:GetService("Players").LocalPlayer.Character:WaitForChild("Head"):WaitForChild("FaceFrontAttachment") local Frame = game:GetService("Players").LocalPlayer.PlayerGui.ScreenGui.Frame local function SetupAttachment(Char) local A = Instance.new("Attachment") A.Parent = Char:WaitForChild("HumanoidRootPart") A.WorldPosition = Char:WaitForChild("Head").Position + Char:WaitForChild("Head").CFrame.LookVector return A end local Attachment = SetupAttachment(game:GetService("Players").LocalPlayer.Character) runS.Stepped:Connect(function() Frame.Position = UDim2.fromOffset(Cam:WorldToViewportPoint(Attachment.WorldPosition).X,Cam:WorldToViewportPoint(Attachment.WorldPosition).Y) end)