Start typing to search packages!
loadingspinner
By @biotoxin495
Roblox
MirroredLoadingSpinner — A small animated loading spinner module
LoadingSpinner is a small, dependency-free Roblox utility for displaying animated loading spinners over UI elements.
It creates a dimmed overlay inside any GuiObject, fades in a configurable icon, and rotates it until the loading state is cleared. Each target can have one active spinner, and every spinner is represented by a handle that can be hidden or destroyed independently.
Quick example
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LoadingSpinner = require(ReplicatedStorage.LoadingSpinner)
local spinners = LoadingSpinner.new()
local target = script.Parent
local handle = spinners:Show(target)
task.wait(2)
handle:Hide()
Hide fades the spinner out before cleaning it up. To remove it immediately instead, call handle:Destroy().
🚀 Features
- Fully standalone and dependency-free
- Attach a spinner to any
GuiObject - One active spinner per target
- Per-instance default configuration
- Per-spinner configuration overrides
- Animated fade-in and fade-out
- Configurable icon, size, color, rotation speed, and direction
- Optional input blocking
- Optional show delay to avoid brief loading flashes
- Optional minimum visible duration
- Per-spinner handles
IsLoading,SetLoading, andHideAllhelpers- Automatic cleanup when a target is destroyed
- Optional custom UI factory
- Strict Luau types
📖 Basic usage
Copy LoadingSpinner.luau into your project and require it from a client script.
LoadingSpinner creates and animates Roblox UI, so it should normally be used from the client.
Configuring defaults
Pass a configuration table to LoadingSpinner.new to define defaults for that controller.
local spinners = LoadingSpinner.new({
Icon = "rbxassetid://15734250582",
IconColor = Color3.fromRGB(255, 255, 255),
IconSize = UDim2.fromOffset(36, 36),
OverlayColor = Color3.fromRGB(0, 0, 0),
OverlayTransparency = 0.4,
SpinDuration = 1.2,
FadeDuration = 0.15,
ShowDelay = 0.1,
MinimumVisibleDuration = 0.2,
})
Every call to Show can override those defaults:
local handle = spinners:Show(script.Parent, {
IconColor = Color3.fromRGB(80, 180, 255),
OverlayTransparency = 0.25,
})
State-driven usage
SetLoading is convenient when the spinner follows an existing boolean state.
spinners:SetLoading(container, true)
local success, result = pcall(loadData)
spinners:SetLoading(container, false)
You can query whether a target currently owns an active or pending spinner:
if spinners:IsLoading(container) then
print("The container is loading")
end
A spinner waiting for its configured ShowDelay still counts as loading.
⚙️ API
Controller
LoadingSpinner.new(defaultConfig?)
Creates a new LoadingSpinner controller. Each controller owns its own configuration and active spinner registry.
local spinners = LoadingSpinner.new()
spinners:Show(target, config?)
Creates and returns a spinner handle for target.
local handle = spinners:Show(frame)
If the target already has a spinner owned by this controller, the old spinner is destroyed before the new one is created.
spinners:Hide(target)
Fades out the spinner associated with target.
spinners:Hide(frame)
If the spinner is still waiting for its ShowDelay, it is cancelled without being shown.
spinners:HideAll()
Fades out every spinner owned by the controller.
spinners:HideAll()
spinners:IsLoading(target)
Returns whether the target has an active or pending spinner.
local isLoading = spinners:IsLoading(frame)
spinners:SetLoading(target, isLoading, config?)
Shows or hides a spinner based on a boolean.
spinners:SetLoading(frame, true, {
ShowDelay = 0.15,
})
spinners:SetLoading(frame, false)
When isLoading is true, the method returns the active spinner handle. Repeated true updates reuse the current handle instead of restarting its animation. When isLoading is false, the method returns nil.
spinners:Destroy()
Immediately destroys every spinner owned by the controller and makes the controller unusable.
spinners:Destroy()
Spinner handle
handle:Hide()
Fades the spinner out and then destroys it. The configured MinimumVisibleDuration is respected before the fade begins.
handle:Destroy()
Immediately stops all animations, removes the UI, and unregisters the spinner. It is safe to call more than once.
handle:IsActive()
Returns true while the spinner is pending, visible, or fading out.
handle:IsVisible()
Returns true after the spinner UI has been created. This remains true while it is fading out.
handle:GetTarget()
Returns the target GuiObject, or nil after the handle has been destroyed.
handle:GetUI()
Returns the generated overlay Frame, or nil if the spinner has not appeared yet or has already been destroyed.
Complete configuration reference
| Property | Type | Default | Description |
|---|---|---|---|
Name | string | "LoadingSpinner" | Name assigned to the generated overlay. |
ZIndex | number | 100 | Z-index of the overlay. The indicator uses ZIndex + 1. |
Icon | string | Included spinner asset | Image used by the spinner. |
IconColor | Color3 | White | Color applied to the spinner image. |
IconSize | UDim2 | 32 x 32 | Size of the spinner image. |
SpinDuration | number | 1.5 | Seconds required for one complete rotation. |
RotationDirection | number | 1 | Positive values rotate clockwise; negative values rotate counter-clockwise. |
OverlayColor | Color3 | Black | Color of the dimming overlay. |
OverlayTransparency | number | 0.5 | Visible transparency of the overlay, clamped from 0 to 1. |
BlockInput | boolean | true | Sets the overlay's Active property so it can intercept input. |
FadeDuration | number | 0.1 | Fade-in and fade-out duration in seconds. |
ShowDelay | number | 0 | Delay before creating the spinner. Useful for avoiding flashes during fast operations. |
MinimumVisibleDuration | number | 0 | Minimum time the spinner remains visible before hiding. |
Create | function | nil | Optional custom UI factory. |
Negative duration values are treated as 0. SpinDuration is kept above zero so that the rotation tween remains valid.
Avoiding loading flashes
Very fast operations can briefly display and immediately remove a spinner. ShowDelay prevents the spinner from appearing unless the operation lasts long enough.
local spinners = LoadingSpinner.new({
ShowDelay = 0.15,
MinimumVisibleDuration = 0.2,
})
With this configuration:
- Operations shorter than 0.15 seconds do not display a spinner.
- Once displayed, the spinner remains visible for at least 0.2 seconds.
Custom UI
Use Create when the default overlay structure does not match your project.
The callback receives the resolved configuration and must return:
- An unparented
Frameused as the overlay. - An
ImageLabelused as the rotating indicator.
local spinners = LoadingSpinner.new({
Create = function(config)
local overlay = Instance.new("Frame")
overlay.Name = config.Name or "LoadingSpinner"
overlay.Size = UDim2.fromScale(1, 1)
overlay.BorderSizePixel = 0
overlay.BackgroundColor3 = config.OverlayColor or Color3.new(0, 0, 0)
overlay.ZIndex = config.ZIndex or 100
local indicator = Instance.new("ImageLabel")
indicator.AnchorPoint = Vector2.new(0.5, 0.5)
indicator.Position = UDim2.fromScale(0.5, 0.5)
indicator.Size = config.IconSize or UDim2.fromOffset(32, 32)
indicator.BackgroundTransparency = 1
indicator.Image = config.Icon or ""
indicator.ImageColor3 = config.IconColor or Color3.new(1, 1, 1)
indicator.ZIndex = (config.ZIndex or 100) + 1
indicator.Parent = overlay
return overlay, indicator
end,
})
LoadingSpinner ensures the indicator belongs to the returned overlay, then manages parenting, rotation, fading, and cleanup after the callback returns.
📝 Notes
- A spinner is automatically unregistered when its handle is hidden and the fade completes, its handle is destroyed, its target is destroyed, its generated overlay is destroyed externally, or its controller is destroyed.
- All cleanup methods are idempotent, so repeated calls are safe.
- LoadingSpinner is intended for client-side UI.
🛠️ Installation
Copy LoadingSpinner.luau into your project — for example under ReplicatedStorage:
ReplicatedStorage
└── LoadingSpinner
Then require it from a client script:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local LoadingSpinner = require(ReplicatedStorage.LoadingSpinner)
License
Add the license used by your project before publishing the module.
made with ❤️ by biotoxin495
Package Details
Install command (Click to copy)
Version
1.0.4
License
MIT
Safe for commercial use
Automated license review — not legal advice.
