LA = LA or {} --https://easings.net LA.Lerp = function(a, b, t) return a + (b - a) * t end LA.LerpVector = function(a, b, t) return vector3(LA.Lerp(a.x, b.x, t), LA.Lerp(a.y, b.y, t), LA.Lerp(a.z, b.z, t)) end LA.EaseInSine = function(t) return 1 - math.cos((t * math.pi) / 2) end LA.EaseOutSine = function(t) return math.sin((t * math.pi) / 2) end LA.EaseInOutSine = function(t) return -(math.cos(math.pi * t) - 1) / 2 end LA.EaseInCubic = function(t) return t ^ 3 end LA.EaseOutCubic = function(t) return 1 - (1 - t) ^ 3 end LA.EaseInOutCubic = function(t) return t < 0.5 and 4 * t ^ 3 or 1 - ((-2 * t + 2) ^ 3) / 2 end LA.EaseInQuint = function(t) return t ^ 5 end LA.EaseOutQuint = function(t) return 1 - (1 - t) ^ 5 end LA.EaseInOutQuint = function(t) return t < 0.5 and 16 * t ^ 5 or 1 - ((-2 * t + 2) ^ 5) / 2 end LA.EaseInCirc = function(t) return 1 - math.sqrt(1 - t ^ 2) end LA.EaseOutCirc = function(t) return math.sqrt(1 - (t - 1) ^ 2) end LA.EaseInOutCirc = function(t) return t < 0.5 and (1 - math.sqrt(1 - (2 * t) ^ 2)) / 2 or (math.sqrt(1 - (-2 * t + 2) ^ 2) + 1) / 2 end LA.EaseInElastic = function(t) return t == 0 and 0 or t == 1 and 1 or -2 ^ (10 * t - 10) * math.sin((t * 10 - 10.75) * (2 * math.pi) / 3) end LA.EaseOutElastic = function(t) return t == 0 and 0 or t == 1 and 1 or 2 ^ (-10 * t) * math.sin((t * 10 - 0.75) * (2 * math.pi) / 3) + 1 end LA.EaseInOutElastic = function(t) return t == 0 and 0 or t == 1 and 1 or t < 0.5 and -(2 ^ (20 * t - 10) * math.sin((20 * t - 11.125) * (2 * math.pi) / 4.5)) / 2 or (2 ^ (-20 * t + 10) * math.sin((20 * t - 11.125) * (2 * math.pi) / 4.5)) / 2 + 1 end LA.EaseInQuad = function(t) return t ^ 2 end LA.EaseOutQuad = function(t) return 1 - (1 - t) ^ 2 end LA.EaseInOutQuad = function(t) return t < 0.5 and 2 * t ^ 2 or 1 - (-2 * t + 2) ^ 2 / 2 end LA.EaseInQuart = function(t) return t ^ 4 end LA.EaseOutQuart = function(t) return 1 - (1 - t) ^ 4 end LA.EaseInOutQuart = function(t) return t < 0.5 and 8 * t ^ 4 or 1 - ((-2 * t + 2) ^ 4) / 2 end LA.EaseInExpo = function(t) return t == 0 and 0 or 2 ^ (10 * t - 10) end LA.EaseOutExpo = function(t) return t == 1 and 1 or 1 - 2 ^ (-10 * t) end LA.EaseInOutExpo = function(t) return t == 0 and 0 or t == 1 and 1 or t < 0.5 and 2 ^ (20 * t - 10) / 2 or (2 - 2 ^ (-20 * t + 10)) / 2 end LA.EaseInBack = function(t) return 2.70158 * t ^ 3 - 1.70158 * t ^ 2 end LA.EaseOutBack = function(t) return 1 + 2.70158 * (t - 1) ^ 3 + 1.70158 * (t - 1) ^ 2 end LA.EaseInOutBack = function(t) return t < 0.5 and (2 * t) ^ 2 * ((1.70158 + 1) * 2 * t - 1.70158) / 2 or ((2 * t - 2) ^ 2 * ((1.70158 + 1) * (t * 2 - 2) + 1.70158) + 2) / 2 end LA.EaseInBounce = function(t) print(1 - LA.EaseOutBounce(1 - t)) return 1 - LA.EaseOutBounce(1 - t) end LA.EaseOutBounce = function(t) if t < 1 / 2.75 then return 7.5625 * t ^ 2 elseif t < 2 / 2.75 then return 7.5625 * (t - 1.5 / 2.75) ^ 2 + 0.75 elseif t < 2.5 / 2.75 then return 7.5625 * (t - 2.25 / 2.75) ^ 2 + 0.9375 else return 7.5625 * (t - 2.625 / 2.75) ^ 2 + 0.984375 end end LA.EaseInOutBounce = function(t) return t < 0.5 and (1 - LA.EaseOutBounce(1 - 2 * t)) / 2 or (1 + LA.EaseOutBounce(2 * t - 1)) / 2 end LA.EaseIn = function(t, easingType) easingType = string.lower(easingType) if easingType == "linear" then return t elseif easingType == "sine" then return LA.EaseInSine(t) elseif easingType == "cubic" then return LA.EaseInCubic(t) elseif easingType == "quint" then return LA.EaseInQuint(t) elseif easingType == "circ" then return LA.EaseInCirc(t) elseif easingType == "elastic" then return LA.EaseInElastic(t) elseif easingType == "quad" then return LA.EaseInQuad(t) elseif easingType == "quart" then return LA.EaseInQuart(t) elseif easingType == "expo" then return LA.EaseInExpo(t) elseif easingType == "back" then return LA.EaseInBack(t) elseif easingType == "bounce" then return LA.EaseInBounce(t) end end LA.EaseOut = function(t, easingType) easingType = string.lower(easingType) if easingType == "linear" then return t elseif easingType == "sine" then return LA.EaseOutSine(t) elseif easingType == "cubic" then return LA.EaseOutCubic(t) elseif easingType == "quint" then return LA.EaseOutQuint(t) elseif easingType == "circ" then return LA.EaseOutCirc(t) elseif easingType == "elastic" then return LA.EaseOutElastic(t) elseif easingType == "quad" then return LA.EaseOutQuad(t) elseif easingType == "quart" then return LA.EaseOutQuart(t) elseif easingType == "expo" then return LA.EaseOutExpo(t) elseif easingType == "back" then return LA.EaseOutBack(t) elseif easingType == "bounce" then return LA.EaseOutBounce(t) end end LA.EaseInOut = function(t, easingType) easingType = string.lower(easingType) if easingType == "linear" then return t elseif easingType == "sine" then return LA.EaseInOutSine(t) elseif easingType == "cubic" then return LA.EaseInOutCubic(t) elseif easingType == "quint" then return LA.EaseInOutQuint(t) elseif easingType == "circ" then return LA.EaseInOutCirc(t) elseif easingType == "elastic" then return LA.EaseInOutElastic(t) elseif easingType == "quad" then return LA.EaseInOutQuad(t) elseif easingType == "quart" then return LA.EaseInOutQuart(t) elseif easingType == "expo" then return LA.EaseInOutExpo(t) elseif easingType == "back" then return LA.EaseInOutBack(t) elseif easingType == "bounce" then return LA.EaseInOutBounce(t) end end LA.EaseInVector = function(a, b, t, easingType) local tEase = LA.EaseIn(t, easingType) local x, y, z = a.x, a.y, a.z local x2, y2, z2 = b.x, b.y, b.z local x3, y3, z3 = x2 - x, y2 - y, z2 - z local x4, y4, z4 = x3 * tEase, y3 * tEase, z3 * tEase local x5, y5, z5 = x + x4, y + y4, z + z4 return vector3(x5, y5, z5) end LA.EaseOutVector = function(a, b, t, easingType) local tEase = LA.EaseOut(t, easingType) local x, y, z = a.x, a.y, a.z local x2, y2, z2 = b.x, b.y, b.z local x3, y3, z3 = x2 - x, y2 - y, z2 - z local x4, y4, z4 = x3 * tEase, y3 * tEase, z3 * tEase local x5, y5, z5 = x + x4, y + y4, z + z4 return vector3(x5, y5, z5) end LA.EaseInOutVector = function(a, b, t, easingType) local tEase = LA.EaseInOut(t, easingType) local x, y, z = a.x, a.y, a.z local x2, y2, z2 = b.x, b.y, b.z local x3, y3, z3 = x2 - x, y2 - y, z2 - z local x4, y4, z4 = x3 * tEase, y3 * tEase, z3 * tEase local x5, y5, z5 = x + x4, y + y4, z + z4 return vector3(x5, y5, z5) end LA.EaseVector = function(inout, a, b, t, easingType) inout = string.lower(inout) if inout == "in" then return LA.EaseInVector(a, b, t, easingType) elseif inout == "out" then return LA.EaseOutVector(a, b, t, easingType) elseif inout == "inout" then return LA.EaseInOutVector(a, b, t, easingType) end assert(false, "Invalid type") end LA.EaseOnAxis = function(inout, a, b, t, easingType, axis) axis = axis or vector3(0, 0, 0) local x, y, z = a.x, a.y, a.z local increment = 0 if inout == "in" then increment = LA.EaseIn(t, easingType) elseif inout == "out" then increment = LA.EaseOut(t, easingType) elseif inout == "inout" then increment = LA.EaseInOut(t, easingType) end return axis * increment end LA.TestCheck = function(point1, point2) local dx = point1.x - point2.x local dy = point1.y - point2.y local dz = point1.z - point2.z return math.sqrt(dx*dx + dy*dy + dz*dz) end LA.BoxZoneCheck = function(point, lower, upper) local x1, y1, z1 = lower.x, lower.y, lower.z local x2, y2, z2 = upper.x, upper.y, upper.z return point.x > x1 and point.x < x2 and point.y > y1 and point.y < y2 and point.z > z1 and point.z < z2 end LA.DistanceCheck = function(pointA, pointB) return #(pointA - pointB) < 0.5 end LA.Chance = function(chance) assert(chance, "Chance must be passed") assert(type(chance) == "number", "Chance must be a number") assert(chance >= 0 and chance <= 100, "Chance must be between 0 and 100") return math.random(1, 100) <= chance end LA.Vector4To3 = function(vector4) assert(vector4, "Vector4 must be passed") assert(type(vector4) == "vector4", "Vector4 must be a vector4") return vector3(vector4.x, vector4.y, vector4.z), vector4.w end LA.Dot = function(vectorA, vectorB) return vectorA.x * vectorB.x + vectorA.y * vectorB.y + vectorA.z * vectorB.z end LA.Length = function(vector) return math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z) end LA.Normalize = function(vector) local length = LA.Length(vector) return vector3(vector.x / length, vector.y / length, vector.z / length) end LA.Create2DRotationMatrix = function(angle) -- angle in radians local c = math.cos(angle) local s = math.sin(angle) return { c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, } end LA.Create3DAxisRotationMatrix = function(vector) local yaw = vector.z local pitch = vector.x local roll = vector.y local cy = math.cos(yaw) local sy = math.sin(yaw) local cp = math.cos(pitch) local sp = math.sin(pitch) local cr = math.cos(roll) local sr = math.sin(roll) local matrix = { vector3(cp * cy, cp * sy, -sp), vector3(cy * sp * sr - cr * sy, sy * sp * sr + cr * cy, cp * sr), vector3(cy * sp * cr + sr * sy, cr * cy * sp - sr * sy, cp * cr) } return matrix end LA.Circle = function(t, radius, center) local x = radius * math.cos(t) + center.x local y = radius * math.sin(t) + center.y return vector3(x, y, center.z) end LA.Clamp = function(value, min, max) return math.min(math.max(value, min), max) end LA.CrossProduct = function(a, b) local x = a.y * b.z - a.z * b.y local y = a.z * b.x - a.x * b.z local z = a.x * b.y - a.y * b.x return vector3(x, y, z) end LA.CreateTranslateMatrix = function(x, y, z) return { 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1, } end LA.MultiplyMatrix = function(m1, m2) local result = {} for i = 1, 4 do for j = 1, 4 do local sum = 0 for k = 1, 4 do sum = sum + m1[(i - 1) * 4 + k] * m2[(k - 1) * 4 + j] end result[(i - 1) * 4 + j] = sum end end return result end LA.MultiplyMatrixByVector = function(m, v) local result = {} for i = 1, 4 do local sum = 0 for j = 1, 4 do sum = sum + m[(i - 1) * 4 + j] * v[j] end result[i] = sum end return result end --Slines LA.SplineLerp = function(nodes, start, endPos, t) -- Ensure t is clamped between 0 and 1 t = LA.Clamp(t, 0, 1) -- Find the two closest nodes around t local prevNode, nextNode = nil, nil for i = 1, #nodes - 1 do if nodes[i].time <= t and nodes[i + 1].time >= t then prevNode, nextNode = nodes[i], nodes[i + 1] break end end -- Edge cases: If t is before or after the defined range if not prevNode then return start end if not nextNode then return endPos end -- Normalize t within the segment local segmentT = (t - prevNode.time) / (nextNode.time - prevNode.time) -- Interpolate the value (y-axis) local smoothedT = LA.Lerp(prevNode.value, nextNode.value, segmentT) -- Perform final Lerp using the interpolated smoothing factor return LA.Lerp(start, endPos, smoothedT) end LA.SplineSmooth = function(nodes, points, t) -- Ensure valid input if #points < 2 then return points end t = LA.Clamp(t, 0, 1) local smoothedPoints = {} for i = 1, #points - 1 do local smoothedPos = LA.SplineLerp(nodes, points[i], points[i + 1], t) table.insert(smoothedPoints, smoothedPos) end -- Ensure last point remains unchanged table.insert(smoothedPoints, points[#points]) return smoothedPoints end LA.Spline = function(points, resolution) -- Ensure valid input if #points < 2 then return points end -- Create a list of nodes local nodes = {} for i = 1, #points do table.insert(nodes, { time = i / (#points - 1), value = i }) end -- Smooth the points local smoothedPoints = {} for i = 0, 1, resolution do local smoothedPos = LA.SplineSmooth(nodes, points, i) table.insert(smoothedPoints, smoothedPos) end return smoothedPoints end LA.SplineCatmullRom = function(points, resolution) -- Ensure valid input if #points < 4 then return points end -- Create a list of nodes local nodes = {} for i = 1, #points do table.insert(nodes, { time = i / (#points - 1), value = i }) end -- Smooth the points local smoothedPoints = {} for i = 0, 1, resolution do local smoothedPos = LA.SplineSmooth(nodes, points, i) table.insert(smoothedPoints, smoothedPos) end return smoothedPoints end exports('LA', LA) return LA -- local easingTypes = { -- "linear", -- "sine", -- "cubic", -- "quint", -- "circ", -- "elastic", -- "quad", -- "quart", -- "expo", -- "back", -- "bounce" -- } --local inout = { -- "in", -- "out", -- "inout" --} -- LA.LerpAngle = function(a, b, t) -- local num = math.abs(b - a) % 360 -- local num2 = 360 - num -- if num < num2 then -- return a + num * t -- else -- return a - num2 * t -- end -- end -- LA.LerpVectorAngle = function(a, b, t) -- local x, y, z = a.x, a.y, a.z -- local x2, y2, z2 = b.x, b.y, b.z -- local x3, y3, z3 = LA.LerpAngle(x, x2, t), LA.LerpAngle(y, y2, t), LA.LerpAngle(z, z2, t) -- return vector3(x3, y3, z3) -- end -- return LA