[2.2.0] Cascade UI Animator - A Keyframe based UI Animator

Cascade UI Animator

Keyframe animations for Roblox UI. Build once, use in any game.

store
docs
tutorials
feedback


See it in action


What does it do?

Cascade is a timeline editor that lets you keyframe any UI property — position, size, transparency, color, rotation, scale — and play them back at runtime with a two-line API.

Animations save as ModuleScripts inside your game. No external files, no exporting. The runtime reads them directly.


The Runtime

Cascade includes a lightweight AnimationService that runs in-game. It uses an additive accumulator — multiple animations on the same property blend together instead of overriding each other. A hover, a click, and a shake can all run on the same button at the same time.


Features

Animation Blending
Multiple animations on the same property blend additively. Hover + click + shake all on one button — they combine instead of fighting.

Axis Isolation
Animate Position.X without touching Position.Y. Animate Size.X.Scale without affecting Size.X.Offset. Each axis is independent.

Relative Mode
Toggle any track to relative — values become deltas instead of absolutes. A hover that adds +0.05 to Scale works whether the button’s base scale is 1.0 or 2.0. Makes animations reusable across different UI elements.

PlayBatch with Stagger
Play the same animation on multiple instances with a cascading delay. One call animates an entire grid of items, each starting a fraction of a second after the last.

Reverse Playback
Play any animation backwards with { Reverse = true }. Use the same hover animation for mouse enter and mouse leave — no separate animation needed.

Animation Events
Place event markers on the timeline with typed data (String, Number, Boolean). Your script reacts when the animation reaches them — trigger sounds, swap text, spawn particles, all synced to the animation.

Auto-Record
Toggle recording and drag UI elements in the viewport. The plugin captures property changes as keyframes automatically. No manual value entry needed.

Smart Input
Type values in any reasonable format — 255, 128, 64 for a color, .5, .3 for a UDim2. The parser figures out what you mean.

Full Undo/Redo
50-level history stack. Every action is undoable.

Customizable Keybinds
Rebind every shortcut to match your workflow. Persists across sessions.


Supported Properties

All GuiObjects
Position, Size, Rotation, AnchorPoint, BackgroundColor3, BackgroundTransparency, BorderColor3, BorderSizePixel, Visible, ZIndex

Text Elements
TextColor3, TextTransparency, TextStrokeColor3, TextStrokeTransparency, TextSize, MaxVisibleGraphemes

Image Elements
ImageColor3, ImageTransparency

ScrollingFrame
CanvasPosition, CanvasSize, ScrollBarImageColor3, ScrollBarImageTransparency

UI Components
UIStroke (Color, Transparency, Thickness), UICorner (CornerRadius), UIGradient (Transparency, Rotation, Offset), UIPadding (all directions), UIScale (Scale)

All composite types expand into sub-properties — UDim2 splits into X.Scale, X.Offset, Y.Scale, Y.Offset for axis isolation.


Runtime API

The runtime is a single module you drop into ReplicatedStorage. Install it from the plugin menu.

Fire and forget:

local AnimationService = require(ReplicatedStorage.CascadeRuntimeEngine.AnimationService)
local config = require(ReplicatedStorage.CascadeAnimations.MyAnimation)

-- Play on one instance
AnimationService.Play(myFrame, config)

-- Play on multiple instances with stagger
AnimationService.PlayBatch(buttons, config, { Stagger = 0.1 })

-- Play in reverse
AnimationService.Play(myFrame, config, { Reverse = true })

-- Reset properties when done
AnimationService.Play(myFrame, config, { Reset = true })

Track-based control:

local track = AnimationService.CreateTrack(myFrame, config)

track.Completed:Connect(function()
    print("Done")
end)

track.MarkerReached:Connect(function(name, data)
    if name == "PlaySound" then
        soundEffect:Play()
    end
end)

track:Play()
track:SetSpeed(2)    -- 2x speed
track:Scrub(0.5)     -- Jump to 0.5s
track:Pause()
track:Destroy()

Batch with events per instance:

local batch = AnimationService.CreateBatchedTrack(stars, config, { Stagger = 0.15 })

batch.MarkerReached:Connect(function(name, data, instance)
    -- Each star triggers its own sound when it lands
    playChime(instance)
end)

batch:Play()

All Play options:

Option Type Description
Delay number Wait before starting
Loop bool/number true = infinite, N = count
Reverse bool Play backwards
Reset bool Restore original values on cleanup
Stagger number Delay between batch instances
DeleteOnComplete bool Auto-destroy when finished
StartTime number Start from specific time

Service API Reference
Function Description
Play(instance, config, options?) Play animation, returns signal
PlayBatch(instances, config, options?) Play on multiple instances
Pause(instance, config) Pause animation
Resume(instance, config) Resume paused animation
Stop(instance) Stop all animations on instance
CreateTrack(instance, config, options?) Manual control track
CreateBatchedTrack(instances, config, options?) Manual batch track
SetTime(instance, config, time) Scrub to time
SetFrame(instance, config, frame) Scrub to frame
ClearInstance(instance) Remove all animations + reset

Track signals: Completed, Looped, Cancelled, MarkerReached


Support

Cascade is a paid plugin. Developing this system has taken a lot of time and testing. By purchasing it, you’re supporting continued development — new features, expanded property support, and improvements based on your feedback.

If you use it, a review on the store page means a lot.

56 Likes

WHAT!!! I’ve never seen anything of the sorts but I’ve always wondered who would be the first person to make a keyframe based UI animation plugin!

3 Likes

Yeah, I’m glad you noticed! That was actually one of the reasons I even created this plugin. Animating without keyframes in actual frames felt weird to me.

1 Like

I’m pretty sure “Visulie” supported it but the downside is that the plugin doesn’t have undo redo. but hey, i might as well try this one out!

1 Like

Cool! Please if you find any bugs or anything let me know! Hope you find the plugin useful!

Pro tip! If any of the keybinding are duplicates of studio shortcuts you already use, you’re going to need to change either the plugins or the studio shortcut or else the action won’t work.

looking sharp, can you put the AnimationService on GitHub and release it to wally?

1 Like

Thanks! Maybe in the future. I have a couple of pretty big updates I want to make to the system.

I don’t really have anything to say besides that this looks awesome. Great work!

1 Like

Thank you! I appreciate the comment!

1 Like

This is game changer! roblox could never… Unless in the far far far far far far future

1 Like

Hope you like the plugin, if you have any feedback please post it here. Tnank you!

After testing it myself I have a few suggestions in mind:

Make creating an animation to be more similar to Roblox’s workflow.
Here’s proposed API change to make things consistent.

--- Created only once
local animTrack = CascadeService.CreateAnimation(GuiObject, AnimationOrPreProcessed)
local batchedAnimTrack = CascadeService.CreateAnimationBatch(GuiObjects: {}, AnimationOrPreProcessed)

--- Read only or mutable properties and Methods can be accessed like this
print(animTrack.State) --- Reads current state of the animation
animTrack:Play(Config) --- Playing the animation with exisiting optional configs
batchedAnimTrack:Play(Config) --- Playing the animation batch with exisiting optional configs

--- Optional config when stopping the animation
animTrack:Stop({
	Reset = true, --- when the animation stops its either stops at the current frame or resets to the first frame.
})

animTrack:Destroy() --- For cleanup / stops animation if playing and remove from memory

--- Connects to state changes
local conn = animTrack.StateChanged:Connect(function(state)
	print(state) --- "Started" | "Looped" | "Completed" | "Stopped"
end)
conn:Disconnect()

if conn.Connected then
	--- logic here
end

And to top it all of implement type annotations for easier use with auto-complete.
overall amazing plugin! can’t wait for the upcoming roadmap on animation events!

1 Like

Thank you for the feedback! I can add type annotations and optional config to Stop as a small patch, I think those are good additions to the API.

Changing the API to return a track instead of just playing a track is a shift in mindset, it’s a bigger change. I have to think about that one.

Right now the AnimatioService takes care of cleanup if you destroy an gui object, and the assumption that is built-in the system right now is that if you don’t destroy an object that means you will probably play an animation again on that object. That’s why the animator for that instance is kept in cache. What I could do is to update ClearBaseState to ClearInstance and remove everything for that instance.

1 Like

Could we possibly get a video? I don’t want to purchase this without a clear understanding of how to use it, even with the documentation provided.

I’ve never been a fan of animation, but I am looking for a UI keyframe based plugin. I just need to ensure that my money is being spent wisely.

1 Like

There is a link to a showcase I made a while ago under the store link. Have you seen that one? It would be ccol to get some feedback if it is missing something because I’m new to making tutorials and showcases.

1 Like

You’re right, appreciate you for letting me know.

1 Like


I’ve created a new logo for my plugin but I can’t decide which one to use. Red or Blue Scrubber? Voting ends 3 Jan 2026.

  • Red Scrubber
  • Blue Scrubber
0 voters

Hey, is there UIScale in this?

that would be amazing to use

1 Like

Just bought the plugin, I’ll try it out and give my feedbacks

1 Like