Building apps with physics-based animations


by Conrad VanLandingham

I find UI animations very difficult to get just right. Usually, I end up with trial-and-error durations and timing-functions spread across an app between numerous CSS transitions and/or Velocity calls to get everything feeling consistent and performant. CSS animations are great for doing simple transitions, but can get out of hand easily (especially when sequencing) and I’ve seen inconsistent behavior from browser-to-browser, especially in how they handle interruptions. Javascript libraries such as Velocity and Greensock make tremendous leaps in sequencing, performance, and animating more advanced properties, but still require you to resort to using your hard-coded easing curves and durations.

That’s where the concept of using physics-backed spring animations come in (and no, I don’t mean just making everything bounce around). Consider touch-scrolling on iOS: when you drag your finger across the screen, the content tracks along with it. But when you lift your finger, physics happens (MAGIC!) - the content continues tracking with the same momentum and slows down naturally. If you “throw” the content past the end of its bounds, its momentum is absorbed with a virtual spring that pushes back on it until it reaches equilibrium. This interaction feels very natural, and could not be achieved with pre-determined easing and timing functions.

Now imagine attaching virtual springs to your normal DOM elements. Instead of saying that you want to move an element to the left 100 pixels over 1 second (with perhaps a cubic bezier ease), you can just say move to -100 pixels, and the spring “attached” to that element would take care of calculating its animation, literally “pulling” it to the left. Essentially, we’re just using the physical properties of a spring to determine an object’s speed and position over time.

Springs have two general properties to control its characteristics - tension and friction. Tension defines how much force the spring has built up when it is ‘released’ (when the animation starts). The higher the tension, the faster the spring moves (and the more it’ll tend to oscillate). Friction, on the other hand, ensures that the spring doesn’t move indefinitely, and once you have a high enough value it will almost not oscillate at all. The same tension and friction constant could be used for an entire application so that all of the animations have a consistent feel, yet each use a velocity and acceleration pattern that’s dependent on that object’s current velocity and where its rest position will be.

That element that you’re moving left 100 pixels - lets say halfway through that movement the user canceled the action that started the movement, and you want the element to move back to 0. Your spring, taking in to account its current velocity going the opposite direction would naturally slow down and start accelerating back towards point 0. And all you had to do is update that Spring’s position to 0 again.

There are a few libraries that implement Spring physics for the purpose of animating UI elements. Facebook’s Rebound seems to be pretty well known, and has a Javascript port - http://facebook.github.io/rebound-js/docs/rebound.html. Another Facebook developer has started a React-specific library, React-Motion, with components that utilize Spring physics (and doesn’t rely on Rebound) https://github.com/chenglou/react-motion. Its API is for the most part very simple and nice:

import {Motion, spring} from 'react-motion';
// An element that springs 100 pixels to the left

<Motion defaultStyle={{x: 0}} style={{x: spring(-100)}}>
  {value => <div style={{left: value.x}}>My Element!</div>}
</Motion>

I am also working on a React library that I invite you to take a look at - Rey. It’s not quite ready yet for a proper introduction/tutorial, so I will save that for another blog post. But its basic goal (and why I’m building it over just using React Motion, for example) is to create “transition states” that can be set up outside the context of a component (think stylesheets, but for transitions). I personally believe animation logic does not belong in line with the rest of your component’s logic and code - even worse to mix that logic in between CSS transitions and arbitrary JS code. Moving towards modular components (with CSS Modules), I envision a file structure that looks more like:

/my-component
	MyComponent.js
	style.css
	transitions.js
	…

Where transitions.js could almost be as simple as exporting an object similar to:

export const transitionStates = {
  opened: {
    y: 0,
    opacity:1
  },
  closed: {
    y: -100,
    opacity: 0
  }
}

Note: this is not the actual API for Rey; is just an illustration

Of course, Rey won’t force you to define your transitions like this, and I also have other motivations for the project that I hope to touch more on later. It does some cool things already - such as the ability to create a dynamic “chain” of springs that follow each other. It tries to fit in nicely with React’s built-in components, including compatibility with React’s TransitionGroup (which React-Motion does not). Also, most of the code so far inherits from Rebound directly, and will expose Rebound’s API so that all functionality available in Rebound is immediately usable.

I invite you to check out Rey - and if you do, please open up an issue on github or shoot me a message with feedback on the API or any ideas you have. I welcome pull requests too.

Lastly, you should check out Rebound’s example page. It has a neat “photo scale animation” demo at the bottom that allows you to see the effect of tension and friction on a spring - http://facebook.github.io/rebound-js/examples/.

Share Share on Twitter Share on Facebook Share on LinkedIn

How Can We Help?

Reaching out doesn’t mean you’re ready to start a project, but we’d love to learn more about the challenge you’re facing, answer any questions, and see if we might be a good fit for working together.

Contact Us