I made a custom TweenService for fun and learning. Here’s the module script:
local easingStyles = {}
-- Contains a bunch of functions which input a number from 0 to 1, and outputs a similar number based on the curve
-- Each function also inputs a direction for the curve
local function inOut(i:number,style:(number,EnumItem) -> number,...):number
if i < .5 then
return style(i * 2,Enum.EasingDirection.In,...) / 2
else
return style((i - .5) * 2,Enum.EasingDirection.Out,...) / 2 + .5
end
end
local function createPolynomialFunction(degree:number): (number,EnumItem) -> number
local polynomialFunction
polynomialFunction = function(i:number,direction:EnumItem):number
i = math.clamp(i,0,1)
if direction == Enum.EasingDirection.In then
return i ^ degree
elseif direction == Enum.EasingDirection.Out then
return i ^ (1 / degree)
elseif direction == Enum.EasingDirection.InOut then
return inOut(i,polynomialFunction)
end
end
return polynomialFunction
end
easingStyles.Linear = createPolynomialFunction(1)
easingStyles.Quadratic = createPolynomialFunction(2)
easingStyles.Cubic = createPolynomialFunction(3)
easingStyles.Quartic = createPolynomialFunction(4)
easingStyles.Quintic = createPolynomialFunction(5)
easingStyles.Exponential = function(i:number,direction:EnumItem):number
i = math.clamp(i,0,1)
if direction == Enum.EasingDirection.In then
return 2 ^ (10 * (i - 1))
elseif direction == Enum.EasingDirection.Out then
return 1 - 2 ^ (-10 * i)
elseif direction == Enum.EasingDirection.InOut then
return inOut(i,easingStyles.Exponential)
end
end
easingStyles.Sine = function(i:number,direction:EnumItem):number
i = math.clamp(i,0,1)
local halfPi = math.pi / 2
if direction == Enum.EasingDirection.In then
return math.sin((i - 1) * halfPi) + 1
elseif direction == Enum.EasingDirection.Out then
return math.sin(i * halfPi)
elseif direction == Enum.EasingDirection.InOut then
return inOut(i,easingStyles.Sine)
end
end
easingStyles.Circular = function(i:number,direction:EnumItem):number
i = math.clamp(i,0,1)
if direction == Enum.EasingDirection.In then
return 1 - math.sin(math.acos(i))
elseif direction == Enum.EasingDirection.Out then
return math.sin(math.acos(i + (.5 - i) * 2))
elseif direction == Enum.EasingDirection.InOut then
return inOut(i,easingStyles.Circular)
end
end
easingStyles.Back = function(i:number,direction:EnumItem,steepness:number):number
i = math.clamp(i,0,1)
steepness = steepness or 1.3
local max = steepness ^ .2
if direction == Enum.EasingDirection.In then
local subtraction = (steepness - 1) * i
return (i * max) ^ 5 - subtraction
elseif direction == Enum.EasingDirection.Out then
local subtraction = (steepness - 1) * (1 - i)
return 1 - ((max - i * max) ^ 5 - subtraction)
elseif direction == Enum.EasingDirection.InOut then
return inOut(i,easingStyles.Back,steepness)
end
end
local function create(object:Instance,time:number,properties:{[string]:any},style:() -> number,...)
local startValues = {}
for name,_ in properties do
startValues[name] = object[name]
end
local function updateProperties(alpha:number)
for name,endValue in properties do
local propertyType = typeof(endValue)
if typeof(object[name]) ~= propertyType then return end
local startValue:number = startValues[name]
local newValue:any
local lerpingTypes = {"CFrame","Vector2","Vector3","Color3","UDim2"}
if propertyType == "number" then
object[name] = math.lerp(startValue,endValue,alpha)
elseif table.find(lerpingTypes,propertyType) then
object[name] = startValue:Lerp(endValue,alpha)
elseif propertyType == "UDim" then
local as,ao = startValue.Scale,startValue.Offset
local bs,bo = endValue.Scale,endValue.Offset
object[name] = UDim.new(math.lerp(as,bs,alpha),math.lerp(ao,bo,alpha))
end
end
end
local total = 0
repeat
total += task.wait()
updateProperties(style(total / time,...))
until total >= time
updateProperties(1)
end
return {
EasingStyle = easingStyles,
Tween = create
}
I left out 2 styles, Bounce and Elastic, because they’re more complex.
Compared to the other styles, which are just lines with a simple curve:
Does anyone have ideas for how I can add Bounce and Elastic?

