Problem with rotation with CFrame.lookAt()

I’ve been trying to make a rocket ship animation using CFrame math but I’m having issues with the way it rotates at the beginning of the launch. It works by calculating its position every frame and then having it face towards where it was on the previous frame. Unfortunately it makes these sharp 90 degree turns at the beginning. Is there a different CFrame constructor I could use to prevent this?

You could either try providing an up argument to CFrame.lookAt, or manually calculating the rotation matrix yourself via CFrame.fromMatrix. Could you share what your script looks like now?

It’s a pretty big script, but this is the main function that deals with the positioning.

local frameConnection = RunService.Heartbeat:Connect(function(deltaTime: number) 
			local deltaA = deltaTime / FLY_TIME
			currentA = math.min(currentA + deltaA, 1)
			local easedA = TweenService:GetValue(currentA, EASING_STYLE, EASING_DIRECTION)

			local currentPivot = getCurrentPivot()
			local newPos = bezier(positions, easedA)
			
			local previousPos = currentPivot.Position
			local finalPivot = CFrame.new(newPos, previousPos)
			
			if currentA < ROTATE_THRESHOLD then -- follow the look vector

				rocketModel:PivotTo(finalPivot)
				
			else -- easing into landing position
				local currentRotation = currentPivot.Rotation
				local finalRotation = endPos.Rotation
				rotateSpeed += ROTATE_ACCELERATION
				local newRotation = currentRotation:Lerp(finalRotation, rotateSpeed * deltaTime)
				
				rocketModel:PivotTo(CFrame.new(newPos) * newRotation)
			end
		end)

Try using codes like this:

local lastLookVector = nil

local frameConnection = RunService.Heartbeat:Connect(function(deltaTime)
	local deltaA = deltaTime / FLY_TIME
	currentA = math.min(currentA + deltaA, 1)
	local easedA = TweenService:GetValue(currentA, EASING_STYLE, EASING_DIRECTION)
	local newPos = bezier(positions, easedA)
	if currentA < ROTATE_THRESHOLD then
		if lastLookVector then
			local newLook = (newPos - lastPosition).Unit
			local smoothedLook = lastLookVector:Lerp(newLook, 0.25)
			local pivot = CFrame.new(newPos, newPos + smoothedLook)
			lastLookVector = smoothedLook
			rocketModel:PivotTo(pivot)
		else
			lastLookVector = Vector3.new(0, 0, -1)
		end
	else
		local currentRotation = rocketModel:GetPivot().Rotation
		local finalRotation = endPos.Rotation
		rotateSpeed += ROTATE_ACCELERATION
		local newRotation = currentRotation:Lerp(finalRotation, rotateSpeed * deltaTime)

		rocketModel:PivotTo(CFrame.new(newPos) * newRotation)
	end
	lastPosition = newPos
end)