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

推荐订阅源

Cloudbric
Cloudbric
T
Threat Research - Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
AWS News Blog
AWS News Blog
P
Privacy & Cybersecurity Law Blog
H
Help Net Security
云风的 BLOG
云风的 BLOG
G
GRAHAM CLULEY
Spread Privacy
Spread Privacy
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
Arctic Wolf
Project Zero
Project Zero
Engineering at Meta
Engineering at Meta
P
Privacy International News Feed
Blog — PlanetScale
Blog — PlanetScale
Stack Overflow Blog
Stack Overflow Blog
M
MIT News - Artificial intelligence
The Register - Security
The Register - Security
Recorded Future
Recorded Future
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
C
Cisco Blogs
PCI Perspectives
PCI Perspectives
Recent Announcements
Recent Announcements
Martin Fowler
Martin Fowler
A
About on SuperTechFans
W
WeLiveSecurity
GbyAI
GbyAI
V
Vulnerabilities – Threatpost
The GitHub Blog
The GitHub Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
C
Check Point Blog
Y
Y Combinator Blog
月光博客
月光博客
Scott Helme
Scott Helme
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
U
Unit 42
G
Google Developers Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Threatpost
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google Online Security Blog
Google Online Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
Hugging Face - Blog
Hugging Face - Blog
MongoDB | Blog
MongoDB | Blog
博客园 - 司徒正美

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 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 The physics behind spring animations - 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
Cubic Bézier: from math to motion - The Blog of Maxime Heckel
Maxime Heckel · 2021-11-02 · via Maxime Heckel's Blog

Over the past few months, I've been working a lot on my Design System and one aspect of this work that I enjoyed focusing on is micro-interactions ✨. These can be very tedious to get right, but if built properly they can make components go from good to exceptional!

However, more recently, I brought my attention to something a bit more subtle. While iterating on a button component hover transition, using timing functions such as linear ease-in or ease-out did not feel quite right. The only way I achieved a satisfying result was to set my CSS transition property to the following: cubic-bezier(0.34, 1.56, 0.64, 1), which I copied-pasted from a Codepen without really knowing what those values and function were doing, which, to be honest with you, is the kind of thing that always bothers me  😅. I like to understand the tools I'm using.

So, I went down a rabbit hole of math, animations, and code to have a clear understanding of what cubic-bezier really is, and also what the numbers I passed to that function meant and how they translate to motion. Hence the title of this blog post! We'll first deep dive into the math behind cubic-bezier, then try to visualize how the graphical representation of this function translates into motion and how it relates to other timing functions you might be familiar with. All of that, illustrated through interactive visualizations to allow you to see and tweak the math that's behind these beautiful transitions ⭐️.

The math behind Bézier curves

First, what's really behind this cubic-bezier function we keep seeing in our CSS codebases? Well, to simply put it, this function defines what is called a Cubic Bézier curve. It's a specific type of curve, that helps represent how a transition goes from an initial state to a final state.

Why Cubic? That is where the math part of this article comes in. To start let's look at the definition of the umbrella term "Bézier curve":

A Bézier curve is a parametric curve defined by a set of control points

We can start our discovery of Bézier curves by looking at their simplest form to understand what these "control points" are, and then slowly make our way up in complexity to reach its cubic form.

Linear Interpolation

Let's consider two distinct points P0 and P1, and another point P that's located between them. In this scenario, P0 and P1 are the control points of the curve, and P is a point that moves between them. We can define the position of P with a value between 0 and 1 named t that is similar to a percentage:

  • if t = 1, P will move to P1

  • if t = 0, P will move to P0

  • any values between 0 and 1 would be a "mix" of P0 and P1

I represented this example in the widget below, where P0 and P1 are at the extremities of the curve, and P is the blue dot moving between them. You'll see that the closer from 1 t is, the closer from the end of the curve P will be.

Linear Bézier Curve / Linear interpolation

This is called a Linear Interpolation.

Quadratic Bézier

Let's add another point! We can now have two interpolated points, between each segment, moving respectively on the axis P0 -> P1 and P1 -> P2. If we link these two points (the red dots) with a segment and position an interpolated point (the blue dot) on it as well, we'll obtain something rather interesting:

You can see that the blue dot follows a specific path that resembles a curve. This specifc one is called a Quadratic Bézier curve.

Here's the Javascript version of that formula that I use to get the coordinates x and y of all the positions of the blue dot for 1 second at 60 frames per second to draw the curve above:

1

const quadratic = (P0, P1, P2) => {

12

Math.pow(1 - t, 2) * x0 + 2 * (1 - t) * t * x1 + Math.pow(t, 2) * x2;

15

Math.pow(1 - t, 2) * y0 + 2 * (1 - t) * t * y1 + Math.pow(t, 2) * y2;

20

for (let t = 0; t <= 1; t = t + 1 / 60) {

23

res.push({ x: valX, y: valY });

25

res.push({ x: 1, y: 0 });

Cubic Bézier

Now, if we add a fourth point (so we now have the control points P0, P1, P2, and P3), and follow the same process as before:

  1. we add an interpolated point between each of the segments that link the 4 points (in red below)

  2. we link these interpolated points and define an interpolated point for each of the newly obtained segments (in green)

  3. we link again these points, draw a segment between them, and add yet another interpolated point (in blue)

we finally obtain a the formula representing a Cubic Bézier curve. I know this may sound very complicated at this point, so I hope the visualization below will do a good job at illustrating how this curve is obtained:

Below you'll find the JS version of that formula which, like its quadratic counterpart, will return all the coordinates x and y of all the points describing the position of the blue dot along this Cubic Bézier curve, for 1 second at 60 frames per second:

1

const cubic = (P0, P1, P2, P3) => {

15

Math.pow(1 - t, 3) * y0 +

16

3 * Math.pow(1 - t, 2) * t * y1 +

17

3 * (1 - t) * Math.pow(t, 2) * y2 +

21

Math.pow(1 - t, 3) * x0 +

22

3 * Math.pow(1 - t, 2) * t * x1 +

23

3 * (1 - t) * Math.pow(t, 2) * x2 +

28

for (let t = 0; t <= 1; t = t + 1 / 60) {

31

res.push({ x: valX, y: valY });

33

res.push({ x: 1, y: 0 });

Visualizing the motion

We just did the hard part! 🎉 We broke down the math behind Bézier curves into small bits and slowly combined them to obtain the Cubic Bézier formula and represent its corresponding curve. Now we can see how this Cubic Bézier curve relates to transition and motion in general.

For this part, we consider the Cubic Bézier formula from the previous section and draw its representation but with a twist:

  • we set the control point P0 with the coordinates x:0, y:0

  • we set the control point P3 with the coordinates x:1, y:1

The reason behind that is that the cubic-bezier function in CSS uses two implicit points:

  • P0 represents the initial time x:0 and the initial state y:0. It's the point where our curve starts.

  • P3 represents the final time x:1 and the final state y:1. It's the point where our curve ends.

Thus, this leaves us with only two control points to define: P1 and P2. Now, remember when I gave the example of a cubic-bezier function I used for one of my transition in the intro?

cubic-bezier(0.34, 1.56, 0.64, 1)

The four numbers passed to this function are the coordinates of the control points P1 and P2: cubic-bezier(P1.x, P1.y, P2.x, P2.y). Setting those points gives us a specific curve representing the motion that the element with this timing function will follow during its transition.

To better illustrate that, I built the little Cubic Bezier visualizer below ✨. With it, you can change the position of P1 and P2 by moving the gray handles and get the Cubic Bézier curve corresponding to those values!

The visualizer also allows you to:

  1. see the position an element (the blue dot in this case) throughout its motion for each frame

  2. project the position of the element to observe the change in y value, i.e. the trace of the motion of the element through time, by toggling Project Points on.

By projecting the positions throughout the transition, we can "see" the motion of our element represented by a Cubic Bézier with these specific control points. This is how the "math becomes motion".

Some interesting things you can observe with the motion of this point:

  • we render the position of the point at each frame of the motion

  • the further apart two consecutive points in the trace are, the faster the motion is: the blue dot spends "less time" at a given position.

  • the more narrow the gap between two consecutive points in the trace is, the slower the motion is: the blue dot spends "more time" at that given position.

Easing functions

Now that we know what is truly behind the cubic-bezier CSS function, you might be wondering how the other timing functions you might be familiar with such as ease-in or linear relate to that. In a nutshell, they are actually Cubic Bézier themselves!

Cubic Béziers, Cubic Béziers everywhere

We can describe any of linear, ease-in, ease-out, ease-out in cubic-bézier form. The only thing to do to obtain these specific timing functions is to set the values of the coordinates for P1 and P2 accordingly.

These are just the set of cubic-bezier timing functions available to us out of the box in CSS. There are many types of "ease" transitions that can be represented with specific Cubic Bézier curves. You can visualize some of those below with their corresponding P1 and P2 points:

Thus, not only uncovering the math behind Cubic Bézier helped us understand the cubic-bézier CSS function, but also a large number of easing functions that are used by many on a day-to-day basis!

Cubic Bézier in Framer Motion

Another aspect that re-affirms the tight relationship between Cubic Bézier and easing functions can be found in the design choices made in Framer Motion's transition object.

Unlike what we've seen so far with CSS, there's is no cubic-bézier function per se in Framer Motion. To describe this type of transition you just need to pass the values of the coordinates of your P1 and P2 points as an array to the ease property:

Example of cubic-bezier like transition in Framer Motion

1

import { motion } from 'framer-motion';

3

const Button = (props) => {

4

const buttonVariants = {

18

variants={buttonVariants}

20

ease: [0.34, 1.56, 0.64, 1],

Conclusion

Wow, what a ride! We went from looking at cubic-bezier(0.34, 1.56, 0.64, 1) a bit clueless and not knowing what it meant to:

  • understand the mathematical concepts that govern Bézier curves

  • being able to draw the graphical representation of Cubic Bézier and understand how it translates to motion

  • analyze the close relationship between cubic-bézier and the easing functions we've always been familiar with

Yet, despite having learned a lot together, we've just scratched the surface! We only took a look at CSS but Bézier curves, and especially its cubic form, can be found in many other frontend adjacent tools/process like:

  • in the Chrome Dev tools or other awesome frontend tools such as Leva

Screenshot showcasing the Chrome Dev Tools with the Cubic Bézier editor

Screenshot showcasing the Chrome Dev Tools with the Cubic Bézier editor
  • Design tools like Figma, to draw anything from curves, shapes, and even fonts!

I hope this blog post satisfied your curiosity and helped you learn some of the cool things that hide behind the tools we use on a day-to-day basis. You can now play with the cubic-bézier function with confidence in your code and know exactly what to tweak to come up with unique / delightful transitions and animations for your components.

Quick shoutout to 3 awesome people who helped me directly or indirectly to produce this piece by sharing their own creations around this subject:

  • @pixelbeat who created an awesome Framer prototype to visualize easing curves

  • @FreyaHolmer who made an absolutely amazing Youtube video about Bézier curves. She goes way further into the weeds than this article, thus I highly recommend checking this video out if you want to go further. Her way of illustrating and explaining these complex concepts is really inspiring.