Reanimating the GeoCities Experience with react-spring
Happy Halloween! And for Halloween, we wanted to make the scariest thing we could think of… a modern version of early 2000s web design patterns.
We’re going to be building this:
It’s a web app where a small flock of bats follow your mouse around. We’re specifically going to be using React and the wonderful react-spring library to handle moving the bats around.
And if you saw the above gif and thought “That’s really not enough bats, I can still see my cursor”, here you go:
Using react-spring for animation
If you’ve never used react-spring before, it’s an incredibly easy to use library for managing animations within React.
Let’s look at a really simple example from their docs to understand how it works:
import { useSpring, animated } from '@react-spring/web'
export default function MyComponent() {
const [springs, api] = useSpring(() => ({
from: { x: 0 },
}))
const handleClick = () => {
api.start({
from: { x: 0 },
to: { x: 100 },
})
}
return (
<animated.div
onClick={handleClick}
style={{
width: 80,
height: 80,
background: '#ff6d6d',
borderRadius: 8,
...springs,
}}
/>
)
}
If we run this, we see a box that we can click on to move it to the right:
The way this works is we start off with a spring which is a core concept within react-spring. It allows you to take an animatable property (like x
or rotateZ
) and tell it both what the initial value is, as well as the final value. We trigger this transition manually by calling api.start
when the user clicks on our div.
The result is a springs
value that can be passed in directly to the style
of an animated.div
, alongside our other CSS properties.
react-spring then handles all the work of moving the box from our starting X to our final X. And for simple use cases, that’s all you really need.
There is, however, a ton more you can do within react-spring. You can, for example, add friction or mass to your moving objects. You can stop animations or trigger multiple with a fixed delay between them.
Let’s look at how we can extend this example to swarm our users with bats.
Using react-spring to chase our users around with bats
The first thing we need is a bat. I used this from Diego Gonzalez on Lottiefiles and exported it as a gif.
From there, the code is actually pretty similar to our above example. Let’s look at it in full:
import * as React from 'react'
import {animated, useSprings, config, easings} from '@react-spring/web'
import {MouseEventHandler} from "react";
export default function Bats() {
// Instead of useSpring, we'll use useSprings to create 10 bats
const [bats, api] = useSprings(10, i => ({
x: 0,
y: 0,
config: {
// You can experiment with these parameters, but I
// thought the wobbly config with an added mass
// looked the best. This impacts how quickly the
// bats move
...config.wobbly,
mass: 10,
easing: easings.easeInSine,
},
}))
// On each mouse move, we'll trigger the bats to move close to it
// Note that api.start now takes in a function that affects each bat
// separately.
const handleMouseMove: MouseEventHandler<HTMLDivElement> = (e) => {
// getRandomInt adds a little necessary chaos to the bats
// - (i * 50) is to have them all start at the same y position
api.start(i => ({
x: e.clientX + getRandomInt(-50, 50),
y: e.clientY + getRandomInt(-50, 50) - (i * 50),
}))
}
// Inside the div, we just put our bat gif
return (
<div style={{height: '100vh'}} onMouseMove={handleMouseMove}>
{bats.map((props, index) => (
<animated.div key={index} style={props}>
<img src="/bat.gif" alt="bat" width={50} height={50} />
</animated.div>
))}
</div>
)
}
// Copilot write this
const getRandomInt = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min
}
And that’s really it. By adding a little bit of random noise, stacking the bats on top of each other, and giving them some “wobbly” characteristics, we get a pretty nice animation.
react-spring handles everything, like recognizing that bats have velocity and shouldn’t just stop on a dime when they reach their intended (x, y) position.
Are there… non-bat use cases for react-spring?
Surprisingly, there are! React-spring has a lot of examples for inspiration, from clean animations when reordering a list (so you can have the nicest looking productivity app around), nice transitions between pages, or even parallax support for your marketing site.
React-spring ultimately provides a simple but advanced interface for making complex animations. Whether you use that to surround your users with bats or just to make small subtle animations on your dashboard is totally up to you!