How to automate repetitive UI animations

How to automate your UI animations.

To all my fellow scripters, how annoying is it, retyping the same tween animations over and over again? I know how tiresome it can be, and that is why I have sought out a solution! Let me alleviate your carpal tunnel.

What we will be going over in this tutorial:

  1. UI Hierarchy
  2. Naming UI Elements
  3. Scripting and Explanation

Right! Let’s get started.

UI Hierarchy

Your Explorer should look something like this, with your script in the same ledge as your frames:


As you can see, every frame is numbered in the order that they will animate in. For this tutorial we shall by using the “Continue” button as it is repeated multiple times. This is an example of where we can reuse code to make our work more efficient.

Optimising code is always a good idea, even when you’re the only developer on it.

For UI elements, we should use a LocalScript.


This is actually a really simple script to understand and I’ll explain it to you line by line.

base_string = "Frame"
-- This is outside our main code. What it's doing is telling us what the base name
-- for our frame is. So if I were to change "Frame1" and "Frame2" and so on to
-- something like "Help1" and "Help2", I should change this variable to "Help"
for i, v in pairs(script.Parent:GetChildren()) do
-- We are getting a list of all objects inside the main frame, so that would be
-- Frame1, Frame2, Frame3 and so forth.
for i, q in pairs(v:GetChildren()) do
-- We're now making a list of each item inside the individual frames. So q could
-- either be "Continue" or "CedarClass". 
if q.Name == "Continue" then
-- Just making sure that we're focusing on the Continue buttons only.
local file = v.Name
local index = nil
-- Now we're getting the actual FRAME name, so we use "v", which was our table for
-- the frame elements. This allows us to find which frame we're moving to next.
-- For now, the variable index is worthless and will be explained later.
for digit in string.gmatch(file, "%d") do
	index = digit
-- This uses a string function to check for any NUMBERS inside our Frame name (file).
-- The %d is a way of checking for digits only.
-- It then assigns the variable index to digit, so it tells us what frame the button
-- is on.
if tonumber(index) >= 7 then
    warn("This is the last frame.")
-- Set the number to the amount of frames you have. This will just let you know to end
-- the animation there. This step is OPTIONAL.
	local frame_current = base_string..index
	local index_added = index + 1
	local new_frame = base_string..index_added
	print(frame_current.." is moving to "..new_frame)
	script.Parent:WaitForChild(new_frame):TweenPosition(, 0, 0, 0))
-- I'm going to go through this line by line. Since "q" has been confirmed to be our
-- continue button, we can listen for a click through this event. Once our Continue
-- button has been clicked, it executes the code below.
-- Frame_Current is adding our index to "Frame", so if index = 7, it would become
-- Frame7. This allows us to identify what frame we are on AT THE PRESENT TIME.
-- Index_Added just adds 1 to the index value, allowing us to see what the next frame
-- in line will be.
-- New_Frame does the same as Frame_Current but adds one to the number at the end.
-- The print statement just confirms the movement.
-- Then, assuming that you set the script hierarchy correctly, by going to the
-- parent of the script, you're going to the top element, letting you search
-- from there. The script then searches for the element using the 
-- previously defined New_Frame variable, and tweens it to the middle of the
-- player's view!

And there you have it! A fully automated tween handler that can handle an infinite amount of repeating animations without needing you to type it out fully! I hope this was of help, and if you have any questions, please comment below.

– kyrodev

1 Like

While this method works, it will be problematic when there are a lot of UI objects applying the same animation. The iteration here has linear time complexity. This means that the more iteration it requires, the longer the time it needs to finish the task.

When optimizing, we should indeed be looking for an optimal solution that is not too complex. However, we should also ensure that it will not have other severe edge cases that may affect the performance of the code. This solution is good and simple, but the edge case it brings can be severe when brought into larger-scale production.

Anyway, here is what I would do:

If the objects you are working with will have the same animation and has a similar appearance, try making the object into a component, which can be created by using a module. Then, inside the module, connect the events and play the animation when needed.

This saves a lot of time and ensures the performance of the code, even on a larger scale.


In the UI example, this is multiple different looking buttons that just act by moving to the next frame, so by naming them the same and applying the same usage, I’m reducing the amount of lines and if I’m not mistaken, less events to listen for (correct me if I’m wrong!)

It’s the same amount of events.

Ah I see. If possible, could you demonstrate how this could be better optimised? It would help a lot with my upcoming project!