Hey y’all!
Before we start on this wonderful tutorial, I just wanted to say...
Fun fact: tomorrow’s Cinco de Mayo, what a wonderful collection of special days!
Today’s obviously Star Wars Day, the famous date May the Fourth is here!
Anyways, this tutorial is dedicated to teaching you about some satisfying gradient animations (among which is a rainbow all the at the end, don’t skip there!).
For all of these animations, we’ll be tweening the gradient’s offset via the TweenService.
I apologize, in advance, for the low GIF FPS.
Shine
- Set up your Color Sequence with the start and finish with the primary color (pink) and the very middle with a lighter counterpart of the primary color (light pink). In addition, set the rotation to something slanted to make the shine look better, something like 45 degrees is perfect.
In a Local Script, we’ll tween the offset to make it look like the middle light part is going from left to right.
- Start off by declaring some variables.
local button = script.Parent
local gradient = button.UIGradient
local ts = game:GetService("TweenService")
local ti = TweenInfo.new(1, Enum.EasingStyle.Circular, Enum.EasingDirection.Out)
local offset1 = {Offset = Vector2.new(1, 0)}
local create = ts:Create(gradient, ti, offset1)
local startingPos = Vector2.new(-1, 0) --start on the right, tween to the left so it looks like the shine went from left to right
local addWait = 2.5 --the amount of seconds between each couplet of shines
- Add a recursive function after resetting the offset of the gradient:
gradient.Offset = startingPos
local function animate()
create:Play()
create.Completed:Wait() --wait for tween to stop
gradient.Offset = startingPos --reset offset
create:Play() --play again (I did this only 2 times per "couplet", you can do it more times if you want)
create.Completed:Wait()
gradient.Offset = startingPos
wait(addWait) --wait some bit before the next couplet
animate() --call itself to make this into a loop
end
animate() --but we still need to initially call it
And that is it! The shine gradient animations is compelted! That was the easiest of them all.
Hover
Because the GIF’s so laggy, I’ll explain what’s going on here. So, when I hover over a button the solid color button switches to a gradient. Upon leaving, it tweens to the opposite side to a different color. So, the button is now a new color. And it tweens back after hovering over and then leaving the button.
-
Just create Color Sequence with at least 3 different colors (2 is fine, but it’s better with 3). I did yellow, green, blue.
-
Again, declare our variable.
local button = script.Parent
local gradient = button.UIGradient
local ts = game:GetService("TweenService")
local ti = TweenInfo.new(1, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out)
local s, kpt, ran = ColorSequence.new, ColorSequenceKeypoint.new, math.random
local offset1 = {Offset = Vector2.new(0, 0)} --hover in, so that the gradient is visible
local offset2 = {Offset = Vector2.new(-1, 0)} --hover out, but to one side
local offset3 = {Offset = Vector2.new(1, 0)} --hover out, but to another side
local create1 = ts:Create(gradient, ti, offset1)
local create2 = ts:Create(gradient, ti, offset2)
local create3 = ts:Create(gradient, ti, offset3)
local startPos = Vector2.new(-1, 0) --start off in a solid color
local hover = 1 --used to indicate which offset value it will tween to to get a different color upon the mouse leaving the button
--[[
We'll use modulus with the "hover" variable to check if the number is even or odd,
if even then tween to one side, else tween to the other
]]
- Add in the functions connected to the
MouseEnter
andMouseLeave
events.
button.MouseEnter:Connect(function()
create1:Play() --tween to the middle/the area with the gradient
end)
button.MouseLeave:Connect(function()
--[[if even, then tween to the right, else, tween to the left]]
if hover % 2 == 0 then create2:Play() else create3:Play() end
hover = hover + 1 --increase hover to switch hover out colors
end)
And we’re done with this 2nd easiest gradient animation!
Hover Stay
-
For this animation, you literally just need two colors in the Color Sequence.
-
Again, declare some variables, first:
local button = script.Parent
local gradient = button.UIGradient
local ts = game:GetService("TweenService")
local ti = TweenInfo.new(2.5, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
local offset1 = {Offset = Vector2.new(-1, 0)}
local create1 = ts:Create(gradient, ti, offset1)
local startPos = Vector2.new(1, 0)
local rot = 180 --starting gradient rotation
This is why we’re using the gradient’s rotation: when we stay hovering over the button, the gradient will eventually move to a solid color. And that’s the moment when we flip the rotation, either 180 or 0, so that the color we just passed to reach this solid color will be right after. Then, we repeat this with the other color.
- Reset the rotation and offset and create the hover in function:
gradient.Offset = startPos
gradient.Rotation = 0
button.MouseEnter:Connect(function()
button.BorderSizePixel = 2 --just to show that the mouse is currently in
create1:Play()
end)
- Now, we need to create the function that actually runs this animation when the previous tween has been completed:
local function completed()
--border size pixel comming in handy because we only animate the gradient when the mouse is hovering over
if button.BorderSizePixel == 2 and rot == 0 then
gradient.Rotation = 180
gradient.Offset = startPos
create1:Play()
elseif button.BorderSizePixel == 2 and rot == 180 then --this will be run first
gradient.Rotation = 0
gradient.Offset = startPos
create1:Play()
end
end
- We need to run the function above initially with an event and also need to end off by including the
MouseLeave
event:
create1.Completed:Connect(function()
--flip rotation
if rot == 0 then rot = 180 elseif rot == 180 then rot = 0 end
completed()
end)
button.MouseLeave:Connect(function()
button.BorderSizePixel = 3 --some different value to indicate that button is not being hovered over
create1:Pause() --pause the tween right there, and it will be played from there when tween:Play() is called
end)
Finally, we’re done with this part. Now, onto…
[color=red]R[/color][color=orange]A[/color][color=yellow]I[/color][color=green]N[/color][color=cyan]B[/color][color=blue]O[/color][color=purple]W[/color]!
There are several ways to create a rainbow, but after a lot of experimenting, I finally reached the result that was the most fluent and where the colors blended together very well.
Plan of Action:
We’ll do the rotation flipping as we did with the hover stay animation. There are going to be 3 key points, so it will be a little more difficult to code than 2 key points, but the result is better! We need to include many if statements because we’ll be using a table with random color values, but indexing with a number greater than the number of elements spits out an error. Believe me, I tried to optimize the script as much as possible, but this is the shortest I got it to. Also, the main reason it’s long is that it’s a little repetitive (which I also tried to solve, but I’m unsuccessful), which is why I’ll leave out comments for the later parts. With that being said, let’s begin:
-
Of course, start with a gradient consisting of 3 key points.
-
Variable declaration:
local button = script.Parent
local gradient = button.UIGradient
local ts = game:GetService("TweenService")
local ti = TweenInfo.new(1, Enum.EasingStyle.Linear, Enum.EasingDirection.Out)
local offset = {Offset = Vector2.new(1, 0)}
local create = ts:Create(gradient, ti, offset)
local startingPos = Vector2.new(-1, 0)
local list = {} --list of random colors (we'll be generating them shortly after)
local s, kpt = ColorSequence.new, ColorSequenceKeypoint.new
local counter = 0 --count the last table index we just indexed/last gradient color reference
local status = "down" --[[there will be two groups of if statements (one above and one below).
It glitches out some times and runs the same group multiple times, so we need this. ]]
- Initialization (random colors creation, setup of the gradient, etc.):
gradient.Offset = startingPos --reset the offset of the gradient
local function rainbowColors()
--[[HSV uses values 0-1, but we'll use until 255 and divide later to
better control the colors.]]
local sat, val = 255, 255
for i = 1, 15 do --15 is a multiple of 255
local hue = i * 17 --255/15 = 17
table.insert(list, Color3.fromHSV(hue / 255, sat / 255, val / 255)) --divide by 255 to be in range of 0-1
end
end
rainbowColors() --add to the list table
--set up the first gradient
gradient.Color = s({
kpt(0, list[#list]),
kpt(0.5, list[#list - 1]),
kpt(1, list[#list - 2])
})
counter = #list --max indexed is #list, which is 10 in this instance
- Now, onto the repetitive, but rather a simple part:
local function animate()
create:Play()
create.Completed:Wait() --wait for tween completion
gradient.Offset = startingPos
gradient.Rotation = 180 --flip time!
--[[#list - 1 because we have 3 key points, 1 will be preserved from
the previous tween, while the other 2 are new. We need to make
sure that indexing something beyond #list doesn't happen as it will
throw an error. In this instance, it will be 9, 10, and instead of it looking
for 11, it will go back to 1.]]
if counter == #list - 1 and status == "down" then
gradient.Color = s({
kpt(0, gradient.Color.Keypoints[1].Value), --preserve previous color, which we'll be able to see
kpt(0.5, list[#list]), --change this color behind the scenes!
kpt(1, list[1]) --change this color behind the scenes!
})
counter = 1 --last index is 1 i.e. list[1]
status = "up" --the upper section already ran, time for the lower!
elseif counter == #list and status == "down" then --if the current counter is exactly 10 (in this instance), then it will go back to 1 and 2
gradient.Color = s({
kpt(0, gradient.Color.Keypoints[1].Value),
kpt(0.5, list[1]),
kpt(1, list[2])
})
counter = 2
status = "up"
elseif counter <= #list - 2 and status == "down" then --in all other cases, when couter is 1-8
gradient.Color = s({
kpt(0, gradient.Color.Keypoints[1].Value),
kpt(0.5, list[counter + 1]), --one color over
kpt(1, list[counter + 2]) --two colors over
})
counter = counter + 2
status = "up"
end
create:Play()
create.Completed:Wait()
gradient.Offset = startingPos
gradient.Rotation = 0 --flip time again!
if counter == #list - 1 and status == "up" then --same as before, really, but instead of "down", it's "up", since the upper section already ran
gradient.Color = s({
--descending order because now it's rotation 0
kpt(0, list[1]), --1
kpt(0.5, list[#list]), --10
kpt(1, gradient.Color.Keypoints[3].Value) --put this at #3 because we just flipped rotation, so this color will be at the opposite side
})
counter = 1
status = "down" --below section already ran, back to the top!
elseif counter == #list and status == "up" then
gradient.Color = s({
kpt(0, list[2]), --2
kpt(0.5, list[1]), --1
kpt(1, gradient.Color.Keypoints[3].Value) --10
})
counter = 2
status = "down"
elseif counter <= #list - 2 and status == "up" then --in all other cases like before
gradient.Color = s({
kpt(0, list[counter + 2]),
kpt(0.5, list[counter + 1]),
kpt(1, gradient.Color.Keypoints[3].Value)
})
counter = counter + 2
status = "down"
end
animate() --call the function inside of itself, so that it runs indefinitely
end
animate() --call the function initially
Congrats! You just coded one of the most difficult UIGradient animations. If you have any tips to shortern my code, then feel free to share via DM.
Closing Remarks
Download the .RBXM file that is a StarterGui of all the gradient animations discussed in this tutorial and upload it under ScreenGui. Note: code is uncommented.
GradientAnimations.rbxm (8.7 KB)
Please give your feedback, too:
From a scale of 1-10, how useful is this to you and your game/future game? 1 being you’re never going to use these, 10 being you’re 100% thinking about doing so! All of these animations are meant to be applied to GUI buttons to emphasize and style them.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
0 voters
Did you learn anything new? Any new animation, any new way of coding, even the Tween Service, anything.
- Yes
- No
0 voters
May the Fourth be with you,
and have a colorful day!