Easing equations with 'Influence' and 'In-/Outgoing Velocity' like in Adobe After Effects


I want to synchronise the easing of something I coded to something I made in After Effects as exactly as possible.

In After Effects, when animating something you can more precisely control the motion of that animation with the Graph Editor. This either shows the animated property’s value change over time (e.g. 0 – 100%), or the speed of the transformation over time.

The graph points in this editor contain bezier handles when clicked.
The bezier handles give you control over the easing of the keyframed transformation: Clicking and dragging them determine the curve on the grid, altering the easing function and thus the motion of the animated layer.


The way the curve is displaced by these bezier handles is called Influence by After Effects.
You can also right click one of either keyframes and input values by typing them in.

My animation in After Effects now goes from a full stop (Outgoing velocity: 0p/s | Influence of 75% of keyframe 1), to reaching a peak in speed, to end at a full stop again (Incoming velocity: 0p/s | Influence of 75% of keyframe 2).

I’ve looked around for easing equations, and this type of animation is very similar to a standard Quadratic Ease_In_Out function.

public class EasingInOutQuart implements Easing {
  public float get(float t) {
    t *= 2;

    if (t < 1) {
      return 0.5 * t * t * t * t;

    t -= 2;
    return -0.5 * (t * t * t * t - 2);

It unfortunately doesn’t coincide exactly to my specific easing in After Effects, because I can’t ‘influence’ the curve of my values the same way I can in After Effects using the bezier handles, which is what I’m hoping to achieve.

My question is: How would it be possible for me to write a function similar to this one, where I have more control over te exact progress of my values? On easings.net I saw that the CSS code for a Quartic Ease InOut function contains what looks like an ease in/out influence, which is more or less what I’m looking for. The 0.76 and 0.24:

.block {
	transition: transform 0.6s cubic-bezier(0.76, 0, 0.24, 1);

There’s a topic made in the Adobe Support Community with the same question, unfortunately the topic never got answered satisfactory. I’m linking it here since this guy maybe explains it better than I am right now…

I hope everything is clear. I hope that someone can help me out with this. Thanks in advance!

1 Like

not sure what you mean

  • this reads easing from an ArrayList of draggable points (the y of the points is mapped to easing)
  • points are made with a sin() formula

I would be far more happy with it if when we could get ALL the points from curveVertex(pv.x, pv.y).

  • But I don’t know how.
  • See what I mean when you press and hold any key and watch the CAR going not on the black line (which would be cool) but from point to point

// see https://discourse.processing.org/t/dont-understand-what-this-code-means-easing/38588/3
// see https://discourse.processing.org/t/bezier-curve-move-weight-points/8872/3

// graph: 
// holding the curveVertex points in 2D - the core data. Here you add and edit your points. 
ArrayList<PointGraph> listPointsGraph = new ArrayList();

int step=1; 

boolean goodtogo=true;

boolean firstTimeKeyPressed=true;


// move a sphere along the curve (Rollercoaster) optional 
boolean showRollercoasterFlag = false; 
int showRollercoaster_i; // current number of sphere on track for the Rollercoaster CAR 
int i2=0; // counter for the taken steps between 2 single points of track for rollercoaster  


// for drag 
boolean hold=false; 
int hold_i = 0; 


float easing = 0.05;

float targetX, targetY; 
float followingX, followingY; 

// ---------------------------------------------------------------------
// CORE functions 

void setup() {
  size(1850, 880);

  makeArrayList();  // the graph
}// func 

void draw() {

// called by draw() 

void drawForNormal() {

  fill(0); // black 
  text("A black curve (curveVertex() command) composed of red points of an ArrayList, mouse drag to move points. Red points control the easing. \nA small car is giong on the graph like on a Rollercoaster, \n"
    +"but unfortunately it doesn't follow the black line (how to get data from curveVertex() command?) but goes directly between the red points."
    +"\nTry the sketch also with holding a key down and mouse drag (this is without the target/follower and in makeArrayList() a step of 90 for the for loop)", 
    17, 17, 
    width-100, 900); 

  // show ArrayList

  // drag? 
  if (hold) {    

  if (true) {

  if (keyPressed)
  if (goodtogo) {
}// func 

void showTargetAndFollower() {
  // needs to have ALL points without any gaps (in makeArrayList())

  PointGraph pm = listPointsGraph.get(frameCount*10%width);
  float value = pm.getY();

  // we calculate the easing based on the graph: 
  //    * the lower the graph (nearer to height) the slower (0.0001)
  //    * the higher the graph (nearer to 150) the faster (0.9)
  easing = map(value, height, 150, 0.001, 0.59 ); 

  // manage x 
  targetX = frameCount*10%width;  // get the mouseX as target x coord
  float dx = targetX - followingX;  // calc delta between the current x and target x
  followingX += dx * easing; // move the current x a bit closer to the target x by adding delta BUT NOT the full delta but a value that is a smaller fraction 

  // Do the same with Y
  targetY = 100; // get the mouseY as target y coord
  // float dy = targetY - y;  // delta between the current y and target y
  // y += dy * easing; // move the current y a bit closer to the target y
  followingY = targetY;  

  stroke(255, 0, 0); 
  line(targetX-17, targetY, 
    targetX+17, targetY);

  rect(followingX, followingY, 
    12, 12);

// -------------------------------------------------------------------------

void keyPressed() {
  if (firstTimeKeyPressed) {
    makeArrayList();  // the graph

void keyReleased() {
  if (!keyPressed) {
    makeArrayList();  // the graph

void mouseReleased() {
  // end drag 
  hold = false;

// -------------------------------------------------------------------------

void makeArrayList() {
  // make Graph, called from setup()
  //float radiusX=300; 
  float radiusY=110;

  // float centerX=width/2;
  float centerY=height-130; 

  // start and end of graph and density 
  for (int angleStar = 0; angleStar <= width+100; angleStar += step) {

    float starX =angleStar; // centerX + (cos (radians(angleStar)) * radiusX);
    float starY = centerY + (sin (radians(angleStar)) * radiusY);

    // the part gets elevated 
    if (starX>220 &&
      starX<777) {
      // starY+=map(starX-220, 0, 310, -10, -42);

    PVector newPVector = new PVector(starX, starY);
    listPointsGraph.add (  new PointGraph ( newPVector, false) );   // 2D

  // futher 
  //  listPointMy.get(65).pv.y -= 155;

void showArrayList() {
  // show graph

  // show the curve with beginShape and endShape
  int i=0;
  if (listPointsGraph.size()>0) {
    for ( i = 0; i < listPointsGraph.size(); i++) {

  //show the points (additionally) green OR Red 
  float rad=3;
  boolean firstTimeShowingGreen=true; 
  for ( i = 0; i < listPointsGraph.size(); i++) {
    PointGraph pm = listPointsGraph.get(i);
    PVector pv=pm.pv;
    // if we are close to the mouse, color green, else red
    if (dist(mouseX, mouseY, pv.x, pv.y)<11 && firstTimeShowingGreen) {
      // near mouse 
      fill( 0, 255, 0); // green
      if (mousePressed&&!hold) {
        hold_i= i;
    } else {
      // normal 
      fill(255, 0, 0);  // red

// ------------------------------------------------------------------------

void rollerCoaster() {
  // interprete the graph as a rollercoaster track with a CAR on it


  if (showRollercoaster_i > listPointsGraph.size()) {

  // get two points between which the CAR currently is running  
  PointGraph pm1=listPointsGraph.get( showRollercoaster_i );
  PointGraph pm2=listPointsGraph.get( showRollercoaster_i+1 ); 

  // get dist between 2 points 
  float dist1 = pm1.pv.dist(pm2.pv);
  // calculate the steps between the 2 points depending on dist1 between them (smooth running) 
  float steps; // = 9;
  steps = (dist1 / 2.0);

  // calc t (can be seen as amt in lerp() / curvePoint) 
  float t = i2 / (float) steps;

  // similar to lerp() wth amt:  
  float x = curvePoint(pm1.pv.x, pm1.pv.x, pm2.pv.x, pm2.pv.x, t);
  float y = curvePoint(pm1.pv.y, pm1.pv.y, pm2.pv.y, pm2.pv.y, t);

  // different camera view for rollercoaster view
  // setRollerCoasterCamera(x, y, z, t); 

  // show ball&box [the rollercoaster car] 
  if (true) { 
    fill(255, 2, 244);
    translate(x, y);
    rect(0, 0, 9, 9);
    translate(4, -3);
    ellipse(0, 0, 7, 7); 

  if (i2>steps) {
    if (showRollercoaster_i>listPointsGraph.size()-2) { // little rough management at the end of arraylist... ??? 

// ==================================================================

class PointGraph {

  // one point one the track 

  PVector pv;  // position 
  boolean selected=false; // selected y/n for mouse drag 

  // constructor 
  PointGraph( PVector pv_, boolean selected_ ) {
    pv        = pv_.copy();
    selected = selected_;
  } // constructor

  // -------------------------------------------------

  void showAsRect( float rad ) {
    translate(pv.x, pv.y);
    rect(0, 0, rad, rad); 
  } // method

  float getY() {
    // used for easing

  void useAsCurveVertexPVector() {
    // use curveVertex with PVector as input  
    curveVertex(pv.x, pv.y);
  } // method 

Hi Chrisir,

I’m not sure what this sketch has to do with my question about easing, or why you’re posting this underneath my post. Did you mean to post it somewhere else?

My Sketch gives you easing based on a mathematical graph that you can modify with the mouse

Never mind