Currently this code follows a spline. The problem is that the speed is weird and based off the length of the track for some reason. Some values are broken. What I want you to do is fix everything to make a perfect roller coaster physics simulation in roblox here is the code. Code:local coasterFolder = workspace:WaitForChild("Coaster")
local trackParts = {}
local twistData = {}
local gravity = 9.8 -- Gravity acceleration
local cartMass = 10 -- Mass of the cart
local friction = 1 -- Friction coefficient
local arcLengthStep = 0.01 -- Fine step for arc length calculation
local stepSize = 0.05 -- For track visualization
local dt = 0.01 -- Time step

local trackPartTemplate = Instance.new("Part")
trackPartTemplate.Size = Vector3.new(1, 1, 1)
trackPartTemplate.Anchored = true
trackPartTemplate.CanCollide = false
trackPartTemplate.Material = Enum.Material.SmoothPlastic
trackPartTemplate.BrickColor = BrickColor.new("Dark stone grey")

-- Function to load parts from the folder and sort them by IntValue
function loadTrackParts()
	local unsortedParts = {}

	for _, part in pairs(coasterFolder:GetChildren()) do
		if part:IsA("Part") then
			local orderValue = part:FindFirstChild("Value")
			if orderValue and orderValue:IsA("IntValue") then
				table.insert(unsortedParts, {part = part, order = orderValue.Value})
			end
		end
	end

	-- Sort parts based on the IntValue
	table.sort(unsortedParts, function(a, b)
		return a.order < b.order
	end)

	-- Populate trackParts and twistData
	for _, entry in ipairs(unsortedParts) do
		local part = entry.part
		table.insert(trackParts, part.Position)
		local twist = {
			pitch = part.Orientation.X,
			yaw = part.Orientation.Y,
			roll = part.Orientation.Z
		}
		table.insert(twistData, twist)
	end
end

-- Catmull-Rom Spline Interpolation
function catmullRomSpline(p0, p1, p2, p3, t)
	local t2 = t * t
	local t3 = t2 * t
	return 0.5 * ((2 * p1) +
		(-p0 + p2) * t +
		(2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 +
		(-p0 + 3 * p1 - 3 * p2 + p3) * t3)
end

-- Function to get a point along the spline between two control points
function getSplinePoint(t, i)
	local p0 = trackParts[i - 1] or trackParts[i]
	local p1 = trackParts[i]
	local p2 = trackParts[i + 1]
	local p3 = trackParts[i + 2] or trackParts[i + 1]
	return catmullRomSpline(p0, p1, p2, p3, t)
end

-- Function to calculate the arc length of a spline segment for uniform movement
function calculateArcLength(i, step)
	local totalLength = 0
	local lastPos = getSplinePoint(0, i)

	for t = step, 1, step do
		local currentPos = getSplinePoint(t, i)
		totalLength = totalLength + (currentPos - lastPos).Magnitude
		lastPos = currentPos
	end

	return totalLength
end

-- Function to calculate the cart's velocity based on the slope of the track
function calculatePhysicsVelocity(currentPos, nextPos, currentVelocity, dt)
	local displacement = nextPos - currentPos
	local slope = displacement.Y / displacement.Magnitude -- slope = rise/run
	local acceleration = gravity * slope * dt -- Accelerate downward, decelerate upward
	local newVelocity = currentVelocity + acceleration

	-- Prevent the cart from going backward (too slow)
	if newVelocity < 0 then
		newVelocity = 0
	end

	-- Apply friction to simulate real-world slowdown
	newVelocity = newVelocity * friction

	return newVelocity
end

-- Move cart along the spline using physics
function moveCart(cart, initialSpeed)
	local currentSpeed = initialSpeed
	local i = 2 -- Start at the second waypoint
	local t = 0

	while i < #trackParts do
		local totalLength = calculateArcLength(i, arcLengthStep)
		while t <= 1 do
			local currentPos = getSplinePoint(t, i)
			local nextPos = getSplinePoint(t + dt, i)

			-- Move the cart to the current position
			cart.Position = currentPos
			cart.CFrame = CFrame.lookAt(cart.Position, nextPos)

			-- Apply twists (pitch, yaw, roll)
			local twist = twistData[i]
			cart.CFrame = cart.CFrame * CFrame.Angles(math.rad(twist.pitch), math.rad(twist.yaw), math.rad(twist.roll))

			-- Calculate velocity based on physics (slope, gravity, and friction)
			currentSpeed = calculatePhysicsVelocity(currentPos, nextPos, currentSpeed, dt)

			-- Update t for the next frame based on the cart's speed
			t = t + (currentSpeed / totalLength) * dt

			wait(dt)
		end
		t = 0 -- Reset t for the next segment
		i = i + 1 -- Move to the next segment
	end
end

-- Function to generate visual track parts between points
function generateTrackVisualization(stepSize)
	for i = 2, #trackParts - 1 do
		local t = 0
		while t < 1 do
			local splinePoint = getSplinePoint(t, i)
			local nextSplinePoint = getSplinePoint(t + stepSize, i)

			local trackPart = trackPartTemplate:Clone()
			trackPart.Size = Vector3.new(0.5, 0.5, (splinePoint - nextSplinePoint).Magnitude)
			trackPart.CFrame = CFrame.new(splinePoint, nextSplinePoint) * CFrame.new(0, 0, -trackPart.Size.Z / 2)

			local twist = twistData[i]
			trackPart.CFrame = trackPart.CFrame * CFrame.Angles(math.rad(twist.pitch), math.rad(twist.yaw), math.rad(twist.roll))

			trackPart.Parent = workspace
			t = t + stepSize
		end
	end
end

-- Load the track and generate the visual track
loadTrackParts()
generateTrackVisualization(0.05)

-- Move the cart (assuming you have a part named "Cart")
local cart = workspace:WaitForChild("Cart")
moveCart(cart, 10) -- Initial speed set to 0