UI Animations

In animation, tweening is the process of generating intermediate frames between two key points in a sequence. When designing a user interface, you can use tweening to transition a GuiObject smoothly from one state to another, such as:

  • Smoothly increasing the size of a button when a user selects it.
  • Sliding UI menus in and out from the screen edges.
  • Gradually animating a health bar between two widths when a user receives a health boost.

Single-Property Tweens

Position

To tween the position of a GuiObject:

  1. Set the AnchorPoint for the object.
  2. Determine UDim2 coordinates for the object's target position, using the scale parameters of UDim2 instead of exact pixel values so that the object tweens to the exact center of the screen.
  3. Pass a TweenInfo and the target position to TweenService:Create().
  4. Play the tween with Tween.Play.

The following code snippet moves an ImageLabel within a ScreenGui to the exact center of the screen:

UI Tween - Position

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8object.AnchorPoint = Vector2.new(0.5, 0.5)
9
10local targetPosition = UDim2.new(0.5, 0, 0.5, 0)
11
12local tweenInfo = TweenInfo.new(2)
13local tween = TweenService:Create(object, tweenInfo, {Position = targetPosition})
14
15tween:Play()
16

Size

To tween the size of a GuiObject:

  1. Determine UDim2 coordinates for the object's target size, using the scale parameters of UDim2 instead of exact pixel values so that the object tweens to a relative percentage of the screen size.
  2. Attach a UIAspectRatioConstraint to the object to maintain its designed aspect ratio when tweening.
  3. Pass a TweenInfo and the target size to TweenService:Create().
  4. Play the tween with Tween.Play.

The following code snippet scales an ImageLabel within a ScreenGui to 40% of the screen width or height (whichever is smaller) from the object's center anchor point:

UI Tween - Size

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8object.AnchorPoint = Vector2.new(0.5, 0.5)
9
10local aspectRatioConstraint = Instance.new("UIAspectRatioConstraint")
11aspectRatioConstraint.Parent = object
12
13local targetSize = UDim2.new(0.4, 0, 0.4, 0)
14
15local tweenInfo = TweenInfo.new(2)
16local tween = TweenService:Create(object, tweenInfo, {Size = targetSize})
17
18tween:Play()
19

Rotation

To tween the rotation of a GuiObject:

  1. Set the AnchorPoint for the object to rotate around.
  2. Determine the target Rotation for the object.
  3. Pass a TweenInfo and the target rotation to TweenService:Create().
  4. Play the tween with Tween.Play.
UI Tween - Size

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8object.AnchorPoint = Vector2.new(0.5, 0.5)
9
10local targetRotation = 45
11
12local tweenInfo = TweenInfo.new(2)
13local tween = TweenService:Create(object, tweenInfo, {Rotation = targetRotation})
14
15tween:Play()
16

Transparency

Multiple properties control UI transparency, depending on the object type. You can tween each of these properties individually or combined through a multi-property tween. Alternatively, you can tween an object's overall transparency by placing it inside a CanvasGroup and tweening the group's GroupTransparency.¹

¹ CanvasGroup is currently in beta and must be enabled through Studio's Beta Features by toggling on Canvas Group.

UI Tween - Image Transparency

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8local targetTransparency = 0.8
9
10local tweenInfo = TweenInfo.new(2)
11local tween = TweenService:Create(object, tweenInfo, {ImageTransparency = targetTransparency})
12
13tween:Play()
14
UI Tween - Canvas Group Transparency

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local canvasGroup = ScreenGui:WaitForChild("CanvasGroup")
7
8local targetTransparency = 0.8
9
10local tweenInfo = TweenInfo.new(2)
11local tween = TweenService:Create(canvasGroup, tweenInfo, {GroupTransparency = targetTransparency})
12
13tween:Play()
14

Color

Multiple properties control UI color, depending on the object type. You can tween each of these properties individually or combined through a multi-property tween. Alternatively, you can tween an object's overall color by placing it inside a CanvasGroup and tweening the group's GroupColor3.²

² CanvasGroup is currently in beta and must be enabled through Studio's Beta Features by toggling on Canvas Group.

UI Tween - Image Color

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8local targetColor = Color3.fromRGB(255, 0, 0)
9
10local tweenInfo = TweenInfo.new(2)
11local tween = TweenService:Create(object, tweenInfo, {ImageColor3 = targetColor})
12
13tween:Play()
14
UI Tween - Canvas Group Color

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local canvasGroup = ScreenGui:WaitForChild("CanvasGroup")
7
8local targetColor = Color3.fromRGB(255, 0, 0)
9
10local tweenInfo = TweenInfo.new(2)
11local tween = TweenService:Create(canvasGroup, tweenInfo, {GroupColor3 = targetColor})
12
13tween:Play()
14

Stroke

Multiple properties control UI borders, depending on the object type.

Alternatively, you can apply a UIStroke child and tween its thickness, color, and/or transparency.

UI Object Properties
UIStroke Color, Thickness, Transparency
UI Tween - UIStroke Color & Thickness

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("TextLabel")
7
8local stroke = Instance.new("UIStroke")
9stroke.Color = Color3.fromRGB(255, 255, 255)
10stroke.Thickness = 5
11stroke.Parent = object
12
13local targetColor = Color3.fromRGB(255, 0, 0)
14local targetThickness = 10
15
16local tweenInfo = TweenInfo.new(2)
17local tween = TweenService:Create(stroke, tweenInfo, {Color = targetColor, Thickness = targetThickness})
18
19tween:Play()
20

Multi-Property Tweens

You can combine any of the single-property tweens into more complex tweens by passing multiple target properties to TweenService:Create(), for example position + rotation or size + transparency.

UI Tween - Position & Rotation

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8object.AnchorPoint = Vector2.new(0.5, 0.5)
9
10local targetPosition = UDim2.new(0.5, 0, 0.5, 0)
11local targetRotation = 45
12
13local tweenInfo = TweenInfo.new(2)
14local tween = TweenService:Create(object, tweenInfo, {Position = targetPosition, Rotation = targetRotation})
15
16tween:Play()
17
UI Tween - Size & Transparency

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8object.AnchorPoint = Vector2.new(0.5, 0.5)
9
10local aspectRatioConstraint = Instance.new("UIAspectRatioConstraint")
11aspectRatioConstraint.Parent = object
12
13local targetSize = UDim2.new(0.4, 0, 0.4, 0)
14local targetTransparency = 0.8
15
16local tweenInfo = TweenInfo.new(2)
17local tween = TweenService:Create(object, tweenInfo, {Size = targetSize, ImageTransparency = targetTransparency})
18
19tween:Play()
20

Tween Sequences

You can chain UI animations to occur one after another by playing subsequent tweens upon the previous tween's Completed event. For example, the following script moves an object to the center of the screen, then rotates it by 45°.

UI Tween Sequence

1local TweenService = game:GetService("TweenService")
2local Players = game:GetService("Players")
3
4local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
5local ScreenGui = PlayerGui:WaitForChild("ScreenGui")
6local object = ScreenGui:WaitForChild("ImageLabel")
7
8object.AnchorPoint = Vector2.new(0.5, 0.5)
9
10local targetPosition = UDim2.new(0.5, 0, 0.5, 0)
11local targetRotation = 45
12
13local tweenInfo = TweenInfo.new(2)
14local positionTween = TweenService:Create(object, tweenInfo, {Position = targetPosition})
15local rotationTween = TweenService:Create(object, tweenInfo, {Rotation = targetRotation})
16
17-- Initially play position tween
18positionTween:Play()
19
20-- Play rotation tween upon completion of position tween
21positionTween.Completed:Connect(function()
22 rotationTween:Play()
23end)
24

Easing Options

Using the easing options of TweenInfo, you can control the easing style and direction of UI animations.

Style

EasingStyle sets the rate of interpolation from start to end. By default, easing style is set to Quad.

Style Description
Linear Moves at a constant speed.
Sine Speed is determined by a sine wave.
Quad Speed is determined by quadratic interpolation.
Cubic Similar to Quad, but starts at a lower speed.
Quart Similar to Quad, but starts at a higher speed.
Quint Similar to Quart, but starts at a higher speed.
Exponential Speed reduces very quickly as tween approaches the target.
Circular Follows a circlular arc, slowing down as tween approaches the target.
Back Slightly overshoots the target, then backs into place.
Bounce Bounces backwards multiple times after reaching the target, before eventually settling.
Elastic Moves as if attached to a rubber band, overshooting the target several times.
Easing Style - Cubic

1local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Cubic)
2local tween = TweenService:Create(object, tweenInfo, {Rotation = 45})
3

Direction

EasingDirection defines how the easing style interpolation applies to an object, with a default of Out. Note that a tween with Linear easing style is not affected, as linear interpolation is constant from start to end.

Direction Description
In The easing style applies in a forward direction.
Out The easing style applies in a reverse direction.
InOut The easing style applies forward for the first half and in reverse for the second half.
Easing Direction - InOut

1local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Cubic, Enum.EasingDirection.InOut)
2local tween = TweenService:Create(object, tweenInfo, {Rotation = 45})
3

Animating Text

You can easily enhance text-based UI, such as cutscene banners, player instructions, and prompts, with animated effects.

Typewriter Effect

The "typewriter" effect is ideal for TextLabels that tell a story, output NPC conversations, etc.

  1. Create a new ModuleScript within ReplicatedStorage.

  2. Rename the new script AnimateUI.

  3. Paste the following code into the script:

    ModuleScript - AnimateUI

    1local LocalizationService = game:GetService("LocalizationService")
    2local Players = game:GetService("Players")
    3
    4local SOURCE_LOCALE = "en"
    5local translator = nil
    6
    7local AnimateUI = {}
    8
    9function AnimateUI.loadTranslator()
    10 pcall(function()
    11 translator = LocalizationService:GetTranslatorForPlayerAsync(Players.LocalPlayer)
    12 end)
    13 if not translator then
    14 pcall(function()
    15 translator = LocalizationService:GetTranslatorForLocaleAsync(SOURCE_LOCALE)
    16 end)
    17 end
    18end
    19
    20function AnimateUI.typeWrite(guiObject, text, delayBetweenChars)
    21 guiObject.Visible = true
    22 guiObject.AutoLocalize = false
    23 local displayText = text
    24
    25 -- Translate text if possible
    26 if translator then
    27 displayText = translator:Translate(guiObject, text)
    28 end
    29
    30 -- Replace line break tags so grapheme loop will not miss those characters
    31 displayText = displayText:gsub("<br%s*/>", "\n")
    32 displayText:gsub("<[^<>]->", "")
    33
    34 -- Set translated/modified text on parent
    35 guiObject.Text = displayText
    36
    37 local index = 0
    38 for first, last in utf8.graphemes(displayText) do
    39 index = index + 1
    40 guiObject.MaxVisibleGraphemes = index
    41 wait(delayBetweenChars)
    42 end
    43end
    44
    45return AnimateUI
    46
  4. Create a TextLabel in a suitable location, such as within a ScreenGui parented to StarterGui.

  5. Insert a new LocalScript as a direct child of the label and paste in the following code. Note that each message is output by calling AnimateUI.typeWrite() with parameters for the parent object, the string to output, and the delay between characters.

    LocalScript

    1local ReplicatedStorage = game:GetService("ReplicatedStorage")
    2
    3local AnimateUI = require(ReplicatedStorage:WaitForChild("AnimateUI"))
    4
    5local label = script.Parent
    6
    7-- Load translator if game is localized
    8--AnimateUI.loadTranslator()
    9
    10local message1 = [[Beyond this door is the<br /><font size="46" color="rgb(255,50,25)">Great Zorgoth...</font> <font size="40">🗡</font>]]
    11AnimateUI.typeWrite(label, message1, 0.05)
    12
    13task.wait(1)
    14
    15local message2 = [[...who rules this dungeon <font color="rgb(255,200,50)">unchallenged!</font> <font size="30">😈</font>]]
    16AnimateUI.typeWrite(label, message2, 0.05)
    17