惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

人人都是产品经理
人人都是产品经理
D
Docker
GbyAI
GbyAI
B
Blog RSS Feed
博客园 - 司徒正美
博客园 - Franky
美团技术团队
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
aimingoo的专栏
aimingoo的专栏
C
Check Point Blog
IT之家
IT之家
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
www.infosecurity-magazine.com
www.infosecurity-magazine.com
AI
AI
O
OpenAI News
Attack and Defense Labs
Attack and Defense Labs
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
S
Secure Thoughts
博客园 - 聂微东
L
LINUX DO - 最新话题
U
Unit 42
SecWiki News
SecWiki News
A
Arctic Wolf
Schneier on Security
Schneier on Security
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
V
Visual Studio Blog
量子位
The Cloudflare Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
大猫的无限游戏
大猫的无限游戏
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
T
Threat Research - Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
B
Blog
博客园 - 【当耐特】
C
CERT Recently Published Vulnerability Notes
Scott Helme
Scott Helme
Last Week in AI
Last Week in AI
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Microsoft Security Blog
Microsoft Security Blog
Apple Machine Learning Research
Apple Machine Learning Research
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
Latest news
Latest news

Maxime Heckel's Blog

On Rendering the Sky, Sunsets, and Planets - The Blog of Maxime Heckel Shades of Halftone - The Blog of Maxime Heckel Field Guide to TSL and WebGPU - The Blog of Maxime Heckel On Shaping Light: Real-Time Volumetric Lighting with Post-Processing and Raymarching for the Web - The Blog of Maxime Heckel Speaking at Figma Config 2025 - The Blog of Maxime Heckel Post-Processing Shaders as a Creative Medium - The Blog of Maxime Heckel On Crafting Painterly Shaders - The Blog of Maxime Heckel The Art of Dithering and Retro Shading for the Web - The Blog of Maxime Heckel Moebius-style post-processing and other stylized shaders - The Blog of Maxime Heckel Shining a light on Caustics with Shaders and React Three Fiber - The Blog of Maxime Heckel Real-time dreamy Cloudscapes with Volumetric Raymarching - The Blog of Maxime Heckel Painting with Math: A Gentle Study of Raymarching - The Blog of Maxime Heckel Building a magical AI-powered semantic search from scratch - The Blog of Maxime Heckel Beautiful and mind-bending effects with WebGL Render Targets - The Blog of Maxime Heckel Refraction, dispersion, and other shader light effects - The Blog of Maxime Heckel The magical world of Particles with React Three Fiber and Shaders - The Blog of Maxime Heckel The Study of Shaders with React Three Fiber - The Blog of Maxime Heckel Building a Design System from scratch - The Blog of Maxime Heckel Everything about Framer Motion layout animations - The Blog of Maxime Heckel Building a Vaporwave scene with Three.js - The Blog of Maxime Heckel Cubic Bézier: from math to motion - The Blog of Maxime Heckel First steps with GPT-3 for frontend developers - The Blog of Maxime Heckel Building the perfect GitHub CI workflow for your frontend team - The Blog of Maxime Heckel Migrating to Next.js - The Blog of Maxime Heckel Static Tweets with MDX and Next.js - The Blog of Maxime Heckel Advanced animation patterns with Framer Motion - The Blog of Maxime Heckel Scrollspy demystified - The Blog of Maxime Heckel The Power of Composition with CSS Variables - The Blog of Maxime Heckel My first failed SwiftUI project - The Blog of Maxime Heckel Guide to creating animations that spark joy with Framer Motion - The Blog of Maxime Heckel Using Shortcuts and serverless to build a personal Apple Health API - The Blog of Maxime Heckel SEO mistakes I've made and how I fixed them - The Blog of Maxime Heckel Going native: SwiftUI from the perspective of a React developer - The Blog of Maxime Heckel Build your own preview deployment service - The Blog of Maxime Heckel The little guide to CI/CD for frontend developers - The Blog of Maxime Heckel Immigrating to the US - The Blog of Maxime Heckel Generate screenshots of your code with a serverless function - The Blog of Maxime Heckel How to use Framer Motion with Emotion styled-components - The Blog of Maxime Heckel Data Fetching with NextJS: What I learned - The Blog of Maxime Heckel Learning in public - The Blog of Maxime Heckel Fixing the dark mode flash issue on server rendered websites - The Blog of Maxime Heckel How to fix NPM link duplicate dependencies issues - The Blog of Maxime Heckel Running scheduled cross-browser end-to-end tests on Github CI - The Blog of Maxime Heckel How I built my first custom ESLint rule - The Blog of Maxime Heckel React Lazy: a take on preloading views - The Blog of Maxime Heckel Automated UI accessibility testing with Cypress - The Blog of Maxime Heckel Building a GraphQL wrapper for the Docker API - The Blog of Maxime Heckel Switching off the lights - Adding dark mode to your React app - The Blog of Maxime Heckel Getting started with Typescript on Gatsby - The Blog of Maxime Heckel Rebuilding Redux with Hooks and Context - The Blog of Maxime Heckel Asynchronous rendering with React - The Blog of Maxime Heckel Using Flow generics to type generic React components - The Blog of Maxime Heckel How to efficiently type your styled-components with Flow - The Blog of Maxime Heckel How I got started with Kubernetes on GKE - The Blog of Maxime Heckel React sub-components Part 3: Whitelisting sub-components with flow - The Blog of Maxime Heckel React sub-components Part 2: Using the new Context API - The Blog of Maxime Heckel React sub-components - The Blog of Maxime Heckel Running Golang tests with Jest - The Blog of Maxime Heckel No title No title
The physics behind spring animations - The Blog of Maxime Heckel
Maxime Heckel · 2020-06-23 · via Maxime Heckel's Blog

In the past few months, I've become a big fan of Framer Motion. After looking at how I could use it to animate my styled-components, I've been tinkering around spring animations and rebuilt almost all the transitions and animations of components in several UI projects. While showcasing the result to some fellow developers I got some questions around the meaning of some of the terms and options used to set up a spring animation like mass, stiffness, and damping. Most of them were setting them without really knowing how they were influencing the resulting animation. Lucky for them, I used to study maths and physics in college and was able to bring light on the physics behind this type of animation.

This article aims to explain how a spring animation in a library like Framer Motion works, the laws of physics that are behind it, and the relation between the different options you can set for a spring animation.

Hooke's Law

First of all, a spring animation has this name because the animation itself follows the physics of a spring or what we also call a Harmonic Oscillator. This term and the math surrounding it might seem very scary and complicated but bare with me, I'll break down everything as simply as possible. When I was in college, we defined a Harmonic Oscillator as follows:

a system that experiences a force (F) proportional to a displacement x when displaced from its equilibrium.

The formula for such force is called Hooke's Law and it is defined as follows:

where k is a positive constant called stiffness which we can also write as:

What that means is that:

  • if we pull the spring (i.e. x > 0 ) to a certain distance away from its equilibrium, it will start to move

  • if we don't pull it, it won't move (i.e. x = 0)

However, maybe you might have heard at school or on one of the many science-focused Youtube channels on that force is the object's mass times its acceleration, which translates to the following formula:

where m is the mass and a is the acceleration.

Thus given this formula and the formula above, we can deduct that:

which is equivalent to

We now have an equation from which we define the acceleration based on the displacement of our spring and the mass of the object attached to that spring. From the acceleration we can deduct the following:

  • the velocity of the object at any given time

  • the position of the object at any given time

To get the velocity of the object, you need to add the acceleration rate to the previously recorded velocity, which can translate to the following equation:

Finally, we can get the position as it follows a similar principle: the position of the object is equal to the previously recorded position to which we add the velocity:

For the time interval, as frontend developers, we might know it better as a frame rate or "frames per second". Considering the smoothness of Framer Motion's animations we can assume that its spring animations runs at 60 frames per second thus a time interval that is constant and equal to 1/60 or 0.01666.

Translating the maths to Javascript

Now that we've done the math, you can see that by knowing the mass of the object, the stiffness and the displacement of our spring, we can know the position of the object attached to that spring at any given time, i.e at any given frame. We can translate all the equations above in Javascript, and for a given displacement calculate all the positions of an object for 600 frames, i.e. 10 seconds:

Function that returns the positions of an object following the motion of a spring

1

const loop = (stiffness, mass) => {

13

let frameRate = 1 / 60;

21

let Fspring = k * (x - springLength);

23

let a = Fspring / mass;

I built this small playground below with a graph representation of the positions that are returned by the function above a component animated by Framer Motion that has the same mass and stiffness. You can tune the mass and the stiffness with the range inputs above the graph and observe how each variable influences the animated component and the graph of positions.

Taking damping into account

While observing the visualization above, you might have wondered why is the spring animation never-ending as opposed to the ones you might have tried yourself with Framer Motion. That is because the math formulas we used to generate the position of the object were not taking into account friction and heat. If we want to obtain a spring animation that feels natural, we should see the movement of the object slowing down as time passes to eventually stop moving. That is where the damping comes into the picture. You might have seen this term when looking at the documentation of Framer Motion and wondered what it meant or does to the resulting spring animation, here's how we will define it:

Damping is the force that slows down and eventually stops an oscillation by dissipating energy

Its formula is:

where d is the damping ratio and v the velocity

Taking damping into account will bring some changes to the acceleration formula we established in the first part. We know that

However, F here is equal to the spring force and the damping force, instead of just the spring force, thus:

1

Fs + Fd = m*a -> a = (Fs + Fd)/m

We can now add this new formula to the Javascript code we've showcased in the previous part (I highlighted the additions I've made to the code compared to the previous implementation):

Updated function that takes into account the damping ratio

1

const loop = (stiffness, mass, damping) => {

16

let frameRate = 1 / 60;

23

let Fspring = k * (x - springLength);

26

let a = (Fspring + Fdamping) / mass;

And finally, represent the resulting position data in the playground:

As you can see we now have a spring animation that eventually stops due to damping dissipating the energy out of the system. The chart above showcases this by converging towards a final "resting position". By increasing the damping slider to a high value you can observe that the object subject to spring animation tends to converge to the "resting position" way faster than for a lower damping value.

A real-life example

By default, Framer Motion sets the stiffness of the spring animation to 100, the damping to 10, and the mass to 1 according to the docs. Below, I wrote an animated Button component that is closer to a real-life example that you might want to implement in your UI projects. Now that you know what mass, stiffness and damping you can try to fine-tune your spring animation.

import { motion } from 'framer-motion';
import './scene.css';

const Example = () => {
  return (
    <motion.button
      style={{
        background:
          'linear-gradient(180deg, #ff008c 0%, rgb(211, 9, 225) 100%)',
        color: 'white',
        height: '50px',
        width: '200px',
        borderRadius: '10px',
        border: 'none',
        boxShadow: 'none',
        outline: 'none',
        cursor: 'pointer',
      }}
      whileTap={{
        scale: 1.3,
        borderRadius: '6px',
      }}
      transition={{ type: 'spring', stiffness: 100, damping: 10, mass: 1 }}
    >
      Click me!
    </motion.button>
  );
};

export default Example;

Want to learn more the math/physics behind animations you see on a day-to-day basis?

I dedicated an entire blog post about the math behind Cubic Béziers that contains slick visualizations that easily explain how the motion these complex formulas define is obtained!

Want to learn more about Framer Motion?

Checkout my blog post Guide to creating animations that spark joy with Framer Motion!