Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

HoverFX

A modular, high-performance UI hover effects library for Roblox.

Add polished, modern animations to any GUI element in seconds — glow, ripple, parallax, magnetic, spring physics and more, By Jake Nelson.

Installation · Quick Start · All Presets · Options · Styles · API · Examples


✨ What is HoverFX?

HoverFX is a plug-and-play hover effect system for Roblox UI. Instead of writing repetitive TweenService boilerplate for every button, you call one line:

HoverFX.attach(button, "LiftScale")

Every effect is a self-contained preset module — you can stack multiple on the same element, detach them at runtime, define reusable style bundles, or bulk-apply to an entire ScreenGui.


📁 Package Structure

HoverFX (ModuleScript)
├── Elements/               — empty folder for user extensions
├── Features/               — 19 individual effect modules
│   ├── Mobile              — touch hover fallback
│   ├── Press               — click press-down feedback
│   ├── Scale               — scale up on hover
│   ├── Shrink              — scale down on hover
│   ├── Lift                — vertical lift on hover
│   ├── LiftScale           — lift + scale (most popular)
│   ├── ShadowDepth         — animated drop shadow
│   ├── Glow                — UIStroke border glow
│   ├── Underline           — animated underline reveal
│   ├── ColorShift          — background/text color lighten
│   ├── GradientSlide       — UIGradient rotation + offset
│   ├── ShineSweep          — highlight sweep across element
│   ├── RippleClick         — material ripple from click origin
│   ├── Sound               — hover and click sounds
│   ├── ParallaxFollow      — 3D cursor-following tilt
│   ├── MagneticHover       — proximity magnetic pull
│   ├── IconWiggle          — child icon wiggle animation
│   ├── PulseGlow           — pulsing glow aura
│   └── Wave                — horizontal stretch-snap wave
├── Packages/
│   └── Spring              — Heartbeat physics engine
├── Attribute               — runtime disable helpers
├── Reference               — weak-key state registry
├── Types                   — HoverOptions type exports
├── Utility                 — defaults, helpers, factories
└── VERSION                 — returns "1.0.0"

📦 Installation

Option A — Roblox Studio (Recommended)

  1. Download HoverFX.rbxmx from Releases
  2. Drag and drop the file into Roblox Studio — it will insert as a ModuleScript
  3. Move HoverFX into ReplicatedStorage

Option B — Rojo / File Sync

Clone this repo and sync with Rojo into your project.

Require

local HoverFX = require(game.ReplicatedStorage.HoverFX)

🚀 Quick Start

Simplest usage

local HoverFX = require(game.ReplicatedStorage.HoverFX)

-- Single effect
HoverFX.attach(script.Parent, "LiftScale")

-- Full premium pack in one call
HoverFX.quick(script.Parent)

-- Clean up when done
HoverFX.detach(script.Parent)

With a LocalScript inside a button

TextButton
 └── LocalScript
local HoverFX = require(game.ReplicatedStorage.HoverFX)
local button = script.Parent

HoverFX.attach(button, "LiftScale", { Scale = 1.1, Lift = 8 })
HoverFX.attach(button, "RippleClick")
HoverFX.attach(button, "Glow", { GlowColor = Color3.fromRGB(255, 200, 80) })

Presets

All presets are called with HoverFX.attach(element, "PresetName", options?)


LiftScale

Scales up and lifts upward on hover. The go-to preset for buttons.

HoverFX.attach(button, "LiftScale")
HoverFX.attach(button, "LiftScale", { Scale = 1.1, Lift = 10 })

Scale

Scales up only, no vertical movement.

HoverFX.attach(button, "Scale")
HoverFX.attach(button, "Scale", { Scale = 1.15 })

Shrink

Shrinks on hover instead of growing. Good for toggles or destructive actions.

HoverFX.attach(button, "Shrink")
HoverFX.attach(button, "Shrink", { Scale = 0.92 })

Lift

Lifts upward only, no scale change.

HoverFX.attach(button, "Lift")
HoverFX.attach(button, "Lift", { Lift = 12 })

Press

Compresses and pushes down on mouse/touch hold. Best combined with LiftScale.

HoverFX.attach(button, "Press")
HoverFX.attach(button, "Press", { PressScale = 0.93, PressDepth = 5 })

Glow

Animates a UIStroke border glow on hover.

HoverFX.attach(button, "Glow")
HoverFX.attach(button, "Glow", {
    GlowThickness   = 4,
    GlowTransparency = 0.2,
    GlowColor       = Color3.fromRGB(120, 200, 255)
})

PulseGlow

Glow that continuously pulses in and out while the cursor is hovering.

HoverFX.attach(button, "PulseGlow")
HoverFX.attach(button, "PulseGlow", {
    PulseGlowMinThickness = 1,
    PulseGlowMaxThickness = 6,
    PulseGlowSpeed        = 0.5
})

ShadowDepth

A fake drop-shadow sibling that grows on hover to simulate depth.

⚠️ Requires the button's parent to be a GuiObject (e.g. Frame, not ScreenGui directly).

HoverFX.attach(button, "ShadowDepth")
HoverFX.attach(button, "ShadowDepth", {
    ShadowOffsetIn  = 8,
    ShadowGrowIn    = 10,
    ShadowOpacityIn = 0.45
})

➖ Underline

Reveals an animated underline bar sweeping from left to right on hover.

HoverFX.attach(button, "Underline")
HoverFX.attach(button, "Underline", {
    UnderlineHeight  = 3,
    UnderlinePadding = 4
})

ColorShift

Lightens the background, text and icon color on hover via lerp.

HoverFX.attach(button, "ColorShift")
HoverFX.attach(button, "ColorShift", {
    ColorShiftAmount = 0.2,
    AlsoTextColor    = false  -- skip text color shift
})

GradientSlide

Rotates and offsets an existing UIGradient on hover.

⚠️ Requires a UIGradient as a direct child of the element.

TextButton
 ├── UICorner
 ├── UIGradient   ← required
 └── LocalScript
HoverFX.attach(button, "GradientSlide")
HoverFX.attach(button, "GradientSlide", {
    GradientRotation = 45,
    GradientOffsetX  = 0.35
})

ShineSweep

Sweeps a bright highlight bar diagonally across the element on hover.

HoverFX.attach(button, "ShineSweep")
HoverFX.attach(button, "ShineSweep", {
    ShineDuration    = 0.5,
    ShineAngle       = 25,
    ShineTransparency = 0.65,
    ShineWidthScale  = 0.3,
    ShineCooldown    = 0.4
})

RippleClick

Spawns a material-design expanding ripple at the exact click/touch point.

HoverFX.attach(button, "RippleClick")
HoverFX.attach(button, "RippleClick", {
    RippleColor        = Color3.fromRGB(255, 255, 255),
    RippleTransparency = 0.5,
    RippleScale        = 2.5,
    RippleDuration     = 0.4,
    RippleCooldown     = 0.1
})

🔊 Sound

Plays reusable hover and/or click sounds with built-in cooldown spam protection.

HoverFX.attach(button, "Sound", {
    HoverSoundId = "rbxassetid://12345678",
    ClickSoundId = "rbxassetid://87654321",
    SoundVolume  = 0.4,
    SoundCooldown = 0.08
})

ParallaxFollow

Tilts and shifts the element in 3D to follow the cursor, creating a parallax effect.

HoverFX.attach(button, "ParallaxFollow")
HoverFX.attach(button, "ParallaxFollow", {
    ParallaxMaxAngle  = 10,
    ParallaxMaxOffset = 8
})

MagneticHover

Subtly pulls the element toward the cursor when it enters a proximity radius.

HoverFX.attach(button, "MagneticHover")
HoverFX.attach(button, "MagneticHover", {
    MagneticRadius    = 90,
    MagneticMaxOffset = 10,
    MagneticStrength  = 0.85
})

IconWiggle

Wiggles the first detected icon child (ImageLabel/ImageButton) on hover and click.

⚠️ Requires a child ImageLabel or ImageButton, ideally named "Icon".

HoverFX.attach(button, "IconWiggle")
HoverFX.attach(button, "IconWiggle", {
    IconWiggleAngle  = 14,
    IconWiggleOffset = 4,
    IconWiggleTime   = 0.1
})

Wave

Brief horizontal stretch-and-snap animation on hover.

HoverFX.attach(button, "Wave")
HoverFX.attach(button, "Wave", {
    WaveAmount   = 8,
    WaveDuration = 0.2
})

Mobile

Touch-only hover fallback. Use on non-button Frames that need touch feedback.

HoverFX.attach(frame, "Mobile")
HoverFX.attach(frame, "Mobile", { Scale = 1.05, Lift = 4 })

Smart

Auto-detects what's on the element (UIGradient, UIStroke, icons, text) and intelligently applies the best combination of effects.

HoverFX.attach(button, "Smart")
HoverFX.attach(button, "Smart", {
    SmartIncludeShine    = false,
    SmartIncludeRipple   = false,
    SmartIncludeParallax = false,
    PerformanceMode      = true   -- skip expensive effects
})

⚙️ Options Reference

All options are optional. Any unset value falls back to a sensible default.

Option Type Default Description
Scale number 1.08 Target scale on hover
Lift number 6 Pixel lift upward on hover
TimeIn number 0.12 Tween duration on hover enter (seconds)
TimeOut number 0.12 Tween duration on hover leave (seconds)
EasingStyle Enum.EasingStyle Quad Easing style for tweens
EasingDirection Enum.EasingDirection Out Easing direction for tweens
UseUIScale boolean true Use UIScale for scaling (recommended)
PressScale number 0.96 Scale during press-down
PressDepth number 2 Pixel offset downward during press
GlowThickness number 3 UIStroke thickness on hover
GlowTransparency number 0.35 UIStroke transparency on hover
GlowColor Color3 nil Override glow stroke color
GradientRotation number 35 Degrees added to gradient rotation
GradientOffsetX number 0.25 X offset added to gradient on hover
ShineDuration number 0.45 Duration of the shine sweep
ShineAngle number 20 Tilt angle of the shine bar
ShineCooldown number 0.25 Minimum seconds between sweeps
RippleDuration number 0.45 Duration of the ripple expand
RippleColor Color3 White Ripple tint color
RippleScale number 2.25 Final ripple size multiplier
RippleCooldown number 0.12 Minimum seconds between ripples
ShadowEnabled boolean true Enable shadow in ShadowDepth
ShadowOffsetIn number 6 Shadow Y offset on hover
ShadowGrowIn number 6 Shadow size growth on hover
ShadowOpacityIn number 0.65 Shadow transparency on hover
ParallaxMaxAngle number 6 Max tilt angle in degrees
ParallaxMaxOffset number 4 Max positional offset in pixels
MagneticRadius number 60 Pixel radius for magnetic attraction
MagneticMaxOffset number 5 Max pixel pull distance
MagneticStrength number 0.7 Pull strength multiplier (0–1)
IconWiggleAngle number 8 Wiggle rotation in degrees
IconWiggleOffset number 2 Wiggle lift in pixels
PulseGlowMinThickness number 2 Minimum pulse stroke thickness
PulseGlowMaxThickness number 4 Maximum pulse stroke thickness
PulseGlowSpeed number 0.6 Seconds per pulse half-cycle
WaveAmount number 4 Pixel width added during wave
WaveDuration number 0.25 Total wave animation duration
HoverSoundId string nil Asset ID for hover sound
ClickSoundId string nil Asset ID for click sound
SoundVolume number 0.35 Sound playback volume
SoundCooldown number 0.08 Minimum seconds between sounds
ColorShiftAmount number 0.12 Lerp amount toward white (0–1)
AlsoTextColor boolean true Also shift text color
Spring boolean false Use spring physics instead of tweens
SpringSpeed number 32 Spring responsiveness
SpringDamping number 0.82 Spring damping (less = more bounce)
IgnoreDisabled boolean false Ignore Active = false state
PerformanceMode boolean false Skip expensive effects (parallax, shine, ripple, wave, magnetic, icon wiggle)

Spring Physics

Any preset can use physics-based spring smoothing instead of tweens by adding Spring = true.

HoverFX.attach(button, "LiftScale", {
    Spring        = true,
    SpringSpeed   = 35,   -- higher = snappier
    SpringDamping = 0.75  -- lower = more bounce
})

-- Also works great with ParallaxFollow
HoverFX.attach(button, "ParallaxFollow", {
    Spring = true,
    SpringSpeed = 28
})

Styles System

Styles are named bundles of presets. Define once, apply everywhere.

Built-in styles

Style Included presets
Premium ShadowDepth, Press, LiftScale, Glow, PulseGlow, ColorShift, GradientSlide, RippleClick, Sound, ParallaxFollow, IconWiggle, MagneticHover, Wave
Lite Press, LiftScale, ColorShift, Glow
SmartPremium Smart
-- Apply a built-in style
HoverFX.applyStyle(button, "Premium")
HoverFX.applyStyle(button, "Lite")
HoverFX.applyStyle(button, "SmartPremium")

Define your own style

HoverFX.defineStyle("MyStyle", {
    "Press",
    "LiftScale",
    "RippleClick",
    "Glow"
}, {
    Scale          = 1.12,
    GlowColor      = Color3.fromRGB(100, 220, 255),
    RippleColor    = Color3.fromRGB(100, 220, 255),
    Spring         = true
})

-- Use it anywhere
HoverFX.applyStyle(button, "MyStyle")

-- Override options per-call
HoverFX.applyStyle(button, "MyStyle", { Scale = 1.05 })

Stacking Presets

Multiple presets can be stacked on the same element. They run independently and all detach together.

HoverFX.attach(button, "LiftScale")
HoverFX.attach(button, "RippleClick")
HoverFX.attach(button, "Glow",      { GlowColor = Color3.fromRGB(255, 180, 0) })
HoverFX.attach(button, "ShineSweep")
HoverFX.attach(button, "Sound",     { HoverSoundId = "rbxassetid://123" })

📖 API Reference

HoverFX.attach(gui, preset, options?)

Attaches a single preset to a GuiObject.

HoverFX.attach(button, "LiftScale", { Scale = 1.1 })

HoverFX.detach(gui, removeInstances?)

Removes all effects from a GuiObject and restores its original state.

HoverFX.detach(button)
HoverFX.detach(button, true) -- also destroys created instances (glow stroke, shadow, etc.)

HoverFX.quick(gui, options?)

Attaches the full premium pack (all effects) in one call.

HoverFX.quick(button)
HoverFX.quick(button, { PerformanceMode = true }) -- lighter version

HoverFX.defineStyle(name, presets, options?)

Defines a reusable named bundle of presets.

HoverFX.defineStyle("Neon", { "Glow", "PulseGlow", "RippleClick" }, {
    GlowColor = Color3.fromRGB(0, 255, 180)
})

HoverFX.applyStyle(gui, name, optionsOverride?)

Applies a defined style to a GuiObject.

HoverFX.applyStyle(button, "Neon")

HoverFX.applyTo(container, presetOrStyle, options?, isStyle?)

Applies a preset or style to every GuiButton found inside a container.

HoverFX.applyTo(screenGui, "LiftScale")
HoverFX.applyTo(screenGui, "Premium", nil, true)  -- isStyle = true

Attribute.setDisabled(gui, bool) / Attribute.getDisabled(gui) / Attribute.toggleDisabled(gui)

Temporarily disables effects at runtime without detaching them.

local Attribute = require(HoverFX.Attribute)

Attribute.setDisabled(button, true)    -- pause effects
Attribute.setDisabled(button, false)   -- resume effects
Attribute.toggleDisabled(button)       -- flip state

💡 Examples

Card with full premium effects

local HoverFX = require(game.ReplicatedStorage.HoverFX)
local card = script.Parent

HoverFX.quick(card, {
    Scale          = 1.04,
    Lift           = 6,
    Spring         = true,
    GlowColor      = Color3.fromRGB(255, 255, 255),
    RippleColor    = Color3.fromRGB(255, 255, 255),
    ShadowEnabled  = true
})

Neon-styled action button

HoverFX.defineStyle("Neon", {
    "Press", "LiftScale", "Glow", "PulseGlow", "RippleClick", "ShineSweep"
}, {
    Scale            = 1.08,
    GlowColor        = Color3.fromRGB(0, 255, 160),
    GlowThickness    = 4,
    RippleColor      = Color3.fromRGB(0, 255, 160),
    PulseGlowSpeed   = 0.4,
    Spring           = true
})

HoverFX.applyStyle(button, "Neon")

Apply to all buttons in a menu

local HoverFX = require(game.ReplicatedStorage.HoverFX)

HoverFX.applyTo(script.Parent.MenuFrame, "Lite")

Disable effects during a cutscene

local Attribute = require(game.ReplicatedStorage.HoverFX.Attribute)

-- Pause all effects on a button
Attribute.setDisabled(button, true)

-- Resume after cutscene
cutsceneEnded:Connect(function()
    Attribute.setDisabled(button, false)
end)

Performance mode for low-end devices

local isMobile = game:GetService("UserInputService").TouchEnabled

HoverFX.quick(button, {
    PerformanceMode = isMobile,
    Spring          = not isMobile
})

⚠️ Notes & Requirements

Preset Requirement
GradientSlide UIGradient must be a direct child of the element
ShadowDepth Element's parent must be a GuiObject (not ScreenGui)
IconWiggle Element must have a child ImageLabel or ImageButton (named "Icon" preferred)
Glow / PulseGlow Works best when no existing UIStroke conflicts are present
Smart Auto-detects all of the above — no setup needed

Made with ❤️ for the Roblox dev community.

About

A modular Roblox UI effects library that adds smooth hover animations and interactive effects to buttons and interface elements.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors