···11+# FadeUi
22+33+Fade UI elements in and out using `TweenService`. Automatically traverses all descendant `GuiBase` elements and tweens their transparency properties.
44+55+## Methods
66+77+### `FadeOut`
88+99+`FadeOut(ui: GuiBase, transparencyInfo: TweenInfo, waitForEnd: boolean)` → `void`
1010+1111+Fades out all descendant `GuiBase` elements of the given UI container by tweening their transparency properties to `1`.
1212+1313+Handles the following instance types:
1414+1515+- `TextLabel`, `TextButton`, `TextBox`: tweens `BackgroundTransparency` and `TextTransparency`
1616+- `ImageLabel`, `ImageButton`: tweens `BackgroundTransparency` and `ImageTransparency`
1717+- `Frame`: tweens `BackgroundTransparency`
1818+1919+#### Parameters
2020+2121+| Name | Type | Required |
2222+| ---------------- | ----------- | -------- |
2323+| ui | `GuiBase` | Yes |
2424+| transparencyInfo | `TweenInfo` | Yes |
2525+| waitForEnd | `boolean` | Yes |
2626+2727+---
2828+2929+### `FadeIn`
3030+3131+`FadeIn(ui: GuiBase, transparencyInfo: TweenInfo, waitForEnd: boolean)` → `void`
3232+3333+Fades in all descendant `GuiBase` elements of the given UI container by tweening their transparency properties to `0`.
3434+3535+Handles the following instance types:
3636+3737+- `TextLabel`, `TextButton`, `TextBox`: tweens `BackgroundTransparency` and `TextTransparency`
3838+- `ImageLabel`, `ImageButton`: tweens `BackgroundTransparency` and `ImageTransparency`
3939+- `Frame`: tweens `BackgroundTransparency`
4040+4141+#### Parameters
4242+4343+| Name | Type | Required |
4444+| ---------------- | ----------- | -------- |
4545+| ui | `GuiBase` | Yes |
4646+| transparencyInfo | `TweenInfo` | Yes |
4747+| waitForEnd | `boolean` | Yes |
+92
Docs/TweenSequence.md
···11+# TweenSequence
22+33+Play a sequence of tweens, waits, parallel tween groups, and callbacks with support for pausing and resuming mid-sequence.
44+55+## Types
66+77+### `TweenSequenceType`
88+99+```
1010+{ number | Tween | {Tween} | () -> () }
1111+```
1212+1313+A sequence is an ordered array of items. Each item is processed one at a time (except parallel groups), in the order it appears. Supported item types:
1414+1515+| Type | Behaviour |
1616+| ------------- | ----------------------------------------------------------------------------------------------- |
1717+| `number` | Waits for that many seconds before advancing. |
1818+| `Tween` | Plays the tween and waits for it to complete before advancing. |
1919+| `{Tween}` | Plays all tweens in parallel. Waits for the longest one to complete before advancing. |
2020+| `() -> ()` | Calls the function immediately and advances. No waiting. |
2121+2222+---
2323+2424+## Constructor
2525+2626+### `Create`
2727+2828+`Create(sequence: TweenSequenceType)` → `TweenSequence`
2929+3030+Creates a new `TweenSequence` from the provided sequence. Does not begin playback automatically.
3131+3232+#### Parameters
3333+3434+| Name | Type | Required |
3535+| -------- | -------------------- | -------- |
3636+| sequence | `TweenSequenceType` | Yes |
3737+3838+#### Returns
3939+4040+| Type |
4141+| --------------- |
4242+| `TweenSequence` |
4343+4444+#### Example
4545+4646+```lua
4747+local seq = TweenSequence.Create({
4848+ tweenA, -- plays tweenA, waits for completion
4949+ 1.5, -- waits 1.5 seconds
5050+ { tweenB, tweenC }, -- plays tweenB and tweenC in parallel, waits for longest
5151+ function() print("done!") end,
5252+})
5353+seq:Play()
5454+```
5555+5656+---
5757+5858+## Properties
5959+6060+### `Playing`
6161+6262+`Playing: boolean`
6363+6464+`true` while the sequence is actively running. Set to `false` when the sequence completes or is paused.
6565+6666+---
6767+6868+## Methods
6969+7070+### `Play`
7171+7272+`Play()` → `void`
7373+7474+Plays the sequence from the beginning. Each item in the sequence is processed in order.
7575+7676+---
7777+7878+### `Pause`
7979+8080+`Pause()` → `void`
8181+8282+Pauses the sequence at the current step. Any actively playing `Tween` instances at that step are also paused. The elapsed time within the current step is retained for use by [`Resume`](#resume).
8383+8484+---
8585+8686+### `Resume`
8787+8888+`Resume()` → `void`
8989+9090+Resumes the sequence from where it was paused. Completes the remaining duration of the current step (accounting for elapsed time) before advancing to subsequent steps.
9191+9292+Does nothing if the sequence is already playing or has not been started.
+55
Modules/FadeUi.luau
···11+--!optimize 2
22+--!strict
33+local module = {}
44+55+local TweenService = game:GetService("TweenService")
66+77+-- Fades out all descendant <code>GuiBase</code> elements of the given UI container.
88+-- Tweens <code>BackgroundTransparency</code>, <code>TextTransparency</code>, and <code>ImageTransparency</code> to 1.
99+-- Optionally waits for the tween to finish before returning.
1010+function module.FadeOut(ui: GuiBase, transparencyInfo: TweenInfo, waitForEnd: boolean)
1111+ local uisToFade = {}
1212+ for _, v in ipairs(ui:GetDescendants()) do
1313+ if v:IsA("GuiBase") then
1414+ table.insert(uisToFade, v)
1515+ end
1616+ end
1717+ for _, v in ipairs(uisToFade) do
1818+ if v:IsA("TextLabel") or v:IsA("TextButton") or v:IsA("TextBox") then
1919+ TweenService:Create(v, transparencyInfo, { BackgroundTransparency = 1, TextTransparency = 1 }):Play()
2020+ elseif v:IsA("ImageLabel") or v:IsA("ImageButton") then
2121+ TweenService:Create(v, transparencyInfo, { BackgroundTransparency = 1, ImageTransparency = 1 }):Play()
2222+ elseif v:IsA("Frame") then
2323+ TweenService:Create(v, transparencyInfo, { BackgroundTransparency = 1 }):Play()
2424+ end
2525+ end
2626+ if waitForEnd == true then
2727+ task.wait(transparencyInfo.Time)
2828+ end
2929+end
3030+3131+-- Fades in all descendant <code>GuiBase</code> elements of the given UI container.
3232+-- Tweens <code>BackgroundTransparency</code>, <code>TextTransparency</code>, and <code>ImageTransparency</code> to 0.
3333+-- Optionally waits for the tween to finish before returning.
3434+function module.FadeIn(ui: GuiBase, transparencyInfo: TweenInfo, waitForEnd: boolean)
3535+ local uisToFade = {}
3636+ for _, v in ipairs(ui:GetDescendants()) do
3737+ if v:IsA("GuiBase") then
3838+ table.insert(uisToFade, v)
3939+ end
4040+ end
4141+ for _, v in ipairs(uisToFade) do
4242+ if v:IsA("TextLabel") or v:IsA("TextButton") or v:IsA("TextBox") then
4343+ TweenService:Create(v, transparencyInfo, { BackgroundTransparency = 0, TextTransparency = 0 }):Play()
4444+ elseif v:IsA("ImageLabel") or v:IsA("ImageButton") then
4545+ TweenService:Create(v, transparencyInfo, { BackgroundTransparency = 0, ImageTransparency = 0 }):Play()
4646+ elseif v:IsA("Frame") then
4747+ TweenService:Create(v, transparencyInfo, { BackgroundTransparency = 0 }):Play()
4848+ end
4949+ end
5050+ if waitForEnd == true then
5151+ task.wait(transparencyInfo.Time)
5252+ end
5353+end
5454+5555+return module
+201
Modules/TweenSequence.luau
···11+--!optimize 2
22+--!strict
33+local RunService = game:GetService("RunService")
44+55+type TweenSequenceItem = number | Tween | { Tween } | () -> ()
66+export type TweenSequenceType = { TweenSequenceItem }
77+88+type CurrentState = {
99+ thread: thread?,
1010+ index: number,
1111+ elapsed: number,
1212+ heartbeat: RBXScriptConnection?,
1313+ activeTweenIndices: { number },
1414+}
1515+1616+type TweenSequenceImpl = {
1717+ __index: TweenSequenceImpl,
1818+ __tostring: (self: TweenSequence) -> string,
1919+ new: (sequence: TweenSequenceType) -> TweenSequence,
2020+ _connectHeartbeat: (self: TweenSequence) -> (),
2121+ _disconnectHeartbeat: (self: TweenSequence) -> (),
2222+ _runItem: (self: TweenSequence, item: TweenSequenceItem) -> (),
2323+ _resumeItem: (self: TweenSequence, item: TweenSequenceItem) -> (),
2424+ Play: (self: TweenSequence) -> (),
2525+ Pause: (self: TweenSequence) -> (),
2626+ Resume: (self: TweenSequence) -> (),
2727+}
2828+2929+export type TweenSequence = typeof(setmetatable(
3030+ {} :: {
3131+ _sequence: TweenSequenceType,
3232+ _current: CurrentState,
3333+ Playing: boolean,
3434+ },
3535+ {} :: TweenSequenceImpl
3636+ ))
3737+3838+local TweenSequence = {} :: TweenSequenceImpl
3939+TweenSequence.__index = TweenSequence
4040+4141+-- Creates a new <code>TweenSequence</code> from a sequence of items.
4242+-- Items can be <code>number</code> (wait), <code>Tween</code>, <code>{Tween}</code> (parallel), or <code>() -> ()</code> (callback).
4343+function TweenSequence.new(sequence: TweenSequenceType): TweenSequence
4444+ local self = setmetatable({}, TweenSequence)
4545+ self._sequence = sequence
4646+ self.Playing = false
4747+ self._current = {
4848+ thread = nil,
4949+ index = 0,
5050+ elapsed = 0,
5151+ heartbeat = nil,
5252+ activeTweenIndices = {},
5353+ }
5454+ return self
5555+end
5656+5757+function TweenSequence:_connectHeartbeat()
5858+ self._current.heartbeat = RunService.Heartbeat:Connect(function(dt: number)
5959+ self._current.elapsed += dt
6060+ end)
6161+end
6262+6363+function TweenSequence:_disconnectHeartbeat()
6464+ if self._current.heartbeat then
6565+ self._current.heartbeat:Disconnect()
6666+ self._current.heartbeat = nil
6767+ end
6868+end
6969+7070+function TweenSequence:_runItem(item: TweenSequenceItem)
7171+ if typeof(item) == "number" then
7272+ task.wait(item)
7373+ elseif typeof(item) == "table" then
7474+ self._current.activeTweenIndices = {}
7575+ for tweenIndex, tween in item do
7676+ tween:Play()
7777+ table.insert(self._current.activeTweenIndices, tweenIndex)
7878+ tween.Completed:Connect(function()
7979+ local idx = table.find(self._current.activeTweenIndices, tweenIndex)
8080+ if idx then
8181+ table.remove(self._current.activeTweenIndices, idx)
8282+ end
8383+ end)
8484+ end
8585+ local longest: Tween = item[1]
8686+ for _, tween in item do
8787+ if tween.TweenInfo.Time > longest.TweenInfo.Time then
8888+ longest = tween
8989+ end
9090+ end
9191+ longest.Completed:Wait()
9292+ elseif typeof(item) == "function" then
9393+ item()
9494+ else
9595+ item:Play()
9696+ item.Completed:Wait()
9797+ end
9898+end
9999+100100+function TweenSequence:_resumeItem(item: TweenSequenceItem)
101101+ if typeof(item) == "number" then
102102+ local remaining = item - self._current.elapsed
103103+ if remaining > 0 then
104104+ task.wait(remaining)
105105+ end
106106+ elseif typeof(item) == "table" then
107107+ for _, tweenIndex in self._current.activeTweenIndices do
108108+ item[tweenIndex]:Play()
109109+ end
110110+ if #self._current.activeTweenIndices > 0 then
111111+ local longest: Tween = item[self._current.activeTweenIndices[1]]
112112+ for _, tweenIndex in self._current.activeTweenIndices do
113113+ local tween: Tween = item[tweenIndex]
114114+ if tween.TweenInfo.Time > longest.TweenInfo.Time then
115115+ longest = tween
116116+ end
117117+ end
118118+ longest.Completed:Wait()
119119+ end
120120+ else
121121+ local tween = item :: Tween
122122+ tween:Play()
123123+ tween.Completed:Wait()
124124+ end
125125+end
126126+127127+-- Plays the sequence from the beginning.
128128+-- Sets <code>Playing</code> to <code>true</code> for the duration of playback.
129129+function TweenSequence:Play()
130130+ self._current.thread = task.spawn(function()
131131+ self.Playing = true
132132+ for index, item in self._sequence do
133133+ self._current.index = index
134134+ self._current.elapsed = 0
135135+ self._current.activeTweenIndices = {}
136136+ self:_connectHeartbeat()
137137+ self:_runItem(item)
138138+ self:_disconnectHeartbeat()
139139+ end
140140+ self.Playing = false
141141+ end)
142142+end
143143+144144+-- Pauses the sequence at the current step.
145145+-- Pauses any actively playing <code>Tween</code> instances at that step.
146146+function TweenSequence:Pause()
147147+ self:_disconnectHeartbeat()
148148+ if self._current.thread then
149149+ task.cancel(self._current.thread)
150150+ self._current.thread = nil
151151+ end
152152+ local item = self._sequence[self._current.index]
153153+ if item then
154154+ if typeof(item) == "table" then
155155+ for _, tween in item do
156156+ if tween.PlaybackState == Enum.PlaybackState.Playing then
157157+ tween:Pause()
158158+ end
159159+ end
160160+ elseif typeof(item) ~= "number" and typeof(item) ~= "function" then
161161+ item:Pause()
162162+ end
163163+ end
164164+ self.Playing = false
165165+end
166166+167167+-- Resumes the sequence from where it was paused.
168168+-- Completes the remaining duration of the current step before advancing.
169169+function TweenSequence:Resume()
170170+ if self._current.index == 0 or self.Playing then
171171+ return
172172+ end
173173+ self._current.thread = task.spawn(function()
174174+ self.Playing = true
175175+ local startIndex = self._current.index
176176+ self:_connectHeartbeat()
177177+ self:_resumeItem(self._sequence[startIndex])
178178+ self:_disconnectHeartbeat()
179179+ for index = startIndex + 1, #self._sequence do
180180+ self._current.index = index
181181+ self._current.elapsed = 0
182182+ self._current.activeTweenIndices = {}
183183+ self:_connectHeartbeat()
184184+ self:_runItem(self._sequence[index])
185185+ self:_disconnectHeartbeat()
186186+ end
187187+ self.Playing = false
188188+ end)
189189+end
190190+191191+function TweenSequence:__tostring(): string
192192+ return ("TweenSequence(Playing=%s, step=%d/%d)"):format(
193193+ tostring(self.Playing),
194194+ self._current.index,
195195+ #self._sequence
196196+ )
197197+end
198198+199199+return {
200200+ Create = TweenSequence.new,
201201+}