Skip to content

Easing

Easing Graphs

For convenience, I've included a bunch of easing functions because they are very useful in generative art. Easing functions are mathematical functions that map numbers in the range [0, 1] to numbers in the range [0, 1], such that ease(0) always returns 0 and ease(1) always returns 1. Different easing functions do different things in the middle, but there are three main flavors:

  • An ease-in starts slow and speeds up towards the end.
  • An ease-out starts fast and slows down towards the end.
  • An ease-in-out starts slow, gets fast in the middle, and then slows down again at the end.

If you want to understand easing functions in more detail, check out this cheat sheet.

elkplot.easing.ease_in_sine
elkplot.easing.ease_out_sine
elkplot.easing.ease_in_out_sine
elkplot.easing.ease_in_nth_order
elkplot.easing.ease_out_nth_order
elkplot.easing.ease_in_out_nth_order
elkplot.easing.ease_in_expo
elkplot.easing.ease_out_expo
elkplot.easing.ease_in_out_expo
elkplot.easing.ease_in_circ
elkplot.easing.ease_out_circ
elkplot.easing.ease_in_out_circ
elkplot.easing.ease_in_back
elkplot.easing.ease_out_back
elkplot.easing.ease_in_out_back
elkplot.easing.ease_in_elastic
elkplot.easing.ease_out_elastic
elkplot.easing.ease_in_out_elastic
elkplot.easing.ease_in_bounce
elkplot.easing.ease_out_bounce
elkplot.easing.ease_in_out_bounce

Usage

All the easing functions accept one argument representing the x-value in [0, 1], and all of them will return the y-value in [0, 1]. All of them accept any ArrayLike argument. If you want to check the value of the easing function at many different x-coordinates, you can pass in a list of floats or a 1D numpy array.

import numpy as np

import elkplot.easing

eased = elkplot.easing.ease_in_bounce(0.4)
print(eased)  # 0.2275

x = np.linspace(0, 1, 5)
eased = elkplot.easing.ease_in_back(x)
print(eased)  # [ 0.        -0.0640625 -0.0875     0.1828125  1.       ]

The following easing functions have optional extra arguments:

ease_in_back(x, c=1.7)

Pull slightly negative at the start before blasting off towards (1, 1) Args: x: The x-coordinate in [0, 1] c: The degree to which it pulls back into the negative before racing to 1. (If this is 0, it just becomes cubic easing.)

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_in_back(x: npt.ArrayLike, c: float = 1.7) -> npt.ArrayLike:
    """
    Pull slightly negative at the start before blasting off towards (1, 1)
    Args:
        x: The x-coordinate in [0, 1]
        c: The degree to which it pulls back into the negative before racing to 1.
            (If this is 0, it just becomes cubic easing.)

    Returns:
        The y-coordinate in [0, 1]
    """
    return (1 + c) * np.power(x, 3) - c * np.power(x, 2)

ease_in_elastic(x, c=2 * np.pi / 3)

Wiggles back and forth before going off to (1, 1) Args: x: The x-coordinate in [0, 1] c: The "bounciness" factor.

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_in_elastic(x: npt.ArrayLike, c: float = 2 * np.pi / 3) -> npt.ArrayLike:
    """
    Wiggles back and forth before going off to (1, 1)
    Args:
        x: The x-coordinate in [0, 1]
        c: The "bounciness" factor.

    Returns:
        The y-coordinate in [0, 1]
    """
    return np.select(
        [x == 0, x == 1],
        [0, 1],
        -np.power(2, 10 * x - 10) * np.sin((x * 10 - 10.75) * c),
    )

ease_in_nth_order(x, n=2)

Nth order ease in. Args: x: The x-coordinate in [0, 1] n: The order of the polynomial. (n=2 is quadratic ease in, n=3 is cubic, etc.)

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_in_nth_order(x: npt.ArrayLike, n: int = 2) -> npt.ArrayLike:
    """
    Nth order ease in.
    Args:
        x: The x-coordinate in [0, 1]
        n: The order of the polynomial. (n=2 is quadratic ease in, n=3 is cubic, etc.)

    Returns:
        The y-coordinate in [0, 1]
    """
    return np.power(x, n)

ease_in_out_back(x, c=1.7)

Pull slightly negative at the start and overshoots slightly over at the end before pulling back to (1, 1) Args: x: The x-coordinate in [0, 1] c: The degree to which it overshoots/pulls back (If this is 0, it just becomes cubic easing.)

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_in_out_back(x: npt.ArrayLike, c: float = 1.7) -> npt.ArrayLike:
    """
    Pull slightly negative at the start and overshoots slightly over at the end before pulling back to (1, 1)
    Args:
        x: The x-coordinate in [0, 1]
        c: The degree to which it overshoots/pulls back
            (If this is 0, it just becomes cubic easing.)

    Returns:
        The y-coordinate in [0, 1]
    """
    c2 = c * 1.525
    return np.where(
        x < 0.5,
        (np.power(2 * x, 2) * ((c2 + 1) * 2 * x - c2)) / 2,
        (np.power(2 * x - 2, 2) * ((c2 + 1) * (x * 2 - 2) + c2) + 2) / 2,
    )

ease_in_out_elastic(x, c=2 * np.pi / 4.5)

Wiggles about y=0 at the start with the wiggles increasing in magnitude, then races up to y=1 and damps down to a constant at (1, 1) Args: x: The x-coordinate in [0, 1] c: The "bounciness" factor.

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_in_out_elastic(x: npt.ArrayLike, c: float = 2 * np.pi / 4.5) -> npt.ArrayLike:
    """
    Wiggles about y=0 at the start with the wiggles increasing in magnitude, then races up to y=1 and damps down to a
    constant at (1, 1)
    Args:
        x: The x-coordinate in [0, 1]
        c: The "bounciness" factor.

    Returns:
        The y-coordinate in [0, 1]
    """
    return np.select(
        [x == 0, x == 1, x < 0.5],
        [0, 1, -(np.power(2, 20 * x - 10) * np.sin((20 * x - 11.125) * c)) / 2],
        (np.power(2, -20 * x + 10) * np.sin((20 * x - 11.125) * c)) / 2 + 1,
    )

ease_in_out_nth_order(x, n=2)

Nth order ease in and out. Args: x: The x-coordinate in [0, 1] n: The order of the polynomial. (n=2 is quadratic ease in and out, n=3 is cubic, etc.)

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_in_out_nth_order(x: npt.ArrayLike, n: int = 2) -> npt.ArrayLike:
    """
    Nth order ease in and out.
    Args:
        x: The x-coordinate in [0, 1]
        n: The order of the polynomial. (n=2 is quadratic ease in and out, n=3 is cubic, etc.)

    Returns:
        The y-coordinate in [0, 1]
    """
    return np.where(
        x < 0.5, np.power(2, n - 1) * np.power(x, n), 1 - np.power(-2 * x + 2, n) / 2
    )

ease_out_back(x, c=1.7)

Overshoots slightly over 1 before pulling back to (1, 1) Args: x: The x-coordinate in [0, 1] c: The degree to which it overshoots 1 before pulling back. (If this is 0, it just becomes cubic easing.)

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_out_back(x: npt.ArrayLike, c: float = 1.7) -> npt.ArrayLike:
    """
    Overshoots slightly over 1 before pulling back to (1, 1)
    Args:
        x: The x-coordinate in [0, 1]
        c: The degree to which it overshoots 1 before pulling back.
            (If this is 0, it just becomes cubic easing.)

    Returns:
        The y-coordinate in [0, 1]
    """
    return 1 + (1 + c) * np.power(x - 1, 3) + c * np.power(x - 1, 2)

ease_out_elastic(x, c=2 * np.pi / 3)

Like a snapping elastic band, gets to the top very quickly and then wiggles about y=1 until the wiggles damp down to a constant at (1, 1) Args: x: The x-coordinate in [0, 1] c: The "bounciness" factor.

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_out_elastic(x: npt.ArrayLike, c: float = 2 * np.pi / 3) -> npt.ArrayLike:
    """
    Like a snapping elastic band, gets to the top very quickly and then wiggles about y=1 until the wiggles damp down
    to a constant at (1, 1)
    Args:
        x: The x-coordinate in [0, 1]
        c: The "bounciness" factor.

    Returns:
        The y-coordinate in [0, 1]
    """
    return np.select(
        [x == 0, x == 1], [0, 1], np.power(2, -10 * x) * np.sin((x * 10 - 0.75) * c) + 1
    )

ease_out_nth_order(x, n=2)

Nth order ease out. Args: x: The x-coordinate in [0, 1] n: The order of the polynomial. (n=2 is quadratic ease out, n=3 is cubic, etc.)

Returns:

Type Description
ArrayLike

The y-coordinate in [0, 1]

Source code in elkplot/easing.py
def ease_out_nth_order(x: npt.ArrayLike, n: int = 2) -> npt.ArrayLike:
    """
    Nth order ease out.
    Args:
        x: The x-coordinate in [0, 1]
        n: The order of the polynomial. (n=2 is quadratic ease out, n=3 is cubic, etc.)

    Returns:
        The y-coordinate in [0, 1]
    """
    return 1 - np.power(1 - x, n)