decided to take it into my own hands so we can finally end this thread… lol
the code was actually sound, it seems like lua had some comparison error for really small decimals. not sure what it was, but for some reason it said that length != points[#points].Distance
… even though that’s exactly what we set it to!
so, instead I made it so that if the target didn’t find a matching point, it uses the final point by default. here’s the product. now the final point is included.

local ROOTS = {
Vector3.new(10, 10, 0),
Vector3.new(10, 40, 0),
Vector3.new(40, 10, 0),
Vector3.new(40, 40, 0)
}
for _, position in pairs(ROOTS) do
local part = Instance.new("Part")
part.BrickColor = BrickColor.new("Bright blue")
part.Size = Vector3.new(0.5, 0.5, 0.5)
part.Position = position
part.Anchored = true
part.Transparency = 0.5
part.Parent = workspace
end
-- PLOTTING --
function bezier3(n, p0, p1, p2, p3)
local d = 1 / n
local function lerp(p0, p1, t)
return (1 - t) * p0 + t * p1
end
local function quadratic(p0, p1, p2, t)
local L1 = lerp(p0, p1, t)
local L2 = lerp(p1, p2, t)
return lerp(L1, L2, t)
end
local function cubic(p0, p1, p2, p3, t)
local Q1 = quadratic(p0, p1, p2, t)
local Q2 = quadratic(p1, p2, p3, t)
return lerp(Q1, Q2, t)
end
local points = {}
points[1] = {
["Position"] = p0, -- starting point
["Distance"] = 0
}
for t = d, 1 + d, d do
local position = cubic(p0, p1, p2, p3, t) -- get unweighted position
local previous = points[#points]
local gap = (position - previous.Position).Magnitude
local distance = previous.Distance + gap
-- store the vector3 as position, total distance as distance
-- and distance from the previous point as gap
points[#points+1] = {
["Position"] = position,
["Distance"] = distance,
["Gap"] = gap
}
end
-- total curve length
local length = points[#points].Distance
local bezier = {}
for t = d, 1 + d, d do
local target = length * t
-- find the first point that is >= target and the one before it
-- that means the target length is in between these two points
local p0, p1
for i, point in pairs(points) do
if point.Distance >= target then
p0 = points[i-1]
p1 = point
break
else
-- use the final point if target didn't match
p0 = points[#points-1]
p1 = points[#points]
end
end
bezier[#bezier+1] = lerp(
p0.Position,
p1.Position,
(target - p0.Distance) / p1.Gap
)
end
return bezier
end
for _, position in pairs(bezier3(20, table.unpack(ROOTS))) do
local part = Instance.new("Part")
part.BrickColor = BrickColor.new("Bright red")
part.Size = Vector3.new(0.4, 0.4, 0.4)
part.Position = position
part.Anchored = true
part.Parent = workspace
end
by the way, I’m not sure why you said points[1]
broke your script. worked okay with me.