Bring UI animations to life with roact-spring, a modern spring-based animation library

The following is a very brief introduction to roact-spring. Visit the official repository for more information.

roact-spring

GitHub | Documentation

roact-spring is a modern spring-physics based animation library for Roact inspired by react-spring. Instead of fixed durations, it uses physical properties like mass and tension to enable fluid and natural animations.

This library represents a modern approach to animation. It is the perfect bridge between declarative and imperative animations. It takes the best of both worlds and packs them into one flexible library.

Why springs and not durations

The principle you will be working with is called a spring, it does not have a defined curve or a set duration. In that it differs greatly from the animation you are probably used to. We think of animation in terms of time and curves, but that in itself causes most of the struggle we face when trying to make elements on the screen move naturally, because nothing in the real world moves like that.

image

We are so used to time-based animation that we believe that struggle is normal, dealing with arbitrary curves, easings, time waterfalls, not to mention getting this all in sync. As Andy Matuschak (ex Apple UI-Kit developer) expressed it once: Animation APIs parameterized by duration and curve are fundamentally opposed to continuous, fluid interactivity.

Why roact-spring

roact-spring comes with powerful props and configs that enable advanced UI animations. It works with almost all datatypes, greatly improving developer experience. The following are the principles of roact-spring:

Declarative and imperative

roact-spring is the perfect bridge between declarative and imperative animations. It takes the best of both worlds and packs them into one flexible library.

Fluid, powerful, painless

roact-spring is designed to make animations fluid, powerful, and painless to build and maintain. Animation becomes easy and approachable, and everything you do look and feel natural by default.

Versatile

roact-spring works with most data types and provides extensible configurations that makes it painless to create advanced animations.

Getting started

The following example uses useSpring. There are more classes and hooks to use as well as more props and configs to apply. Be sure to see the documentation for more details.

Either: declaratively overwrite values to change the animation

If you re-render the component, the animation will update.

local styles = RoactSpring.useSpring(hooks, {
    transparency = if toggle then 1 else 0,
})

If you want the animation to run on mount, you can use from to set the initial value.

local styles = RoactSpring.useSpring(hooks, {
    from = { transparency = 0 },
    to = { transparency = if toggle then 1 else 0 },
})

Or: pass a function that returns values, and imperatively update using the api

You will get an API table back. It will not automatically animate on mount and re-render, but you can call api.start to start the animation. Handling updates like this is generally preferred as itā€™s more powerful.

local styles, api = RoactSpring.useSpring(hooks, function()
    return { transparency = 0 }
})

-- Update spring with new props
api.start({ transparency = if toggle then 1 else 0 })
-- Stop animation
api.stop()

Finally: apply styles to components

return Roact.createElement("Frame", {
    Transparency = styles.transparency,
    Size = UDim2.fromScale(0.3, 0.3),
})

Demos

These demos are publicly available. Visit the repo to see their sources.

Draggable element

image

Draggable list

image

Staggered list

image

Staggered text

image

Trailing elements

image

86 Likes

Omg I love this so much itā€™s so smooth lol!, also Iā€™m unsure if itā€™s best to assign a variable with an if statement over and or.

ā€” And Or
local number = (Player.Name == ā€˜Kenā€™ and 1) or 0;

ā€” If statement
local number = if (Player.Name == ā€˜Kenā€™) and 1 or 0;

But again this is amazing! Keep up the good work :wink:

Absolutely amazing! I really like the staggered and draggable list.

and it is so smooth

2 Likes

Thanks for the comment! Itā€™s a ternary operator and is generally preferred over the ā€œfakeā€ ternary (and/or) due to the behavior of falsy values preceding an or:

-- Evaluates to 2. Should be false
true and false or 2

-- Evaluates to false as expected
if true then false else 2 

https://luau-lang.org/syntax#if-then-else-expressions

1 Like

roact-spring is now available for roblox-ts projects. Install it with npm:

npm i @rbxts/roact-spring
2 Likes

Thank you for taking on this initiative. Iā€™ll surely look at your project.

1 Like

Amazing. Reminds me of framer motion for react

1 Like

How would I go about specifying a frequency/damping ratio for the springs? I tried looking through the docs and examples but havenā€™t found anything specifying it. Is there any support for setting these values?

This. looks. AMAZING. Iā€™ll definitely be taking a look at this.

1 Like

Theyā€™re part of configs, so youā€™d pass them like any other configs like mass, precision, etc.

-- Set default configs for the spring
local styles, api = RoactSpring.useSpring(hooks, function()
    return {
        position = ā€¦,
        config = { damping = 0.8, frequency = 0.2 },
    }
})

-- Or pass config to individual starts to override default
api.start({
    position = ā€¦,
    config = { damping = 0.4, frequency = 0.3 },
})
1 Like

I donā€™t know how I missed that in the docs, sorry about that! The amount of config options is awesome- this will easily be my go-to for Roact-based projects going forward.

1 Like

Couldnā€™t help but notice thereā€™s no files for the roblox studio version unless I missed something? Iā€™m not too familiar with rojo, github etc. Would greatly benefit from one if itā€™s not out of your hands.

1 Like

@chriscerie
I install the package using wally, yet my package doesnā€™t include the ā€œuseTrailā€ module?
My Install vv

What Iā€™m missing vv
useTrail | roact-spring

Right now itā€™s only supported for rojo users. In the future, I might include roblox files in releases.

1 Like

Youā€™re installing v0.0. Make sure youā€™re using the latest version, which you can find from Wally or from releases.

roact-spring 0.3.1

Release 0.3.1 features powerful looping support. Check it out!

Loop prop

Use loop = true to repeat an animation.

-- Transparency repeatedly animates from 0 to 1
local styles = RoactSpring.useSpring(hooks, {
    from = { transparency = 0 },
    to = { transparency = 1 },
    loop = true,
})

The loop function

Pass a function to be called after each loop. Return true to continue looping, or false to stop.

-- Transparency animates from 0 to 1 three times
local count = hooks.useValue(0)
local styles = RoactSpring.useSpring(hooks, {
    from = { transparency = 0 },
    to = { transparency = 1 },
    loop = function()
        count += 1
        return 3 > count.value
    end,
})

The loop table

Define a loop table to customize the loop animation separately from the initial animation. It may contain any of the useSpring props. For example, if delay: 1 is used, the loop animation will delay for 1 second on each loop.

-- Transparency repeatedly animates from 0 to 1 with 1 second delays
local count = hooks.useValue(0)
local styles = RoactSpring.useSpring(hooks, {
    from = { transparency = 0 },
    to = { transparency = 1 },
    loop = { delay = 1, reset = true },
})
3 Likes

Huge bump But i cant find the docs for the ts version. I already liked the module, and now i wanna use it in roblox-ts

But i have no idea how to

1 Like