This commit is contained in:
Michael Freno
2025-11-18 14:15:51 -05:00
parent d86f7dbd5e
commit 5bb1162e06
5 changed files with 1233 additions and 42 deletions

361
modules/Easing.lua Normal file
View File

@@ -0,0 +1,361 @@
--- Easing functions for animations
--- Provides 30+ easing functions for smooth animation transitions
---
--- Easing function type
---@alias EasingFunction fun(t: number): number
---
---@class Easing
local Easing = {}
-- ============================================================================
-- Linear
-- ============================================================================
---@type EasingFunction
function Easing.linear(t)
return t
end
-- ============================================================================
-- Quadratic (Quad)
-- ============================================================================
---@type EasingFunction
function Easing.easeInQuad(t)
return t * t
end
---@type EasingFunction
function Easing.easeOutQuad(t)
return t * (2 - t)
end
---@type EasingFunction
function Easing.easeInOutQuad(t)
return t < 0.5 and 2 * t * t or -1 + (4 - 2 * t) * t
end
-- ============================================================================
-- Cubic
-- ============================================================================
---@type EasingFunction
function Easing.easeInCubic(t)
return t * t * t
end
---@type EasingFunction
function Easing.easeOutCubic(t)
local t1 = t - 1
return t1 * t1 * t1 + 1
end
---@type EasingFunction
function Easing.easeInOutCubic(t)
return t < 0.5 and 4 * t * t * t or (t - 1) * (2 * t - 2) * (2 * t - 2) + 1
end
-- ============================================================================
-- Quartic (Quart)
-- ============================================================================
---@type EasingFunction
function Easing.easeInQuart(t)
return t * t * t * t
end
---@type EasingFunction
function Easing.easeOutQuart(t)
local t1 = t - 1
return 1 - t1 * t1 * t1 * t1
end
---@type EasingFunction
function Easing.easeInOutQuart(t)
if t < 0.5 then
return 8 * t * t * t * t
else
local t1 = t - 1
return 1 - 8 * t1 * t1 * t1 * t1
end
end
-- ============================================================================
-- Quintic (Quint)
-- ============================================================================
---@type EasingFunction
function Easing.easeInQuint(t)
return t * t * t * t * t
end
---@type EasingFunction
function Easing.easeOutQuint(t)
local t1 = t - 1
return 1 + t1 * t1 * t1 * t1 * t1
end
---@type EasingFunction
function Easing.easeInOutQuint(t)
if t < 0.5 then
return 16 * t * t * t * t * t
else
local t1 = t - 1
return 1 + 16 * t1 * t1 * t1 * t1 * t1
end
end
-- ============================================================================
-- Exponential (Expo)
-- ============================================================================
---@type EasingFunction
function Easing.easeInExpo(t)
return t == 0 and 0 or math.pow(2, 10 * (t - 1))
end
---@type EasingFunction
function Easing.easeOutExpo(t)
return t == 1 and 1 or 1 - math.pow(2, -10 * t)
end
---@type EasingFunction
function Easing.easeInOutExpo(t)
if t == 0 then return 0 end
if t == 1 then return 1 end
if t < 0.5 then
return 0.5 * math.pow(2, 20 * t - 10)
else
return 1 - 0.5 * math.pow(2, -20 * t + 10)
end
end
-- ============================================================================
-- Sine
-- ============================================================================
---@type EasingFunction
function Easing.easeInSine(t)
return 1 - math.cos(t * math.pi / 2)
end
---@type EasingFunction
function Easing.easeOutSine(t)
return math.sin(t * math.pi / 2)
end
---@type EasingFunction
function Easing.easeInOutSine(t)
return -(math.cos(math.pi * t) - 1) / 2
end
-- ============================================================================
-- Circular (Circ)
-- ============================================================================
---@type EasingFunction
function Easing.easeInCirc(t)
return 1 - math.sqrt(1 - t * t)
end
---@type EasingFunction
function Easing.easeOutCirc(t)
local t1 = t - 1
return math.sqrt(1 - t1 * t1)
end
---@type EasingFunction
function Easing.easeInOutCirc(t)
if t < 0.5 then
return (1 - math.sqrt(1 - 4 * t * t)) / 2
else
local t1 = -2 * t + 2
return (math.sqrt(1 - t1 * t1) + 1) / 2
end
end
-- ============================================================================
-- Back (Overshoot)
-- ============================================================================
---@type EasingFunction
function Easing.easeInBack(t)
local c1 = 1.70158
local c3 = c1 + 1
return c3 * t * t * t - c1 * t * t
end
---@type EasingFunction
function Easing.easeOutBack(t)
local c1 = 1.70158
local c3 = c1 + 1
local t1 = t - 1
return 1 + c3 * t1 * t1 * t1 + c1 * t1 * t1
end
---@type EasingFunction
function Easing.easeInOutBack(t)
local c1 = 1.70158
local c2 = c1 * 1.525
if t < 0.5 then
return (2 * t * 2 * t * ((c2 + 1) * 2 * t - c2)) / 2
else
local t1 = 2 * t - 2
return (t1 * t1 * ((c2 + 1) * t1 + c2) + 2) / 2
end
end
-- ============================================================================
-- Elastic (Spring)
-- ============================================================================
---@type EasingFunction
function Easing.easeInElastic(t)
if t == 0 then return 0 end
if t == 1 then return 1 end
local c4 = (2 * math.pi) / 3
return -math.pow(2, 10 * t - 10) * math.sin((t * 10 - 10.75) * c4)
end
---@type EasingFunction
function Easing.easeOutElastic(t)
if t == 0 then return 0 end
if t == 1 then return 1 end
local c4 = (2 * math.pi) / 3
return math.pow(2, -10 * t) * math.sin((t * 10 - 0.75) * c4) + 1
end
---@type EasingFunction
function Easing.easeInOutElastic(t)
if t == 0 then return 0 end
if t == 1 then return 1 end
local c5 = (2 * math.pi) / 4.5
if t < 0.5 then
return -(math.pow(2, 20 * t - 10) * math.sin((20 * t - 11.125) * c5)) / 2
else
return (math.pow(2, -20 * t + 10) * math.sin((20 * t - 11.125) * c5)) / 2 + 1
end
end
-- ============================================================================
-- Bounce
-- ============================================================================
---@type EasingFunction
function Easing.easeOutBounce(t)
local n1 = 7.5625
local d1 = 2.75
if t < 1 / d1 then
return n1 * t * t
elseif t < 2 / d1 then
local t1 = t - 1.5 / d1
return n1 * t1 * t1 + 0.75
elseif t < 2.5 / d1 then
local t1 = t - 2.25 / d1
return n1 * t1 * t1 + 0.9375
else
local t1 = t - 2.625 / d1
return n1 * t1 * t1 + 0.984375
end
end
---@type EasingFunction
function Easing.easeInBounce(t)
return 1 - Easing.easeOutBounce(1 - t)
end
---@type EasingFunction
function Easing.easeInOutBounce(t)
if t < 0.5 then
return (1 - Easing.easeOutBounce(1 - 2 * t)) / 2
else
return (1 + Easing.easeOutBounce(2 * t - 1)) / 2
end
end
-- ============================================================================
-- Configurable Easing Factories
-- ============================================================================
--- Create a custom back easing function with configurable overshoot
---@param overshoot number? Overshoot amount (default: 1.70158)
---@return EasingFunction
function Easing.back(overshoot)
overshoot = overshoot or 1.70158
local c3 = overshoot + 1
return function(t)
return c3 * t * t * t - overshoot * t * t
end
end
--- Create a custom elastic easing function
---@param amplitude number? Amplitude (default: 1)
---@param period number? Period (default: 0.3)
---@return EasingFunction
function Easing.elastic(amplitude, period)
amplitude = amplitude or 1
period = period or 0.3
return function(t)
if t == 0 then return 0 end
if t == 1 then return 1 end
local s = period / 4
local a = amplitude
if a < 1 then
a = 1
s = period / 4
else
s = period / (2 * math.pi) * math.asin(1 / a)
end
return a * math.pow(2, -10 * t) * math.sin((t - s) * (2 * math.pi) / period) + 1
end
end
--- Get list of all available easing function names
---@return string[] names Array of easing function names
function Easing.list()
return {
-- Linear
"linear",
-- Quad
"easeInQuad", "easeOutQuad", "easeInOutQuad",
-- Cubic
"easeInCubic", "easeOutCubic", "easeInOutCubic",
-- Quart
"easeInQuart", "easeOutQuart", "easeInOutQuart",
-- Quint
"easeInQuint", "easeOutQuint", "easeInOutQuint",
-- Expo
"easeInExpo", "easeOutExpo", "easeInOutExpo",
-- Sine
"easeInSine", "easeOutSine", "easeInOutSine",
-- Circ
"easeInCirc", "easeOutCirc", "easeInOutCirc",
-- Back
"easeInBack", "easeOutBack", "easeInOutBack",
-- Elastic
"easeInElastic", "easeOutElastic", "easeInOutElastic",
-- Bounce
"easeInBounce", "easeOutBounce", "easeInOutBounce",
}
end
--- Get an easing function by name
---@param name string Easing function name
---@return EasingFunction? easing The easing function, or nil if not found
function Easing.get(name)
return Easing[name]
end
return Easing