Spline generator through a sequence of points

Here's a utility that takes a sequence of positions and defines a curve that passes through all of them. You can use this to move things like planes and spaceships along a smooth curve, or a cinematic camera that follows a track.

Source: https://pastebin.com/2JZi2wvH
Source here in case that link dies
	SplinePath v1.0 by Waffle

	This module takes an ordered table of positions and defines a curve that passes through the given list of nodes.
	SplinePath.PointOnPath(nodeList, progress) takes a progress argument between 0 and 1 and returns a position along the curve.
	SplinePath.FollowPath(object, nodeList, duration) moves an object along the path in the given amount of time.

local SplinePath = {}

function SplinePath.PointOnPath(nodeList, progress) -- catmull-rom cubic hermite interpolation
	if progress == 1 then return nodeList[#nodeList] end
	local index1 = math.floor(1 + progress * (#nodeList - 1))
	local index2 = index1 + 1
	local point1 = nodeList[index1]
	local point2 = nodeList[index2]
	local tangent1 = (point2 - nodeList[math.max(1, index1 - 1)]) / 2
	local tangent2 = (nodeList[math.min(#nodeList, index1 + 2)] - point1) / 2
	local alpha = (progress * (#nodeList - 1)) % 1
	local h1 =  2*alpha^3 - 3*alpha^2 + 1
	local h2 = -2*alpha^3 + 3*alpha^2
	local h3 =    alpha^3 - 2*alpha^2 + alpha
	local h4 =    alpha^3 -   alpha^2
	return h1*point1 + h2*point2 + h3*tangent1 + h4*tangent2

function SplinePath.FollowPath(object, nodeList, duration)
	local progress = 0
	local updatePeriod = .1
	while true do
		updatePeriod = Task.Wait()
		if not Object.IsValid(object) then return end
		progress = progress + updatePeriod / duration
		if progress > 1 then break end
		local point = SplinePath.PointOnPath(nodeList, progress)
		object:MoveContinuous((point - object:GetWorldPosition()) / updatePeriod)
		object:RotateTo(Rotation.New(point - object:GetWorldPosition(), Vector3.UP), updatePeriod)
	object:MoveTo(nodeList[#nodeList], updatePeriod)

return SplinePath

Example project file zip

The rotation and acceleration is inferred from the direction of the curve and the distance between two nodes, there's no way to control the roll or acceleration directly without using a different type of spline. This is a pretty flexible simple approach, though. The main benefit here over bezier curves is that it passes through each point rather than only being attracted towards each point, so wherever the points are is where the path goes. The order that the points are traversed in is the child order in the hierarchy.