Animations and effects
Hover and click effects, the dissolve, and the four tween curves the library uses.
Hover and Click#
Button takes a Hover and a Click table, and so does each entry in an icon
strip. IconButton reads its own pair only when you omit Buttons; with
Buttons set, every effect comes from the entries. The keys:
| Option | Type | Default | What it does |
|---|---|---|---|
Rotate | number | — | Degrees to turn the icon, added to its resting angle. On Hover it holds while the pointer is inside. On Click it turns and comes back. |
Scale | number | — | Multiplier on the icon's size, clamped to 0-10. Hover only. |
Icon | string | — | Swap to a different icon for the duration, then swap back. |
Text | string | — | Swap the button's caption for the duration. |
Hold | number | 0.9 | Seconds a Click keeps its Icon or Text swap. Click only. |
A hover effect ends when the pointer leaves. A click has no natural end, so an
Icon or Text swap on Click reverts after Hold seconds.
A Click rotation runs on a 0.45s Back Out tween. An exact multiple of 360
snaps back to the resting angle when it lands; any other angle tweens back.
The recipes#
Each of these is a complete control you can paste.
Refresh: one full spin on click#
main:Button({
Text = "Reload data",
ButtonText = "Refresh",
ButtonIcon = "refresh-cw",
Click = { Rotate = 360 },
Callback = reload,
})Confirm: swap to a tick, then back#
main:Button({
Text = "Save configuration",
ButtonText = "Save",
ButtonIcon = "save",
Click = { Icon = "check", Text = "Saved", Hold = 1.4 },
Callback = save,
})Destructive: warn on hover#
main:Button({
Text = "Delete configuration",
ButtonText = "Delete",
ButtonIcon = "trash-2",
Danger = true,
Hover = { Icon = "triangle-alert", Scale = 1.1 },
Click = { Text = "Deleted", Hold = 1.6 },
Callback = deleteConfig,
})Lift: grow a little on hover#
main:Button({
Text = "Open settings",
ButtonText = "Open",
ButtonIcon = "settings",
Hover = { Scale = 1.12 },
Callback = openSettings,
})Nudge: a quarter turn, for something that expands#
main:Button({
Text = "Show advanced",
ButtonText = "Expand",
ButtonIcon = "chevron-right",
Hover = { Rotate = 90 },
Callback = expand,
})Overdrive: two full turns#
main:Button({
Text = "Rebuild everything",
ButtonText = "Rebuild",
ButtonIcon = "rotate-cw",
Click = { Rotate = 720, Text = "Working…", Hold = 1.2 },
Callback = rebuild,
})Per-entry, on an icon strip#
Each button in a strip carries its own:
main:IconButton({
Text = "Playback",
Buttons = {
{ Icon = "play", Callback = play, Hover = { Scale = 1.15 } },
{ Icon = "pause", Callback = pause, Hover = { Scale = 1.15 } },
{ Icon = "refresh-cw", Callback = restart, Click = { Rotate = 360 } },
{ Icon = "trash-2", Callback = clear, Danger = true,
Hover = { Icon = "triangle-alert" } },
},
})Spamming is safe#
Every effect is generation-guarded. Clicking a spinning button again restarts the spin rather than letting the first click's completion snap the icon back mid-turn. You do not need a debounce.
Renaming a button with SetText while no effect is running makes the new label
the one a swap reverts to.
Hover colours#
Separate from the icon effects, Button, Dropdown, Keybind and each
icon-strip entry take:
| Option | Type | Default | What it does |
|---|---|---|---|
HoverColor | Color3 | string | — | The colour the border and glyph light up with. A theme role name works too. Defaults to the accent role, or the danger role on a Danger button. |
HoverFill | Color3 | string | — | The colour the surface fills with on hover, or a theme role name. Defaults to the hover role. |
main:Button({
Text = "Custom hover",
ButtonText = "Run",
HoverColor = Color3.fromRGB(120, 180, 255),
HoverFill = "panel3", -- a theme role, or a Color3
Callback = run,
})On a Button these two are read by the outline style only. filled, ghost
and soft each have their own hover built in.
The dissolve#
The window breaks into tiles when hidden and reassembles when shown. It is on by default and needs no setup.
The tiles are coloured by sampling what the window is actually showing, so the
mosaic looks like the window rather than a grid of flat squares. The burn edge
is ember orange whatever the theme is. Change it on Ember.Fx:
Ember.Fx.ember = Color3.fromRGB(90, 170, 255) -- the burn front
Ember.Fx.emberHot = Color3.fromRGB(235, 245, 255) -- its hot coreEffects.Quality scales the budget: "Low" takes 0.6 of the tiles and
particles, "High" takes 1.35, and "Balanced" leaves them alone. The tile
count is clamped to 32-460 after scaling either way.
Lower MaxTiles and Particles on weak machines, or set Effects.Enabled to
false for no animation at all. The keys and their defaults are in the
configuration reference.
With Effects.RespectReducedMotion = true, animation is also off for any player
whose Roblox client reports ReducedMotionEnabled. It is false by default.
The motion curves#
These are the curves the library animates with. Match them in your own tweens:
| Name | TweenInfo | Used for |
|---|---|---|
fast | 0.14s Quad Out | Colour changes |
base | 0.22s Quint Out | Hover, most state changes |
open | 0.34s Quint Out | Menus and groups expanding |
shut | 0.24s Quart In | The same, closing |
local TweenService = game:GetService("TweenService")
local BASE = TweenInfo.new(0.22, Enum.EasingStyle.Quint, Enum.EasingDirection.Out)
TweenService:Create(myFrame, BASE, { BackgroundTransparency = 0 }):Play()