How to make Moving Gradient

One smoother option is that you could manually calculate the color of each keypoint every frame, which is complex but probably not a bad solution. Here’s a working implementation (sorry formatting is a little stuffed up mb):

local colors = {
    BrickColor.new("Bright red").Color,
    BrickColor.new("Bright orange").Color,
    BrickColor.new("Bright yellow").Color,
    BrickColor.new("Bright green").Color,
    BrickColor.new("Bright blue").Color,
    BrickColor.new("Royal purple").Color
}

local num_colors = #colors
local color_length = 1 / num_colors
local period = 3 -- how long it takes for full animation

game:GetService("RunService").RenderStepped:Connect(function()
   local progress = (tick() % period) / period -- ranges from 0 to 1 based on progress
   local newColors = {}
	local wrapColor = false -- the color at the edges
	
	for i = 1, num_colors + 1 do -- add 1 for extra edge
	    local color = colors[i] or colors[i-num_colors] -- accounting for +1
        local position = progress + (i-1)/num_colors -- the current color's position

		if position > 1 then position = position - 1 end -- wrap positions
		if position == 0 or position == 1 then wrapColor = true end -- the color is at edge
		
		table.insert(newColors, ColorSequenceKeypoint.new(position, color))
   end

	if not wrapColor then -- if there were no clean matches on the edge
		local indexProgress = ((1 - progress) / color_length) + 1
		local col1 = colors[math.floor(indexProgress)]
		local col2 = colors[math.ceil(indexProgress)] or colors[1]
		local finalCol = col1:Lerp(col2, indexProgress % 1) -- find the color between these two cols
		
		table.insert(newColors, ColorSequenceKeypoint.new(0, finalCol))
		table.insert(newColors, ColorSequenceKeypoint.new(1, finalCol))
	end
	
	table.sort(newColors, function(a, b)
		return a.Time < b.Time
	end)
	
	script.Parent.Frame.UIGradient.Color = ColorSequence.new(newColors)
end)

Alternatively, if you’re tweening a frame background and not text itself, you could treat this like the infinitely scrolling background image problem (example How to make moving background scroll infinitely?). The solution here is to tween both of the gradient frames in one direction, then reset their positions and repeat.

local frame1, frame2
local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Linear)
local tween1 = game:GetService('TweenService'):Create(frame1, tweenInfo, {Position = UDim2.new(1, 0, 0, 0})
local tween2 = game:GetService('TweenService'):Create(frame2, tweenInfo, {Position = UDim2.new(0, 0, 0, 0})
tween1.Completed:Connect(function()
   tween2:Cancel() -- make sure the other tween isn't running
   frame1.Position = UDim2.new(0, 0, 0, 0)
   frame2.Position = UDim2.new(-1, 0, 0, 0)
   tween1:Play()
   tween2:Play()
end)
frame1.Position = UDim2.new(0, 0, 0, 0)
frame2.Position = UDim2.new(-1, 0, 0, 0)
tween1:Play()
tween2:Play()

In this example, frame1 is the default frame you see at the start of the animation, and frame2 is to the left of it, hidden by the ClipDescendants property. Both tween to the right, and then when the animation is done it resets their positions to the default positions and tweens them to the right again.

13 Likes