boattween

Run Settings
LanguageLua
Language Version
Run Command
--[==[ BoatTween (because TweenService2 was taken) by boatbomber (Zack Ovits) © 2020 API: function BoatTween:Create(Object,Data) returns a Tween object Params: - Object The instance that is having it's properties tweened - Data A dictionary of the various settings of the tween { number Time = Any positive number How long the tween should take to complete string EasingStyle = Any TweenStyle from the list below The style that the tween follows (Note: Uses strings instead of Enum.EasingStyle to allow us to add styles that Roblox doesn't support) List of available styles: Linear Quad Cubic Quart Quint Sine Expo Circ Elastic Back Bounce Smooth Smoother RidiculousWiggle RevBack Spring SoftSpring Standard Sharp Acceleration Deceleration StandardProductive EntranceProductive ExitProductive StandardExpressive EntranceExpressive ExitExpressive FabricStandard FabricAccelerate FabricDecelerate UWPAccelerate MozillaCurve string EasingDirection = "In" or "Out" or "InOut" or "OutIn" The direction for the TweenStyle to adhere to number DelayTime = 0 -> math.huge The amount of time before the tween begins playback after calling :Play() on the tween (Note: doesn't affect :Resume() calls) number RepeatCount = -1 -> math.huge How many times the tween should repeat with -1 being infinity (Note: will wait the DelayTime in between replaying) boolean Reverses = false or true Whether the tween should reverse itself after completion (note: Waits the DelayTime before reversing) table Goal = dictionary A dictionary where the keys are properties to tween and the values are the end goals of said properties You may tween any property with value of the following types: number boolean CFrame Color3 UDim2 UDim Ray NumberRange NumberSequenceKeypoint PhysicalProperties NumberSequence Region3 Rect Vector2 Vector3 string StepType = "Stepped" or "Heartbeat" or "RenderStepped" The event of RunService for the tween to move on } function Tween:Play() Plays the tween, starting from the beginning function Tween:Stop() Stops the tween, freezing it in its current state function Tween:Resume() Plays the tween, starting from current position and time function TweenObject:Destroy() Clears connections, stops playback, destroys objects property Tween.Instance The object being tweened property Tween.PlaybackState An Enum.PlaybackState representing the Tween's current state event Tween.Stopped Fired when a Tween ends from the :Stop() function event Tween.Completed Fired when a Tween ends due to :Play() being completed event Tween.Resumed Fired when a Tween is played through the :Resume() function --]==] local function Linear(T) return T end local function Bezier(X1, Y1, X2, Y2) if not (X1 and Y1 and X2 and Y2) then error("Need 4 numbers to construct a Bezier curve", 0) end if not (0 <= X1 and X1 <= 1 and 0 <= X2 and X2 <= 1) then error("The x values must be within range [0, 1]", 0) end if X1 == Y1 and X2 == Y2 then return Linear end local SampleValues = {} for Index = 0, 10 do local IndexDiv10 = Index / 10 SampleValues[Index] = (((1 - 3 * X2 + 3 * X2) * IndexDiv10 + (3 * X2 - 6 * X1)) * IndexDiv10 + (3 * X1)) * IndexDiv10 end return function(T) if X1 == Y1 and X2 == Y2 then return Linear end if T == 0 or T == 1 then return T end local GuessT local IntervalStart = 0 local CurrentSample = 1 while CurrentSample ~= 10 and SampleValues[CurrentSample] <= T do IntervalStart += 0.1 CurrentSample += 1 end CurrentSample -= 1 local Dist = (T - SampleValues[CurrentSample]) / (SampleValues[CurrentSample + 1] - SampleValues[CurrentSample]) local GuessForT = IntervalStart + Dist / 10 local InitialSlope = 3 * (1 - 3 * X2 + 3 * X1) * GuessForT * GuessForT + 2 * (3 * X2 - 6 * X1) * GuessForT + (3 * X1) if InitialSlope >= 0.001 then for _ = 0, 3 do local CurrentSlope = 3 * (1 - 3 * X2 + 3 * X1) * GuessForT * GuessForT + 2 * (3 * X2 - 6 * X1) * GuessForT + (3 * X1) local CurrentX = ((((1 - 3 * X2 + 3 * X1) * GuessForT + (3 * X2 - 6 * X1)) * GuessForT + (3 * X1)) * GuessForT) - T GuessForT -= CurrentX / CurrentSlope end GuessT = GuessForT elseif InitialSlope == 0 then GuessT = GuessForT else local AB = IntervalStart + 0.1 local CurrentX, CurrentT, Index = 0, nil, nil while math.abs(CurrentX) > 0.0000001 and Index < 10 do CurrentT = IntervalStart + (AB - IntervalStart) / 2 CurrentX = ((((1 - 3 * X2 + 3 * X1) * CurrentT + (3 * X2 - 6 * X1)) * CurrentT + (3 * X1)) * CurrentT) - T if CurrentX > 0 then AB = CurrentT else IntervalStart = CurrentT end Index += 1 end GuessT = CurrentT end return (((1 - 3 * Y2 + 3 * Y1) * GuessT + (3 * Y2 - 6 * Y1)) * GuessT + (3 * Y1)) * GuessT end end local ipairs = ipairs local BLACK_COLOR3 = Color3.new() -- Generic Roblox DataType lerp function. local function RobloxLerp(V0, V1) return function(Alpha) return V0:Lerp(V1, Alpha) end end local function Lerp(Start, Finish, Alpha) return Start + Alpha * (Finish - Start) end local function SortByTime(A, B) return A.Time < B.Time end local function Color3Lerp(C0, C1) local L0, U0, V0 local R0, G0, B0 = C0.R, C0.G, C0.B R0 = R0 < 0.0404482362771076 and R0 / 12.92 or 0.87941546140213 * (R0 + 0.055) ^ 2.4 G0 = G0 < 0.0404482362771076 and G0 / 12.92 or 0.87941546140213 * (G0 + 0.055) ^ 2.4 B0 = B0 < 0.0404482362771076 and B0 / 12.92 or 0.87941546140213 * (B0 + 0.055) ^ 2.4 local Y0 = 0.2125862307855956 * R0 + 0.71517030370341085 * G0 + 0.0722004986433362 * B0 local Z0 = 3.6590806972265883 * R0 + 11.4426895800574232 * G0 + 4.1149915024264843 * B0 local _L0 = Y0 > 0.008856451679035631 and 116 * Y0 ^ (1 / 3) - 16 or 903.296296296296 * Y0 if Z0 > 1E-15 then local X = 0.9257063972951867 * R0 - 0.8333736323779866 * G0 - 0.09209820666085898 * B0 L0, U0, V0 = _L0, _L0 * X / Z0, _L0 * (9 * Y0 / Z0 - 0.46832) else L0, U0, V0 = _L0, -0.19783 * _L0, -0.46832 * _L0 end local L1, U1, V1 local R1, G1, B1 = C1.R, C1.G, C1.B R1 = R1 < 0.0404482362771076 and R1 / 12.92 or 0.87941546140213 * (R1 + 0.055) ^ 2.4 G1 = G1 < 0.0404482362771076 and G1 / 12.92 or 0.87941546140213 * (G1 + 0.055) ^ 2.4 B1 = B1 < 0.0404482362771076 and B1 / 12.92 or 0.87941546140213 * (B1 + 0.055) ^ 2.4 local Y1 = 0.2125862307855956 * R1 + 0.71517030370341085 * G1 + 0.0722004986433362 * B1 local Z1 = 3.6590806972265883 * R1 + 11.4426895800574232 * G1 + 4.1149915024264843 * B1 local _L1 = Y1 > 0.008856451679035631 and 116 * Y1 ^ (1 / 3) - 16 or 903.296296296296 * Y1 if Z1 > 1E-15 then local X = 0.9257063972951867 * R1 - 0.8333736323779866 * G1 - 0.09209820666085898 * B1 L1, U1, V1 = _L1, _L1 * X / Z1, _L1 * (9 * Y1 / Z1 - 0.46832) else L1, U1, V1 = _L1, -0.19783 * _L1, -0.46832 * _L1 end return function(Alpha) local L = (1 - Alpha) * L0 + Alpha * L1 if L < 0.0197955 then return BLACK_COLOR3 end local U = ((1 - Alpha) * U0 + Alpha * U1) / L + 0.19783 local V = ((1 - Alpha) * V0 + Alpha * V1) / L + 0.46832 local Y = (L + 16) / 116 Y = Y > 0.206896551724137931 and Y * Y * Y or 0.12841854934601665 * Y - 0.01771290335807126 local X = Y * U / V local Z = Y * ((3 - 0.75 * U) / V - 5) local R = 7.2914074 * X - 1.5372080 * Y - 0.4986286 * Z local G = -2.1800940 * X + 1.8757561 * Y + 0.0415175 * Z local B = 0.1253477 * X - 0.2040211 * Y + 1.0569959 * Z if R < 0 and R < G and R < B then R, G, B = 0, G - R, B - R elseif G < 0 and G < B then R, G, B = R - G, 0, B - G elseif B < 0 then R, G, B = R - B, G - B, 0 end R = R < 3.1306684425E-3 and 12.92 * R or 1.055 * R ^ (1 / 2.4) - 0.055 -- 3.1306684425E-3 G = G < 3.1306684425E-3 and 12.92 * G or 1.055 * G ^ (1 / 2.4) - 0.055 B = B < 3.1306684425E-3 and 12.92 * B or 1.055 * B ^ (1 / 2.4) - 0.055 R = R > 1 and 1 or R < 0 and 0 or R G = G > 1 and 1 or G < 0 and 0 or G B = B > 1 and 1 or B < 0 and 0 or B return Color3.new(R, G, B) end end local Lerps = setmetatable({ boolean = function(V0, V1) return function(Alpha) if Alpha < 0.5 then return V0 else return V1 end end end; number = function(V0, V1) local Delta = V1 - V0 return function(Alpha) return V0 + Delta * Alpha end end; string = function(V0, V1) local RegularString = false local N0, D do local Sign0, H0, M0, S0 = string.match(V0, "^([+-]?)(%d*):[+-]?(%d*):[+-]?(%d*)$") local Sign1, H1, M1, S1 = string.match(V1, "^([+-]?)(%d*):[+-]?(%d*):[+-]?(%d*)$") if Sign0 and Sign1 then N0 = 3600 * (tonumber(H0) or 0) + 60 * (tonumber(M0) or 0) + (tonumber(S0) or 0) local N1 = 3600 * (tonumber(H1) or 0) + 60 * (tonumber(M1) or 0) + (tonumber(S1) or 0) if Sign0 == "-" then N0 = -N0 end D = (43200 + (Sign1 ~= "-" and N1 or -N1) - N0) % 86400 - 43200 else RegularString = true end end if RegularString then local Length = #V1 return function(Alpha) Alpha = 1 + Length * Alpha return string.sub(V1, 1, Alpha < Length and Alpha or Length) end else return function(Alpha) local FS = (N0 + D * Alpha) % 86400 local S = math.abs(FS) return string.format( FS < 0 and "-%.2u:%.2u:%.2u" or "%.2u:%.2u:%.2u", (S - S % 3600) / 3600, (S % 3600 - S % 60) / 60, S % 60 ) end end end; CFrame = RobloxLerp; Color3 = Color3Lerp; NumberRange = function(V0, V1) local Min0, Max0 = V0.Min, V0.Max local DeltaMin, DeltaMax = V1.Min - Min0, V1.Max - Max0 return function(Alpha) return NumberRange.new(Min0 + Alpha * DeltaMin, Max0 + Alpha * DeltaMax) end end; NumberSequenceKeypoint = function(V0, V1) local T0, Value0, E0 = V0.Time, V0.Value, V0.Envelope local DT, DV, DE = V1.Time - T0, V1.Value - Value0, V1.Envelope - E0 return function(Alpha) return NumberSequenceKeypoint.new(T0 + Alpha * DT, Value0 + Alpha * DV, E0 + Alpha * DE) end end; PhysicalProperties = function(V0, V1) local D0, E0, EW0, F0, FW0 = V0.Density, V0.Elasticity, V0.ElasticityWeight, V0.Friction, V0.FrictionWeight local DD, DE, DEW, DF, DFW = V1.Density - D0, V1.Elasticity - E0, V1.ElasticityWeight - EW0, V1.Friction - F0, V1.FrictionWeight - FW0 return function(Alpha) return PhysicalProperties.new( D0 + Alpha * DD, E0 + Alpha * DE, EW0 + Alpha * DEW, F0 + Alpha * DF, FW0 + Alpha * DFW ) end end; Ray = function(V0, V1) local O0, D0, O1, D1 = V0.Origin, V0.Direction, V1.Origin, V1.Direction local OX0, OY0, OZ0, DX0, DY0, DZ0 = O0.X, O0.Y, O0.Z, D0.X, D0.Y, D0.Z local DOX, DOY, DOZ, DDX, DDY, DDZ = O1.X - OX0, O1.Y - OY0, O1.Z - OZ0, D1.X - DX0, D1.Y - DY0, D1.Z - DZ0 return function(Alpha) return Ray.new( Vector3.new(OX0 + Alpha * DOX, OY0 + Alpha * DOY, OZ0 + Alpha * DOZ), Vector3.new(DX0 + Alpha * DDX, DY0 + Alpha * DDY, DZ0 + Alpha * DDZ) ) end end; UDim = function(V0, V1) local SC, OF = V0.Scale, V0.Offset local DSC, DOF = V1.Scale - SC, V1.Offset - OF return function(Alpha) return UDim.new(SC + Alpha * DSC, OF + Alpha * DOF) end end; UDim2 = RobloxLerp; Vector2 = RobloxLerp; Vector3 = RobloxLerp; Rect = function(V0, V1) return function(Alpha) return Rect.new( V0.Min.X + Alpha * (V1.Min.X - V0.Min.X), V0.Min.Y + Alpha * (V1.Min.Y - V0.Min.Y), V0.Max.X + Alpha * (V1.Max.X - V0.Max.X), V0.Max.Y + Alpha * (V1.Max.Y - V0.Max.Y) ) end end; Region3 = function(V0, V1) return function(Alpha) local imin = Lerp(V0.CFrame * (-V0.Size / 2), V1.CFrame * (-V1.Size / 2), Alpha) local imax = Lerp(V0.CFrame * (V0.Size / 2), V1.CFrame * (V1.Size / 2), Alpha) local iminx = imin.X local imaxx = imax.X local iminy = imin.Y local imaxy = imax.Y local iminz = imin.Z local imaxz = imax.Z return Region3.new( Vector3.new(iminx < imaxx and iminx or imaxx, iminy < imaxy and iminy or imaxy, iminz < imaxz and iminz or imaxz), Vector3.new(iminx > imaxx and iminx or imaxx, iminy > imaxy and iminy or imaxy, iminz > imaxz and iminz or imaxz) ) end end; NumberSequence = function(V0, V1) return function(Alpha) local keypoints = {} local addedTimes = {} local keylength = 0 for _, ap in ipairs(V0.Keypoints) do local closestAbove, closestBelow for _, bp in ipairs(V1.Keypoints) do if bp.Time == ap.Time then closestAbove, closestBelow = bp, bp break elseif bp.Time < ap.Time and (closestBelow == nil or bp.Time > closestBelow.Time) then closestBelow = bp elseif bp.Time > ap.Time and (closestAbove == nil or bp.Time < closestAbove.Time) then closestAbove = bp end end local bValue, bEnvelope if closestAbove == closestBelow then bValue, bEnvelope = closestAbove.Value, closestAbove.Envelope else local p = (ap.Time - closestBelow.Time) / (closestAbove.Time - closestBelow.Time) bValue = (closestAbove.Value - closestBelow.Value) * p + closestBelow.Value bEnvelope = (closestAbove.Envelope - closestBelow.Envelope) * p + closestBelow.Envelope end keylength += 1 keypoints[keylength] = NumberSequenceKeypoint.new(ap.Time, (bValue - ap.Value) * Alpha + ap.Value, (bEnvelope - ap.Envelope) * Alpha + ap.Envelope) addedTimes[ap.Time] = true end for _, bp in ipairs(V1.Keypoints) do if not addedTimes[bp.Time] then local closestAbove, closestBelow for _, ap in ipairs(V0.Keypoints) do if ap.Time == bp.Time then closestAbove, closestBelow = ap, ap break elseif ap.Time < bp.Time and (closestBelow == nil or ap.Time > closestBelow.Time) then closestBelow = ap elseif ap.Time > bp.Time and (closestAbove == nil or ap.Time < closestAbove.Time) then closestAbove = ap end end local aValue, aEnvelope if closestAbove == closestBelow then aValue, aEnvelope = closestAbove.Value, closestAbove.Envelope else local p = (bp.Time - closestBelow.Time) / (closestAbove.Time - closestBelow.Time) aValue = (closestAbove.Value - closestBelow.Value) * p + closestBelow.Value aEnvelope = (closestAbove.Envelope - closestBelow.Envelope) * p + closestBelow.Envelope end keylength += 1 keypoints[keylength] = NumberSequenceKeypoint.new(bp.Time, (bp.Value - aValue) * Alpha + aValue, (bp.Envelope - aEnvelope) * Alpha + aEnvelope) end end table.sort(keypoints, SortByTime) return NumberSequence.new(keypoints) end end; ColorSequence = function(V0, V1) return function(Alpha) local keypoints = {} local addedTimes = {} local keylength = 0 for _, ap in ipairs(V0.Keypoints) do local closestAbove, closestBelow for _, bp in ipairs(V1.Keypoints) do if bp.Time == ap.Time then closestAbove, closestBelow = bp, bp break elseif bp.Time < ap.Time and (closestBelow == nil or bp.Time > closestBelow.Time) then closestBelow = bp elseif bp.Time > ap.Time and (closestAbove == nil or bp.Time < closestAbove.Time) then closestAbove = bp end end local bValue if closestAbove == closestBelow then bValue = closestAbove.Value else bValue = Color3Lerp(closestBelow.Value, closestAbove.Value)((ap.Time - closestBelow.Time) / (closestAbove.Time - closestBelow.Time)) end keylength += 1 keypoints[keylength] = ColorSequenceKeypoint.new(ap.Time, Color3Lerp(ap.Value, bValue)(Alpha)) addedTimes[ap.Time] = true end for _, bp in ipairs(V1.Keypoints) do if not addedTimes[bp.Time] then local closestAbove, closestBelow for _, ap in ipairs(V0.Keypoints) do if ap.Time == bp.Time then closestAbove, closestBelow = ap, ap break elseif ap.Time < bp.Time and (closestBelow == nil or ap.Time > closestBelow.Time) then closestBelow = ap elseif ap.Time > bp.Time and (closestAbove == nil or ap.Time < closestAbove.Time) then closestAbove = ap end end local aValue if closestAbove == closestBelow then aValue = closestAbove.Value else aValue = Color3Lerp(closestBelow.Value, closestAbove.Value)((bp.Time - closestBelow.Time) / (closestAbove.Time - closestBelow.Time)) end keylength += 1 keypoints[keylength] = ColorSequenceKeypoint.new(bp.Time, Color3Lerp(bp.Value, aValue)(Alpha)) end end table.sort(keypoints, SortByTime) return ColorSequence.new(keypoints) end end; }, { __index = function(_, Index) error("No lerp function is defined for type " .. tostring(Index) .. ".", 4) end; __newindex = function(_, Index) error("No lerp function is defined for type " .. tostring(Index) .. ".", 4) end; }) local function RevBack(T) T = 1 - T return 1 - (math.sin(T * 1.5707963267949) + (math.sin(T * 3.1415926535898) * (math.cos(T * 3.1415926535898) + 1) / 2)) end local function Linear(T) return T end -- @specs https://material.io/guidelines/motion/duration-easing.html#duration-easing-natural-easing-curves local Sharp = Bezier(0.4, 0, 0.6, 1) local Standard = Bezier(0.4, 0, 0.2, 1) -- used for moving. local Acceleration = Bezier(0.4, 0, 1, 1) -- used for exiting. local Deceleration = Bezier(0, 0, 0.2, 1) -- used for entering. -- @specs https://developer.microsoft.com/en-us/fabric#/styles/web/motion#basic-animations local FabricStandard = Bezier(0.8, 0, 0.2, 1) -- used for moving. local FabricAccelerate = Bezier(0.9, 0.1, 1, 0.2) -- used for exiting. local FabricDecelerate = Bezier(0.1, 0.9, 0.2, 1) -- used for entering. -- @specs https://docs.microsoft.com/en-us/windows/uwp/design/motion/timing-and-easing local UWPAccelerate = Bezier(0.7, 0, 1, 0.5) -- @specs https://www.ibm.com/design/language/elements/motion/basics -- Productivity and Expression are both essential to an interface. Reserve Expressive motion for occasional, important moments to better capture user’s attention, and offer rhythmic break to the productive experience. -- Use standard-easing when an element is visible from the beginning to end of a motion. Tiles expanding and table rows sorting are good examples. local StandardProductive = Bezier(0.2, 0, 0.38, 0.9) local StandardExpressive = Bezier(0.4, 0.14, 0.3, 1) -- Use entrance-easing when adding elements to the view such as a modal or toaster appearing, or moving in response to users’ input, such as dropdown opening or toggle. An element quickly appears and slows down to a stop. local EntranceProductive = Bezier(0, 0, 0.38, 0.9) local EntranceExpressive = Bezier(0, 0, 0.3, 1) -- Use exit-easing when removing elements from view, such as closing a modal or toaster. The element speeds up as it exits from view, implying that its departure from the screen is permanent. local ExitProductive = Bezier(0.2, 0, 1, 0.9) local ExitExpressive = Bezier(0.4, 0.14, 1, 1) -- @specs https://design.firefox.com/photon/motion/duration-and-easing.html local MozillaCurve = Bezier(0.07, 0.95, 0, 1) local function Smooth(T) return T * T * (3 - 2 * T) end local function Smoother(T) return T * T * T * (T * (6 * T - 15) + 10) end local function RidiculousWiggle(T) return math.sin(math.sin(T * 3.1415926535898) * 1.5707963267949) end local function Spring(T) return 1 + (-math.exp(-6.9 * T) * math.cos(-20.106192982975 * T)) end local function SoftSpring(T) return 1 + (-math.exp(-7.5 * T) * math.cos(-10.053096491487 * T)) end local function OutBounce(T) if T < 0.36363636363636 then return 7.5625 * T * T elseif T < 0.72727272727273 then return 3 + T * (11 * T - 12) * 0.6875 elseif T < 0.090909090909091 then return 6 + T * (11 * T - 18) * 0.6875 else return 7.875 + T * (11 * T - 21) * 0.6875 end end local function InBounce(T) if T > 0.63636363636364 then T -= 1 return 1 - T * T * 7.5625 elseif T > 0.272727272727273 then return (11 * T - 7) * (11 * T - 3) / -16 elseif T > 0.090909090909091 then return (11 * (4 - 11 * T) * T - 3) / 16 else return T * (11 * T - 1) * -0.6875 end end local EasingFunctions = setmetatable({ InLinear = Linear; OutLinear = Linear; InOutLinear = Linear; OutInLinear = Linear; OutSmooth = Smooth; InSmooth = Smooth; InOutSmooth = Smooth; OutInSmooth = Smooth; OutSmoother = Smoother; InSmoother = Smoother; InOutSmoother = Smoother; OutInSmoother = Smoother; OutRidiculousWiggle = RidiculousWiggle; InRidiculousWiggle = RidiculousWiggle; InOutRidiculousWiggle = RidiculousWiggle; OutInRidiculousWiggle = RidiculousWiggle; OutRevBack = RevBack; InRevBack = RevBack; InOutRevBack = RevBack; OutInRevBack = RevBack; OutSpring = Spring; InSpring = Spring; InOutSpring = Spring; OutInSpring = Spring; OutSoftSpring = SoftSpring; InSoftSpring = SoftSpring; InOutSoftSpring = SoftSpring; OutInSoftSpring = SoftSpring; InSharp = Sharp; InOutSharp = Sharp; OutSharp = Sharp; OutInSharp = Sharp; InAcceleration = Acceleration; InOutAcceleration = Acceleration; OutAcceleration = Acceleration; OutInAcceleration = Acceleration; InStandard = Standard; InOutStandard = Standard; OutStandard = Standard; OutInStandard = Standard; InDeceleration = Deceleration; InOutDeceleration = Deceleration; OutDeceleration = Deceleration; OutInDeceleration = Deceleration; InFabricStandard = FabricStandard; InOutFabricStandard = FabricStandard; OutFabricStandard = FabricStandard; OutInFabricStandard = FabricStandard; InFabricAccelerate = FabricAccelerate; InOutFabricAccelerate = FabricAccelerate; OutFabricAccelerate = FabricAccelerate; OutInFabricAccelerate = FabricAccelerate; InFabricDecelerate = FabricDecelerate; InOutFabricDecelerate = FabricDecelerate; OutFabricDecelerate = FabricDecelerate; OutInFabricDecelerate = FabricDecelerate; InUWPAccelerate = UWPAccelerate; InOutUWPAccelerate = UWPAccelerate; OutUWPAccelerate = UWPAccelerate; OutInUWPAccelerate = UWPAccelerate; InStandardProductive = StandardProductive; InStandardExpressive = StandardExpressive; InEntranceProductive = EntranceProductive; InEntranceExpressive = EntranceExpressive; InExitProductive = ExitProductive; InExitExpressive = ExitExpressive; OutStandardProductive = StandardProductive; OutStandardExpressive = StandardExpressive; OutEntranceProductive = EntranceProductive; OutEntranceExpressive = EntranceExpressive; OutExitProductive = ExitProductive; OutExitExpressive = ExitExpressive; InOutStandardProductive = StandardProductive; InOutStandardExpressive = StandardExpressive; InOutEntranceProductive = EntranceProductive; InOutEntranceExpressive = EntranceExpressive; InOutExitProductive = ExitProductive; InOutExitExpressive = ExitExpressive; OutInStandardProductive = StandardProductive; OutInStandardExpressive = StandardProductive; OutInEntranceProductive = EntranceProductive; OutInEntranceExpressive = EntranceExpressive; OutInExitProductive = ExitProductive; OutInExitExpressive = ExitExpressive; OutMozillaCurve = MozillaCurve; InMozillaCurve = MozillaCurve; InOutMozillaCurve = MozillaCurve; OutInMozillaCurve = MozillaCurve; InQuad = function(T) return T * T end; OutQuad = function(T) return T * (2 - T) end; InOutQuad = function(T) if T < 0.5 then return 2 * T * T else return 2 * (2 - T) * T - 1 end end; OutInQuad = function(T) if T < 0.5 then T *= 2 return T * (2 - T) / 2 else T *= 2 - 1 return (T * T) / 2 + 0.5 end end; InCubic = function(T) return T * T * T end; OutCubic = function(T) return 1 - (1 - T) * (1 - T) * (1 - T) end; InOutCubic = function(T) if T < 0.5 then return 4 * T * T * T else T -= 1 return 1 + 4 * T * T * T end end; OutInCubic = function(T) if T < 0.5 then T = 1 - (T * 2) return (1 - T * T * T) / 2 else T *= 2 - 1 return T * T * T / 2 + 0.5 end end; InQuart = function(T) return T * T * T * T end; OutQuart = function(T) T -= 1 return 1 - T * T * T * T end; InOutQuart = function(T) if T < 0.5 then T *= T return 8 * T * T else T -= 1 return 1 - 8 * T * T * T * T end end; OutInQuart = function(T) if T < 0.5 then T *= 2 - 1 return (1 - T * T * T * T) / 2 else T *= 2 - 1 return T * T * T * T / 2 + 0.5 end end; InQuint = function(T) return T * T * T * T * T end; OutQuint = function(T) T -= 1 return T * T * T * T * T + 1 end; InOutQuint = function(T) if T < 0.5 then return 16 * T * T * T * T * T else T -= 1 return 16 * T * T * T * T * T + 1 end end; OutInQuint = function(T) if T < 0.5 then T *= 2 - 1 return (T * T * T * T * T + 1) / 2 else T *= 2 - 1 return T * T * T * T * T / 2 + 0.5 end end; InBack = function(T) return T * T * (3 * T - 2) end; OutBack = function(T) return (T - 1) * (T - 1) * (T * 2 + T - 1) + 1 end; InOutBack = function(T) if T < 0.5 then return 2 * T * T * (2 * 3 * T - 2) else return 1 + 2 * (T - 1) * (T - 1) * (2 * 3 * T - 2 - 2) end end; OutInBack = function(T) if T < 0.5 then T *= 2 return ((T - 1) * (T - 1) * (T * 2 + T - 1) + 1) / 2 else T *= 2 - 1 return T * T * (3 * T - 2) / 2 + 0.5 end end; InSine = function(T) return 1 - math.cos(T * 1.5707963267949) end; OutSine = function(T) return math.sin(T * 1.5707963267949) end; InOutSine = function(T) return (1 - math.cos(3.1415926535898 * T)) / 2 end; OutInSine = function(T) if T < 0.5 then return math.sin(T * 3.1415926535898) / 2 else return (1 - math.cos((T * 2 - 1) * 1.5707963267949)) / 2 + 0.5 end end; OutBounce = OutBounce; InBounce = InBounce; InOutBounce = function(T) if T < 0.5 then return InBounce(2 * T) / 2 else return OutBounce(2 * T - 1) / 2 + 0.5 end end; OutInBounce = function(T) if T < 0.5 then return OutBounce(2 * T) / 2 else return InBounce(2 * T - 1) / 2 + 0.5 end end; InElastic = function(T) return math.exp((T * 0.96380736418812 - 1) * 8) * T * 0.96380736418812 * math.sin(4 * T * 0.96380736418812) * 1.8752275007429 end; OutElastic = function(T) return 1 + (math.exp(8 * (0.96380736418812 - 0.96380736418812 * T - 1)) * 0.96380736418812 * (T - 1) * math.sin(4 * 0.96380736418812 * (1 - T))) * 1.8752275007429 end; InOutElastic = function(T) if T < 0.5 then return (math.exp(8 * (2 * 0.96380736418812 * T - 1)) * 0.96380736418812 * T * math.sin(2 * 4 * 0.96380736418812 * T)) * 1.8752275007429 else return 1 + (math.exp(8 * (0.96380736418812 * (2 - 2 * T) - 1)) * 0.96380736418812 * (T - 1) * math.sin(4 * 0.96380736418812 * (2 - 2 * T))) * 1.8752275007429 end end; OutInElastic = function(T) -- This isn't actually correct, but it is close enough. if T < 0.5 then T *= 2 return (1 + (math.exp(8 * (0.96380736418812 - 0.96380736418812 * T - 1)) * 0.96380736418812 * (T - 1) * math.sin(4 * 0.96380736418812 * (1 - T))) * 1.8752275007429) / 2 else T *= 2 - 1 return (math.exp((T * 0.96380736418812 - 1) * 8) * T * 0.96380736418812 * math.sin(4 * T * 0.96380736418812) * 1.8752275007429) / 2 + 0.5 end end; InExpo = function(T) return T * T * math.exp(4 * (T - 1)) end; OutExpo = function(T) return 1 - (1 - T) * (1 - T) / math.exp(4 * T) end; InOutExpo = function(T) if T < 0.5 then return 2 * T * T * math.exp(4 * (2 * T - 1)) else return 1 - 2 * (T - 1) * (T - 1) * math.exp(4 * (1 - 2 * T)) end end; OutInExpo = function(T) if T < 0.5 then T *= 2 return (1 - (1 - T) * (1 - T) / math.exp(4 * T)) / 2 else T *= 2 - 1 return (T * T * math.exp(4 * (T - 1))) / 2 + 0.5 end end; InCirc = function(T) return -(math.sqrt(1 - T * T) - 1) end; OutCirc = function(T) T -= 1 return math.sqrt(1 - T * T) end; InOutCirc = function(T) T *= 2 if T < 1 then return -(math.sqrt(1 - T * T) - 1) / 2 else T -= 2 return (math.sqrt(1 - T * T) - 1) / 2 end end; OutInCirc = function(T) if T < 0.5 then T *= 2 - 1 return math.sqrt(1 - T * T) / 2 else T *= 2 - 1 return (-(math.sqrt(1 - T * T) - 1)) / 2 + 0.5 end end; }, { __index = function(_, Index) error(tostring(Index) .. " is not a valid easing function.", 2) end; }) local RunService = game:GetService("RunService") local RawTweenFunctions = EasingFunctions local TypeLerpers = Lerps local Heartbeat = RunService.Heartbeat local BoatTween = {} local ValidStepTypes = { ["Heartbeat"] = true; ["Stepped"] = true; ["RenderStepped"] = true; } if not RunService:IsClient() then ValidStepTypes.RenderStepped = nil end local TweenFunctions = { FabricAccelerate = { In = RawTweenFunctions.InFabricAccelerate; Out = RawTweenFunctions.OutFabricAccelerate; InOut = RawTweenFunctions.InOutFabricAccelerate; OutIn = RawTweenFunctions.OutInFabricAccelerate; }; UWPAccelerate = { In = RawTweenFunctions.InUWPAccelerate; Out = RawTweenFunctions.OutUWPAccelerate; InOut = RawTweenFunctions.InOutUWPAccelerate; OutIn = RawTweenFunctions.OutInUWPAccelerate; }; Circ = { In = RawTweenFunctions.InCirc; Out = RawTweenFunctions.OutCirc; InOut = RawTweenFunctions.InOutCirc; OutIn = RawTweenFunctions.OutInCirc; }; RevBack = { In = RawTweenFunctions.InRevBack; Out = RawTweenFunctions.OutRevBack; InOut = RawTweenFunctions.InOutRevBack; OutIn = RawTweenFunctions.OutInRevBack; }; Spring = { In = RawTweenFunctions.InSpring; Out = RawTweenFunctions.OutSpring; InOut = RawTweenFunctions.InOutSpring; OutIn = RawTweenFunctions.OutInSpring; }; Standard = { In = RawTweenFunctions.InStandard; Out = RawTweenFunctions.OutStandard; InOut = RawTweenFunctions.InOutStandard; OutIn = RawTweenFunctions.OutInStandard; }; StandardExpressive = { In = RawTweenFunctions.InStandardExpressive; Out = RawTweenFunctions.OutStandardExpressive; InOut = RawTweenFunctions.InOutStandardExpressive; OutIn = RawTweenFunctions.OutInStandardExpressive; }; Linear = { In = RawTweenFunctions.InLinear; Out = RawTweenFunctions.OutLinear; InOut = RawTweenFunctions.InOutLinear; OutIn = RawTweenFunctions.OutInLinear; }; ExitProductive = { In = RawTweenFunctions.InExitProductive; Out = RawTweenFunctions.OutExitProductive; InOut = RawTweenFunctions.InOutExitProductive; OutIn = RawTweenFunctions.OutInExitProductive; }; Deceleration = { In = RawTweenFunctions.InDeceleration; Out = RawTweenFunctions.OutDeceleration; InOut = RawTweenFunctions.InOutDeceleration; OutIn = RawTweenFunctions.OutInDeceleration; }; Smoother = { In = RawTweenFunctions.InSmoother; Out = RawTweenFunctions.OutSmoother; InOut = RawTweenFunctions.InOutSmoother; OutIn = RawTweenFunctions.OutInSmoother; }; FabricStandard = { In = RawTweenFunctions.InFabricStandard; Out = RawTweenFunctions.OutFabricStandard; InOut = RawTweenFunctions.InOutFabricStandard; OutIn = RawTweenFunctions.OutInFabricStandard; }; RidiculousWiggle = { In = RawTweenFunctions.InRidiculousWiggle; Out = RawTweenFunctions.OutRidiculousWiggle; InOut = RawTweenFunctions.InOutRidiculousWiggle; OutIn = RawTweenFunctions.OutInRidiculousWiggle; }; MozillaCurve = { In = RawTweenFunctions.InMozillaCurve; Out = RawTweenFunctions.OutMozillaCurve; InOut = RawTweenFunctions.InOutMozillaCurve; OutIn = RawTweenFunctions.OutInMozillaCurve; }; Expo = { In = RawTweenFunctions.InExpo; Out = RawTweenFunctions.OutExpo; InOut = RawTweenFunctions.InOutExpo; OutIn = RawTweenFunctions.OutInExpo; }; Sine = { In = RawTweenFunctions.InSine; Out = RawTweenFunctions.OutSine; InOut = RawTweenFunctions.InOutSine; OutIn = RawTweenFunctions.OutInSine; }; Cubic = { In = RawTweenFunctions.InCubic; Out = RawTweenFunctions.OutCubic; InOut = RawTweenFunctions.InOutCubic; OutIn = RawTweenFunctions.OutInCubic; }; EntranceExpressive = { In = RawTweenFunctions.InEntranceExpressive; Out = RawTweenFunctions.OutEntranceExpressive; InOut = RawTweenFunctions.InOutEntranceExpressive; OutIn = RawTweenFunctions.OutInEntranceExpressive; }; Elastic = { In = RawTweenFunctions.InElastic; Out = RawTweenFunctions.OutElastic; InOut = RawTweenFunctions.InOutElastic; OutIn = RawTweenFunctions.OutInElastic; }; Quint = { In = RawTweenFunctions.InQuint; Out = RawTweenFunctions.OutQuint; InOut = RawTweenFunctions.InOutQuint; OutIn = RawTweenFunctions.OutInQuint; }; EntranceProductive = { In = RawTweenFunctions.InEntranceProductive; Out = RawTweenFunctions.OutEntranceProductive; InOut = RawTweenFunctions.InOutEntranceProductive; OutIn = RawTweenFunctions.OutInEntranceProductive; }; Bounce = { In = RawTweenFunctions.InBounce; Out = RawTweenFunctions.OutBounce; InOut = RawTweenFunctions.InOutBounce; OutIn = RawTweenFunctions.OutInBounce; }; Smooth = { In = RawTweenFunctions.InSmooth; Out = RawTweenFunctions.OutSmooth; InOut = RawTweenFunctions.InOutSmooth; OutIn = RawTweenFunctions.OutInSmooth; }; Back = { In = RawTweenFunctions.InBack; Out = RawTweenFunctions.OutBack; InOut = RawTweenFunctions.InOutBack; OutIn = RawTweenFunctions.OutInBack; }; Quart = { In = RawTweenFunctions.InQuart; Out = RawTweenFunctions.OutQuart; InOut = RawTweenFunctions.InOutQuart; OutIn = RawTweenFunctions.OutInQuart; }; StandardProductive = { In = RawTweenFunctions.InStandardProductive; Out = RawTweenFunctions.OutStandardProductive; InOut = RawTweenFunctions.InOutStandardProductive; OutIn = RawTweenFunctions.OutInStandardProductive; }; Quad = { In = RawTweenFunctions.InQuad; Out = RawTweenFunctions.OutQuad; InOut = RawTweenFunctions.InOutQuad; OutIn = RawTweenFunctions.OutInQuad; }; FabricDecelerate = { In = RawTweenFunctions.InFabricDecelerate; Out = RawTweenFunctions.OutFabricDecelerate; InOut = RawTweenFunctions.InOutFabricDecelerate; OutIn = RawTweenFunctions.OutInFabricDecelerate; }; Acceleration = { In = RawTweenFunctions.InAcceleration; Out = RawTweenFunctions.OutAcceleration; InOut = RawTweenFunctions.InOutAcceleration; OutIn = RawTweenFunctions.OutInAcceleration; }; SoftSpring = { In = RawTweenFunctions.InSoftSpring; Out = RawTweenFunctions.OutSoftSpring; InOut = RawTweenFunctions.InOutSoftSpring; OutIn = RawTweenFunctions.OutInSoftSpring; }; ExitExpressive = { In = RawTweenFunctions.InExitExpressive; Out = RawTweenFunctions.OutExitExpressive; InOut = RawTweenFunctions.InOutExitExpressive; OutIn = RawTweenFunctions.OutInExitExpressive; }; Sharp = { In = RawTweenFunctions.InSharp; Out = RawTweenFunctions.OutSharp; InOut = RawTweenFunctions.InOutSharp; OutIn = RawTweenFunctions.OutInSharp; }; } local function Wait(Seconds) Seconds = math.max(Seconds or 0.03, 0) local TimeRemaining = Seconds while TimeRemaining > 0 do TimeRemaining -= Heartbeat:Wait() end return Seconds - TimeRemaining end function BoatTween.Create(_, Object, Data) -- Validate if not Object or typeof(Object) ~= "Instance" then return warn("Invalid object to tween:", Object) end Data = type(Data) == "table" and Data or {} -- Define settings local EventStep: RBXScriptSignal = ValidStepTypes[Data.StepType] and RunService[Data.StepType] or RunService.Stepped local TweenFunction = TweenFunctions[Data.EasingStyle or "Quad"][Data.EasingDirection or "In"] local Time = math.max(type(Data.Time) == "number" and Data.Time or 1, 0.001) local Goal = type(Data.Goal) == "table" and Data.Goal or {} local DelayTime = type(Data.DelayTime) == "number" and Data.DelayTime > 0.027 and Data.DelayTime local RepeatCount = (type(Data.RepeatCount) == "number" and math.max(Data.RepeatCount, -1) or 0) + 1 local TweenData = {} for Property, EndValue in pairs(Goal) do TweenData[Property] = TypeLerpers[typeof(EndValue)](Object[Property], EndValue) end -- Create instances local CompletedEvent = Instance.new("BindableEvent") local StoppedEvent = Instance.new("BindableEvent") local ResumedEvent = Instance.new("BindableEvent") local PlaybackConnection local StartTime, ElapsedTime = os.clock(), 0 local TweenObject = { ["Instance"] = Object; ["PlaybackState"] = Enum.PlaybackState.Begin; ["Completed"] = CompletedEvent.Event; ["Resumed"] = ResumedEvent.Event; ["Stopped"] = StoppedEvent.Event; } function TweenObject.Destroy() if PlaybackConnection then PlaybackConnection:Disconnect() PlaybackConnection = nil end CompletedEvent:Destroy() StoppedEvent:Destroy() ResumedEvent:Destroy() TweenObject = nil end local CurrentlyReversing = false local CurrentLayer = 0 local function Play(Layer, Reverse) if PlaybackConnection then PlaybackConnection:Disconnect() PlaybackConnection = nil end Layer = Layer or 1 if RepeatCount ~= 0 then if Layer > RepeatCount then TweenObject.PlaybackState = Enum.PlaybackState.Completed CompletedEvent:Fire() CurrentlyReversing = false CurrentLayer = 1 return end end CurrentLayer = Layer if Reverse then CurrentlyReversing = true end if DelayTime then TweenObject.PlaybackState = Enum.PlaybackState.Delayed; (DelayTime < 2 and Wait or wait)(DelayTime) end StartTime = os.clock() - ElapsedTime PlaybackConnection = EventStep:Connect(function() ElapsedTime = os.clock() - StartTime if ElapsedTime >= Time then if Reverse then for Property, Lerper in pairs(TweenData) do Object[Property] = Lerper(0) end else for Property, Lerper in pairs(TweenData) do Object[Property] = Lerper(1) end end PlaybackConnection:Disconnect() PlaybackConnection = nil if Reverse then ElapsedTime = 0 Play(Layer + 1, false) else if Data.Reverses then ElapsedTime = 0 Play(Layer, true) else ElapsedTime = 0 Play(Layer + 1, false) end end else local Delta = Reverse and (1 - ElapsedTime/Time) or (ElapsedTime/Time) local Position = math.clamp(TweenFunction(Delta), 0, 1) for Property, Lerper in pairs(TweenData) do Object[Property] = Lerper(Position) end end end) TweenObject.PlaybackState = Enum.PlaybackState.Playing end function TweenObject.Play() ElapsedTime = 0 Play(1, false) end function TweenObject.Stop() if PlaybackConnection then PlaybackConnection:Disconnect() PlaybackConnection = nil TweenObject.PlaybackState = Enum.PlaybackState.Cancelled StoppedEvent:Fire() end end function TweenObject.Resume() Play(CurrentLayer, CurrentlyReversing) ResumedEvent:Fire() end return TweenObject end return BoatTween
Editor Settings
Theme
Key bindings
Full width
Lines