Custom VR Movement is Laggy

I’m trying to write my own VR movement and such for my own game, but I’m having an issue where when moving the joystick back and forth, the player model kinda sticks and moves very slowly forwards and backwards. However, moving left and right works perfectly.

Video (sorry about the weird graphical bugs, OBS is acting funny): Watch 2025-08-08 19-48-42 | Streamable

I couldn’t find much online, and I was hesitant about asking ChatGPT but even it was useless (maybe for the best, too). There’s a good chance that the player model itself is the problem as well, but given my limited knowledge on scripting and the fact I haven’t done it in so long, a bug seems very well likely.

VRService = game:GetService("VRService")
RunService = game:GetService("RunService")
UserInputService = game:GetService("UserInputService")
ContextActionService = game:GetService("ContextActionService")

Player = game.Players.LocalPlayer
Character = Player.Character or Player.CharacterAdded:Wait()
Root = Character:WaitForChild("HumanoidRootPart")
Humanoid = Character:WaitForChild("Humanoid")
Camera = workspace.CurrentCamera

LeftHand = Character:WaitForChild("LeftHand")
RightHand = Character:WaitForChild("RightHand")

MoveSpeed = 10
TurnSpeed = math.rad(90)
CameraYaw = 0
CanJump = true

local function blockInput(_, inputState, _)
	return Enum.ContextActionResult.Sink
end

ContextActionService:BindAction("BlockLeftClick", blockInput, false, Enum.KeyCode.ButtonL3)
ContextActionService:BindAction("BlockRightClick", function(actionName, inputState, inputObject)
	if inputState == Enum.UserInputState.Begin then
		local rightX, rightY = 0, 0
		local gamepadState = UserInputService:GetGamepadState(Enum.UserInputType.Gamepad1)
		for _, input in ipairs(gamepadState) do
			if input.KeyCode == Enum.KeyCode.Thumbstick2 then
				rightX, rightY = input.Position.X, input.Position.Y
			end
		end

		local humanoidState = Humanoid:GetState()
		local groundedStates = {
			Enum.HumanoidStateType.Running,
			Enum.HumanoidStateType.Landed,
			Enum.HumanoidStateType.RunningNoPhysics
		}

		local IsGrounded = false
		for _, state in ipairs(groundedStates) do
			if humanoidState == state then
				IsGrounded = true
				break
			end
		end

		if rightY > 0.8 and CanJump and IsGrounded then
			CanJump = false
			Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
		end
	end
	if inputState == Enum.UserInputState.End then
		CanJump = true
	end
	return Enum.ContextActionResult.Sink
end, false, Enum.KeyCode.ButtonR3)

ContextActionService:BindAction("BlockThumbstick2Move", blockInput, false, Enum.KeyCode.Thumbstick2)

RunService.RenderStepped:Connect(function(dt)
	local gamepadState = UserInputService:GetGamepadState(Enum.UserInputType.Gamepad1)
	local rightX, rightY = 0, 0
	local leftX, leftY = 0, 0

	for _, input in ipairs(gamepadState) do
		if input.KeyCode == Enum.KeyCode.Thumbstick1 then
			leftX, leftY = input.Position.X, input.Position.Y
		elseif input.KeyCode == Enum.KeyCode.Thumbstick2 then
			rightX, rightY = input.Position.X, input.Position.Y
		end
	end

	if math.abs(leftX) > 0.1 or math.abs(leftY) > 0.1 then
		local forward = Vector3.new(math.sin(CameraYaw), 0, math.cos(CameraYaw))
		local right = Vector3.new(math.cos(CameraYaw), 0, -math.sin(CameraYaw))
		local moveDir = (forward * leftY) + (right * leftX)

		if moveDir.Magnitude > 0 then
			moveDir = moveDir.Unit
			Root.CFrame = Root.CFrame + moveDir * MoveSpeed * dt
		end
	end

	if math.abs(rightX) > 0.1 then
		CameraYaw = CameraYaw - rightX * TurnSpeed * dt
	end

	local camPos = Root.Position + Vector3.new(0,5,0)
	Camera.CFrame = CFrame.new(camPos) * CFrame.Angles(0, CameraYaw, 0)

	local LHTrack = VRService:GetUserCFrame(Enum.UserCFrame.LeftHand)
	local RHTrack = VRService:GetUserCFrame(Enum.UserCFrame.RightHand)
	LeftHand.CFrame = Camera.CFrame * LHTrack
	RightHand.CFrame = Camera.CFrame * RHTrack
end)