Severaly lacking common library primitives/functionality (math, Vector3, NxM Matrix, etc...)

As a Roblox developer, it is currently too hard to …
Perform semi-complex math / operations using built-in library functions.

If Roblox is able to address this issue, it would improve my development experience because …
Not having to implement boiler-plate libraries for commonly needed functionality.

I believe the addition of these functions will have great productivity and performance impacts:

To math:

math.e = 2.7182818284590452353602874713526624977572470936999595749669676277
math.maxint = 2^53-1
math.mindecimal = math.ldexp(1, -1022) -- 1073 on x86
math.lerp(a, b, alpha) = a + (b - a) * alpha
math.map(x, aMin, aMax, bMin, bMax) = bMin + (x - aMin) * (bMax - bMin) / (aMax - aMin)
math.log2(x) = make use of FYL2X instruction on x86
math.isinf(x) = x == math.huge or x == -math.huge
math.isnan(x) = x ~= x
math.isfinite(x) = x ~= math.huge and x ~= -math.huge and x == x
math.isint(x) = x ~= math.huge and x ~= -math.huge and x == x and x == math.floor(x)

-- Normalize a value represented in radians to 0,2pi
math.radnorm(a) = 
	if a < 0 then
		a += math.ceil(-a / RADIANS_360) * RADIANS_360
	end
	return a % RADIANS_360
-- Compute the difference between both degree values, supporting going around the circle
math.raddelta(a, b) = 
	local diff: number = math.radnorm(b) - math.radnorm(a)
	if diff > RADIANS_180 then
		diff -= RADIANS_360
	elseif diff < -RADIANS_180 then
		diff += RADIANS_360
	end
	return diff
-- Same functionality but with degrees instead of radians
math.degnorm(a) = ...
math.degdelta(a, b) = ...

To Random:
Normal number generation with (mu, sigma) parameters
Uniform Vector2, Vector3
Re-seeding
Re-wind (reverse)

To Vector2/Vector3:
More operators such as Pow, Abs, Sign, Clamp, Max, Min, etc...
Checks: IsFinite, IsNaN, IsInt, IsInf
Conversion To/From Color3
Domain mapping, i.e. map x from (aMin, aMax) -> (bMin, bMax)
MagnitudeSq or DistSq

Color3:
Conversion To/From Vector3
HSL support
Function to clamp within (0,1)
Color distance calculation
Grayscale value, i.e. color.R * 0.299 + color.G * 0.587 + color.B * 0.114
Convert to/from array

NumberSequence / ColorSequence:
Eval(x) = ...

Curve fitting toolkit:
ExpFit in 1, 2, 3 dimensions
PolyFit in 1, 2, 3 dimensions
SplineFit in 1, 2, 3 dimensions

2d / 3d geometry primitives:
Intersections
Inside/Outside test

Matrix N x M class

Crypto/Hashing library:
CRC32, SHA1, MD5, SHA2, SHA3, etc...
Base64

Secure PRNG.

String:
isascii
Levenshtein distance

JSON Pretty printing

Complex date formatting/parsing

Complex number formatting/parsing

Proper timezone support

Ability to query the number of processing cores for optimal parallel batching

I let some additional things slip in that aren’t strictly math related, but the point is pretty clear.

Some of these are trivial and also exist in newer Lua versions.
This is not an exhaustive list, but looking for feedback here.

ALL of these things CAN be implemented in pure Lua, but suffer for significant performance penalties and are painful to carry around - they make developing more difficult. These primitives should be accessible to everyone, not just those of us who have curated/tested libraries of our own with these basic functions.

31 Likes

I constantly find myself needing to write out some equations listed here (common ones: isinf, isnan, lerp). It gets quite annoying and loses readability. Fully support.

I would also add math.tau (equal to 2 pi) to the list.

5 Likes

Let’s not forget that we STILL cannot take odd-degree roots of negative numbers because of floating point errors:

print(math.pow(-8, 1/3)) --> nan, instead of -2

math.root(number, degree) would be much appreciated!

8 Likes

(post deleted by author)

12 Likes

Any additions or changes to standard libraries or anything not specific to Roblox would better be suited to be submitted to the Luau repository (e.g. attempt to add math.tau constant). Adding members to the math library would fit since that affects the Luau language and this way all consumers of the Luau language (including Roblox) benefit from the changes.

Above post is out of scope but Roblox APIs/datatypes are better suited as independent feature requests since those are things that specifically affect Roblox and should supply use cases for adding them in and where other existing methods are insufficient or non-existent.

In general, a feature request with too much scope is hard for engineers to address and break down into use cases and responses individually about each item.

3 Likes

Yea I support this idea.

I was going to write a open-source Luau library that includes some math and cframe functions to save others time.
But having all of it built-in might save a lot more time and likely uses less CPU since Lua can never really match up to the true speed of C++.

3 Likes

Don’t forget Vector3:ProjectOnVector(vectorA, vectorB) and Vector3:ProjectOnPlane(vector, plane). These are massively useful functions Unity provides out of the box and that I’ve had to implement myself here on Roblox.

function Globals.ProjectVectorOnVector(vectorA: Vector3, vectorB : Vector3) : Vector3
	-- credit to https://lua-l.lua.narkive.com/wnhJkmuP/point-to-plane-projections-and-algebra
	return vectorB * (vectorA:Dot(vectorB) / vectorB:Dot(vectorB))
end
function Globals.ProjectVectorOnPlane(vector : Vector3, plane : Vector3) : Vector3
	-- credit to Noobot9k
	if not vector or not plane then error("vector and plane are require parameters. got vector: (" .. tostring(vector) .. "), plane: (".. tostring(plane) .. ")" , 3) end
	return vector - Globals.ProjectVectorOnVector(vector, plane)
end

…And Vector3:MoveTowards(currentVector, targetVector, maxDelta)
(not to be confused with Vector3.Lerp)

function Globals.MoveVectorTowards(currentVector : Vector3, targetVector : Vector3, maxDelta : number) : Vector3
	if currentVector == targetVector then return targetVector end

	local difference = targetVector - currentVector
	local neededDelta = difference.Magnitude
	local targetDelta = math.min(neededDelta, maxDelta)

	if neededDelta <= maxDelta then return targetVector end

	return currentVector + difference.Unit * targetDelta
end

…and the similar Math:MoveTowards(a, b, maxDelta) for numbers instead of vectors

function Globals.MoveTowards(a, b, maxDelta)
	local delta = math.clamp(b - a, -maxDelta, maxDelta)
	return a + delta
end

…and Vector3:ClampMagnitude(vector, maxMagnitude)

function Globals.ClampMagnitude(vector : Vector3, maxMagnitude : number)
	if vector.Magnitude > maxMagnitude then
		return vector.Unit * maxMagnitude
	end
	return vector
end

… and math functions for UDIM2s like UDIM2 * UDIM2, UDIM2 * number, UDIM2 / UDIM2, UDIM2 / number, etc. (currently we only have addition between two UDIM2s).

… and maybe some more advanced stuff like getting the closest point along a ray or rounding vector3s

function Globals.RoundV3(vector : Vector3, resolution) : Vector3
	if typeof(vector) ~= "Vector3" then error("Vector3 expected, got ".. typeof(vector), 2) end
	vector /= resolution
	return Vector3.new(Math.Round(vector.X), Math.Round(vector.Y), Math.Round(vector.Z)) * resolution
end

As you can tell I also have my own collection of libraries I’ve made and carry around with me. At one point this library needed to contain math.round and instance:WaitForChildWithTimeout :man_facepalming: at least I finally don’t need those anymore.

4 Likes

Huge support on most of these, one I can add is utf8.upper/lower. Currently you need to write out a giant table of all characters that have an uppercase form since the string library doesn’t support any characters with a codepoint of >255

Exposing compression libraries would be nice as well, it was mentioned here years ago but was never expanded upon :(

A couple things:
Vector2/3:Min and :Max exist, as does Random:NextUnitVector() for Vector3s.

How would sign work for Vector2/3?

2 Likes

Personally a Seed property of a Random object would be really nice but that’s just me

2 Likes

you can recover the state easily as it’s an insecure rng lol

How?‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

1 Like

Hello.

Right now there are too many distinct suggestions in this thread for us to meaningfully discuss them. Please file separate feature requests for each grouping of library functions you desire so we can consider them separately.

In addition, please include a rationale for each suggestion for why it’s difficult or impractical to implement well in Luau, and why it is common enough to merit inclusion in the standard library. We try to keep the API surface small and focused, so there needs to be a sufficient value add for any given addition to make it in.

4 Likes

Is DateTime not sufficient for you, with regards to date formatting? I have found it has satisfied all my needs except relative time.