Cubic-bezier implementation for your JavaScript animation easings – MIT License

Overview

bezier-easing Build Status

BezierEasing provides Cubic Bezier Curve easing which generalizes easing functions (ease-in, ease-out, ease-in-out, ...any other custom curve) exactly like in CSS Transitions.

Implementing efficient lookup is not easy because it implies projecting the X coordinate to a Bezier Curve. This micro library uses fast heuristics (involving dichotomic search, newton-raphson, sampling) to focus on performance and precision.

It is heavily based on implementations available in Firefox and Chrome (for the CSS transition-timing-function property).

Usage

var easing = BezierEasing(0, 0, 1, 0.5);
// easing allows to project x in [0.0,1.0] range onto the bezier-curve defined by the 4 points (see schema below).
console.log(easing(0.0)); // 0.0
console.log(easing(0.5)); // 0.3125
console.log(easing(1.0)); // 1.0

(this schema is from the CSS spec)

TimingFunction.png

BezierEasing(P1.x, P1.y, P2.x, P2.y)

Install

npm install bezier-easing

It is the equivalent to CSS Transitions' transition-timing-function.

In the same way you can define in CSS cubic-bezier(0.42, 0, 0.58, 1), with BezierEasing, you can define it using BezierEasing(0.42, 0, 0.58, 1) which have the `` function taking an X and computing the Y interpolated easing value (see schema).

License

MIT License.

Tests

Build Status

npm test

See also

Who use it?

More informations

Implementation based on this article.

Contributing

You need a node installed.

Install the deps:

npm install

The library is in index.js.

Ensure any modication will:

  • keep validating the tests (run npm test)
  • not bring performance regression (compare with npm run benchmark – don't rely 100% on its precision but it still helps to notice big gaps)
  • Run the visual example: npm run visual
Comments
  • Looking to make complex curves

    Looking to make complex curves

    First of all, this is an awesome library! I spent a long time looking for implementations a couple of weeks ago and didn't find this.

    I'm looking at using this for some animations we are working on where we have some complex animation curves and I was wondering if you might be able to confirm if my idea should work, and also whether you might like it as a PR for this repo.

    So, what we need is a way to specify curves with multiple control points and still interpolate from 0 -> 1.

    This one, for example, does 80% of its movement in the first 20% of time and the final 20% in the last 80% of time.

    The curve for the first bit is [0.23830050393398, 0, 0.25586732616931, 0.79011192334632] and the second is [0.21787238302442, 0.98324004924648, 0.58694150667646, 1].

    What I'm planning is something taking a list of points and control points and be able to use them as if they were one curve:

    var curve = [{
        cp: [0.23830050393398, 0, 0.25586732616931, 0.79011192334632],
    }, {
        cp: [0.21787238302442, 0.98324004924648, 0.58694150667646, 1],
        p: [0.2, 0.8] // first curve will finish at [0.2, 0.8], rest of the curve follows the cp above
    }];
    
    var easing = cubicBezier(curve);
    
    easing(0); // = 0
    easing(0.2); // = 0.8 because we are at the end of the first curve
    easing(1); // 1
    

    So, the first curve would go from 0 -> 0.2, you would take the values from the curve and times them by 0.2 (because a 1 from the first curve would put you at 0.2 on the total curve). The second curves values would be 0.2 + 0.8*secondCurve.

    I imagine it would work that, a single control point wouldnt need a p value because it would go from 0 -> 1 as normal, for two onwards you have p to tell you where the last curve finished.

    So my two questions, does this work out mathematically as far as you can tell? And would you like a PR when I try this later?

    Thanks again

    opened by lukebatchelor 11
  • Very slow on babel+rollup ES6/ES7 compilation

    Very slow on babel+rollup ES6/ES7 compilation

    I've made a lebab conversion of your code, imported into my test setup and my compilation time jumped from 700-1100ms to 15-17s.

    I've searched the web all day for a solution, people talk about leaky scripts, I've re-installed node.js couple of times, searched for self executing anonymous functions, and other shenanigands, I didn't realize it's your script until I made a build without your it.

    Any plans to help solve this issue?

    opened by thednp 8
  • Hi. I made another bezier version, but it's not working properly, it's always liniar

    Hi. I made another bezier version, but it's not working properly, it's always liniar

    Can you tell why this is always liniar? Here it is:

    var bezier = function(mX1, mY1, mX2, mY2) {
        this.mX1 = mX1;
        this.mY1 = mY1;
        this.mX2 = mX1;
        this.mY2 = mY2;
        return bz.pB(mX1, mY1, mX2, mY2);
    }
    var bz = bezier.prototype;
    
    // These values are established by empiricism with tests (tradeoff: performance VS precision)
    bz.ni    = 4; // NEWTON_ITERATIONS
    bz.nms   = 0.001; // NEWTON_MIN_SLOPE
    bz.sp    = 0.0000001; // SUBDIVISION_PRECISION
    bz.smi   = 10, // SUBDIVISION_MAX_ITERATIONS
    
    bz.ksts = 11; // k Spline Table Size
    bz.ksss = 1.0 /  (bz.ksts - 1.0); // k Sample Step Size
    
    bz.f32as = 'Float32Array' in window; // float32ArraySupported
    bz.msv = bz.f32as ? new Float32Array (bz.ksts) : new Array (bz.ksts); // m Sample Values
    bz._p = false;
    
    bz.A = function(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; };
    bz.B = function(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; };
    bz.C = function(aA1)      { return 3.0 * aA1; };
    
    // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
    bz.cB = function(aT, aA1, aA2) { // calc Bezier
        return ((bz.A(aA1, aA2)*aT + bz.B(aA1, aA2))*aT + bz.C(aA1))*aT;
    };
    
    // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
    bz.gS = function (aT, aA1, aA2) { // getSlope
        return 3.0 * bz.A(aA1, aA2)*aT*aT + 2.0 * bz.B(aA1, aA2) * aT + bz.C(aA1);
    };
    
    bz.bS = function(a, aA, aB) { // binary Subdivide
        var x, t, i = 0;
        do {
            t = aA + (aB - aA) / 2.0;
            x = bz.cB(t, bz.mX1, bz.mX2) - a;
            if (x > 0.0) {
                aB = t;
            } else {
                aA = t;
            }
        } while (Math.abs(x) > bz.sp && ++i < bz.smi);
        return t;
    };
    
    bz.nri = function (aX, agt) { // newton Raphs on Iterate
        for (var i = 0; i < bz.ni; ++i) {
            var cs = bz.gS(agt, bz.mX1, bz.mX2);
            if (cs === 0.0) return agt;
            var x = bz.cB(agt, bz.mX1, bz.mX2) - aX;
            agt -= x / cs;
        }
        return agt;
    };
    
    bz.csv = function () { // calc Sample Values
        for (var i = 0; i < bz.ksts; ++i) {
            bz.msv[i] = bz.cB(i * bz.ksss, bz.mX1, bz.mX2);
        }
    };
    
    bz.gx = function (aX) { //get to X
        var is = 0.0, cs = 1, ls = bz.ksts - 1;
    
        for (; cs != ls && bz.msv[cs] <= aX; ++cs) {
            is += bz.ksss;
        }
        --cs;
    
        // Interpolate to provide an initial guess for t
        var dist = (aX - bz.msv[cs]) / (bz.msv[cs+1] - bz.msv[cs]),
            gt = is + dist * bz.ksss,
            ins = bz.gS(gt, bz.mX1, bz.mX2);
    
        if (ins >= bz.nms) {
            return bz.nri(aX, gt);
        } else if (ins === 0.0) {
            return gt;
        } else {
            return bz.bS(aX, is, is + bz.ksss, bz.mX1, bz.mX2);
        }
    };
    
    bz.pB = function (mX1, mY1, mX2, mY2) {
        bz.mX1 = mX1;
        bz.mX2 = mX2;
        bz.mY1 = mY1;
        bz.mY2 = mY2;
    
        return function(aX) { // process bezier
    
            if (!bz._p) bz.pc();
            if (bz.mX1 === bz.mY1 && bz.mX2 === bz.mY2) return aX; // linear
    
            if (aX === 0) return 0;
            if (aX === 1) return 1;
            return bz.cB(bz.gx(aX), bz.mY1, bz.mY2);
        };
    };
    
    bz.pc = function() {
       bz._p = true;
        if (bz.mX1 != bz.mY1 || bz.mX2 != bz.mY2)
        bz.csv();
    };
    
    

    BTW: this is the fastest blade in the land in terms of performance.

    Thanks for any reply.

    opened by thednp 8
  • Is this intentional behavior?

    Is this intentional behavior?

    The two for loops look like this:

    var kSplineTableSize = 11;
    var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0);
    
    for (var i = 0; i < kSplineTableSize; ++i) {
    	sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2);
    }
    
    var intervalStart = 0.0;
    var currentSample = 1;
    var lastSample = kSplineTableSize - 1;
    
    for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) {
    	intervalStart += kSampleStepSize;
    }
    --currentSample;
    
    // Interpolate to provide an initial guess for t
    var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]);
    var guessForT = intervalStart + dist * kSampleStepSize;
    

    So as you can see, the first loop creates an array with keys [0, 10]. The second loop runs for keys [1, 9]. This means that currentSample cannot be 9 (after --currentSample), which also means intervalStart can not be 1, even if sampleValues[10] <= aX. In other words, currentSample is 8 at max and intervalStart is 0.9 max. That means that the dist estimate will at max will use the values sampleValues[8] and sampleValues[9].

    I am not sure whether this is intentional or a bug.

    If it is intentional, there is no reason to have the first for loop run for i=10 and should only go to 9, as sampleValues[10] is never used by this code.

    opened by Validark 5
  • Typings file not found in latest npm install

    Typings file not found in latest npm install

    Hi @gre , In the latest npm install of bezier-easings, the index.d.ts #29 file added by @MonsieurMan is missing. I am also getting this error in chrome TypeError: bezier_easing_1.bezier is not a function. Are they related or the cause is different?

    opened by agugan 4
  • New version, problem with GSAP

    New version, problem with GSAP

    Hello, I have a minified of a 2014's version of BezierEasing. When I require with browserify into a var called BezierEasing it works, cause it's a function that return something.

    Now I have installed the newest version of BezierEasing with NPM and required index.js into the same var, and GSAP give me an error, cause BezierEasing(myEase) passed into Ease object is not a function.

    My Code

    var BezierEasing = require('bezier-easing');
    
    TweenMax.fromTo($myEl, .7, {
        yPercent: 40,
        autoAlpha:0
    }, {
        yPercent: 0,
        autoAlpha:1,
        ease:new Ease(BezierEasing(0.51,0.01,0,1))
    });
    

    Can I have more info about that ?

    Unfortunately I don't have the version number cause I found the min file on my PC from an old project.

    Thank You,

    Lorenzo

    opened by liqueflies 4
  • Curve not working on Raspberry Pi in QML

    Curve not working on Raspberry Pi in QML

    I'm trying to use this project to ease animations in a QML canvas. Implementing and using works fine, at least when run on a Windows machine in Qt 5.7.0 But as soon as I try to run it cross compiled on a Raspberry Pi 3 the curve becomes a linear function. I have no idea what's going wrong here, Qt reports that JIT support is not enabled on the Pi, maybe that is a possible cause for the problem? Every time calcBezier is run I print the input and output values, also float32ArraySupported. On both machines float32ArraySupported is true, and the values are about the same. The code is 100% identical. I have no clue how to fix this.

    My curve is (0.7, 0, 1-0.7, 1)

    opened by yspreen 3
  • Add Universal Module Definition

    Add Universal Module Definition

    This eliminates a spurious error in the console when not using a CommonJS environment.

    The indentation of the main code bloc was left unchanged to avoid touching every line of code.

    opened by ptlis 3
  • Highly optimized and very tiny bezier script

    Highly optimized and very tiny bezier script

    function Bezier(mX1, mX2, mY1, mY2) {
      var isLinear = mX1 === mY1 && mX2 === mY2;
      return function (aX) {
       return (isLinear || aX === 0 || aX === 1) ? aX : (((1.0 - 3.0 * mY2 + 3.0 * mY1) * aX + (3.0 * mY2 - 6.0 * mY1)) * aX + (3.0 * mY1)) * aX;
      }
     }
    // copyright (c) 2015 @dalisoft. All right reserved
    
    opened by dalisoft 3
  • Share common functions between bezier functions.

    Share common functions between bezier functions.

    • That way the constructor is faster (16% faster aprox, measured in http://jsperf.com/bezier-easing-benchmark).
    • Also, since all bezier curves share memory references to the same functions instead of having its own copy, it will save memory, although I haven't measured how much it saves.
    • The execution times are identical. Measured in http://jsperf.com/bezier-easing-execution
    opened by cibernox 3
  • Food for thought: accessing points

    Food for thought: accessing points

    I've run into a couple of places where I'm using arbitrary BezierEasing objects generated outside of my control, and it would be useful to have access to the four arguments that were used to create them. (For example, to create the inverse curve to determine the t at which the position reaches 0.1. Could be an easier way?) I wonder if you think it makes sense to expose the four values used to generate the function? Of course parsing the toString isn't what I'm looking for. =) (Very nice toString though!)

    If so: exposing them as simple mutable properties might be bad, as it gives the impression that they should be mutable (I don't think they should be). Proper getters and setters aren't cross-platform enough. Maybe a function like toString that returns an array?

    Anyway, if you have any thoughts on this, I'd be happy to execute and make a pull request.

    opened by dcporter 3
  • Bump decode-uri-component from 0.2.0 to 0.2.2

    Bump decode-uri-component from 0.2.0 to 0.2.2

    Bumps decode-uri-component from 0.2.0 to 0.2.2.

    Release notes

    Sourced from decode-uri-component's releases.

    v0.2.2

    • Prevent overwriting previously decoded tokens 980e0bf

    https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.1...v0.2.2

    v0.2.1

    • Switch to GitHub workflows 76abc93
    • Fix issue where decode throws - fixes #6 746ca5d
    • Update license (#1) 486d7e2
    • Tidelift tasks a650457
    • Meta tweaks 66e1c28

    https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.1

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • 'bezier-easing'. CommonJS or AMD dependencies can cause optimization bailouts.

    'bezier-easing'. CommonJS or AMD dependencies can cause optimization bailouts.

    Hi, when building angular apps there is a warning if we use this package.

    Is there any workaround?

    I know i can add the package to allowedCommonJsDependencies to get rid of the warning, but the issue remains.

    opened by Sergiobop 0
Owner
@greweb
👾 👨‍👩‍👦‍👦 👨🏻‍🌾 🌱 🀄️ 🍷 🥖
@greweb
Give your pages some headroom. Hide your header until you need it

Headroom.js Headroom.js is a lightweight, high-performance JS widget (with no dependencies) that allows you to react to the user's scroll. The header

Nick Williams 10.9k Jan 4, 2023
Stand-alone parallax scrolling library for mobile (Android + iOS) and desktop. No jQuery. Just plain JavaScript (and some love).

Please note: skrollr hasn't been under active development since about September 2014 (check out the contributions graphs on https://github.com/Prinzho

Alexander Prinzhorn 18.6k Jan 3, 2023
Simple and tiny JavaScript library that adds parallax animations on any images

simpleParallax.js simpleParallax.js is a very simple and tiny Vanilla JS library that adds parallax animations on any images. Where it may be laboriou

Geoffrey 1.5k Jan 3, 2023
Lightweight, vanilla javascript parallax library

RELLAX Rellax is a buttery smooth, super lightweight, vanilla javascript parallax library. Update: Rellax now works on mobile (v1.0.0). Demo Website G

Dixon & Moe 6.7k Dec 30, 2022
Customizable, Pluginable, and High-Performance JavaScript-Based Scrollbar Solution.

Smooth Scrollbar Customizable, Flexible, and High Performance Scrollbars! Installation ⚠️ DO NOT use custom scrollbars unless you know what you are do

Daofeng Wu 3k Jan 1, 2023
Scroll-stash - A JavaScript plugin to help preserve an element's scroll position.

scroll-stash A JavaScript plugin to help preserve an element's scroll position. CodePen Example Installation npm install scroll-stash JavaScript Impo

Sebastian Nitu 5 Sep 5, 2022
Simple & lightweight (<4kb gzipped) vanilla JavaScript library to create smooth & beautiful animations when you scroll.

lax.js Simple & lightweight (<4kb gzipped) vanilla JavaScript library to create smooth & beautiful animations when you scroll. >> DEMO << What's new w

Alex Fox 9.4k Dec 29, 2022
🚀 Scroll Follow Tab is a lightweight javascript library without jQuery, no dependencies.

Scroll Follow Tab is a lightweight javascript library without jQuery, no dependencies. It is used to make scrollspy effect for your menu, table of contents, etc. Only 21.7Kb.

Hieu Truong 11 Jun 20, 2022
An implementation of Bézier curve rendering and manipulation, using the HTML5 Canvas API.

Bézier Curves An implementation of Bézier curve rendering and manipulation, using the HTML5 Canvas API. How does it work? Bézier curves can be simply

nethe550 1 Apr 13, 2022
Quick and easy spring animation. Works with other animation libraries (gsap, animejs, framer motion, motion one, @okikio/animate, etc...) or the Web Animation API (WAAPI).

spring-easing NPM | Github | Docs | Licence Quick and easy spring animations. Works with other animation libraries (gsap, animejs, @okikio/animate, mo

Okiki Ojo 34 Dec 14, 2022
Convert your SVG file directly to Flutter paths and prevent all the messing with bezier curves.

svg-to-flutter-path-converter Convert your SVG file directly to Flutter paths and prevent all the messing with bezier curves. Flutter Clutter The tool

null 30 Jan 2, 2023
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
open source license generator. evet tarafından.

TARAFINDAN evet tarafından yet another open source license generator. Installation Install with npm or yarn. npm i -g tarafindan yarn global add taraf

null 29 Jun 22, 2022
Components and tools for building DeFi dapps on Solana + Anchor. Public domain license.

Solana DeFi Framework Components and tools for building DeFi dapps on Solana + Anchor. Public domain license. Status Pre-pre-pre-alpha. Contributing A

null 4 Mar 28, 2022
Bot that randomly posts 23,463 personalized license plate applications the California DMV received from 2015-2016 to Twitter every so often.

ca-dmv Bot that randomly posts 23,463 personalized license plate applications the California DMV received from 2015-2016 to Twitter every so often. Wa

rj 212 Dec 31, 2022
A JavaScript project for the Leaderboard list app, using webpack and ES6 features, this is a requirement for Micronauts in Module 2 block 4. This project is MIT Licensed

LeaderBoard A JavaScript project for the Leaderboard list app, using webpack and ES6 features, this is a requirement for Micronauts in Module 2 block

Makoji David 9 Sep 9, 2022
A JavaScript animation plugin for menus. It creates a div that moves when you mouse over an element, giving it an elastic animation.

Lava-Lamp Description: A JavaScript animation plugin for menus. It creates a div that moves when you mouse over an element, giving it an elastic anima

Richard Hung 38 Jun 4, 2022