362 lines
8.9 KiB
Lua
362 lines
8.9 KiB
Lua
--- 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
|