Algorithms for Animation
Simple formulas to activate play inform with brand UI
"You can take a problem that can't be solved directly by animation and can't be solved by technology and work together to acheive a much better resolution."
- Joe Longson, Senior Software Engineer - Zootopia
CLI   GUI   NUI

Affordance & percieved affordance

Animations are cognitive aids

Subtle Cues

Progressive Disclosure

CoDrops
https://dribbble.com/ColinGarven
Colin Garven
https://dribbble.com/ColinGarven

Auto Loading

Navigation

Adrian Zumbrunnen
http://www.smashingmagazine.com/2013/10/23/smart-transitions-in-user-experience-design/
Adrian Zumbrunnen
http://www.smashingmagazine.com/2013/10/23/smart-transitions-in-user-experience-design/

Context

Jason Zigrino
https://dribbble.com/shots/2749851-Gboard-Dark-Material-Motion

Interactive

Sergey Valiukh
https://dribbble.com/SergeyValiukh

How do you communicate animation ideas?

Math

Motion

var ball = document.getElementById('ball');
var start = 0;
var basicAnimation = function (e) {
	start += 12;	     
	basic.style.left = start + "px"; 
  if (Math.abs(start) <= 800) {
    requestAnimationFrame(basicAnimation);
  }	
}

The basics of animation: interpolation

valueAtTime = (end - start) * time / duration + start

The basics of animation: interpolation

valueAtTime = (end - start) * time / duration + start

Timing

  (end - start) * time/duration + start
  div.style.left = 900-0 * time/1000 + 0+"px"

"Using a term like nonlinear science is like referring to the bulk of zoology as the study of non-elephant animals."

- Stanislaw Ulam

Natural movement

Velocity, Acceleration, Friction, Torque

Easing functions

Easing

(end - start) * easingfunction([0-1]) + start

Change in property times (some float) plus beginning value.

Power Functions - EaseIn

endX * Math.pow(percentChange, 3) + "px";

Power Functions - EaseOut

(endX - startX)*(1 - Math.pow(1 - (t / d), 3)) +startX+"px";

Trig! ... sine :)

(endX - startX)*Math.sin( t/d * Math.PI / 2 ) +startX+"px";

Follow Through

> 1

Elasticity

(endX - startX)*k * k * ( ( s + 1 ) * k - s ) +startX+"px";

Bounce

if ( k < ( 1 / 2.75 ) ) { 
return 7.5625 * k * k;
} else if ( k < ( 2 / 2.75 ) ) { 
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
} else if ( k < ( 2.5 / 2.75 ) ) {	
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
} else { 
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; } }
				

Physics Engines

Linear Interpolation Function (start, stop, amount)

function lerp(a,b,x) { return a+x*(b-a); }
				

Radial motion

anim.theta += .02*Math.pow(1-anim.r/cw,8) * Math.PI;
anim.p.x = anim.r * Math.cos(anim.theta);
anim.p.y = anim.r * Math.sin(anim.theta);
				

Depth (varying velocity)

// different shaped circles (depth)
function shape() { return randomCircle(.006, .09) }

// initializes each circle w/ random velocity (px/second)
x:lerp(xmin,xmax,Math.random()),
y:lerp(ymin,ymax,Math.random())}

// basic equation: incremental x and/or y by velocity to get acceleration
anim.p.x += anim.v.x
anim.p.y += anim.v.y

// this just keeps everything w/in the bounds of the canvas
anim.p.x = (anim.p.x + cw/2) % cw - cw/2
anim.p.y = (anim.p.y + ch/2) % ch - ch/2
				

Constraints (gravity)

// simple constraint of gradually increasing gravity
gravity = lerp(0,2,fraction);

// add an amount of gravity to the y velocity
anim.v.y += gravity

// same as before, add the velocity to the position
anim.p.x += anim.v.x
anim.p.y += anim.v.y

// flip velocity for bounce
anim.v.y = -.9*Math.abs(anim.v.y)

// adds a bit of drag to slow down horizonal movement
anim.v.x *= .99;

				

Separation, Alignment, & Cohesion


// set boids direction towards center
var centroidDirection = vsub(anim1.p, centroid)
var centroidDistance = vlength(centroidDirection)

// apply interaction force against boids
var centroidForce = -attraction / (centroidDistance || .001)
anim1.force.x += centroidForce * centroidDirection.x
anim2.force.x += centroidForce * centroidDirection.x

var rejectForce = rejection / (distance ? distance * distance : 0)
anim1.force.x += rejectForce * direction.x
anim2.force.x += rejectForce * direction.y

// match velocity to nearby boids
anim1.force.x += velocitySync * anim2.v.x
anim2.force.x += velocitySync * anim1.v.x

					

Collisions (engines!)


// create a world with a ground and some objects
var bodyDef = new Box2D.Dynamics.b2BodyDef();
var fixtureDef = new Box2D.Dynamics.b2FixtureDef();

// set the details for our constraints
fixtureDef.density = 1.0;
fixtureDef.friction = 0.5;

// step through within constraints of our setup
world.Step( 1 / 60 /* frame-rate */,
		10 /* velocity iterations*/,
		1 /* position iterations */);

				

Static & Dynamic

// set body parts oriented in the right direction
torso: partTransitions(0, -.04, .02, .04, -Math.PI/2),
left_arm: partTransitions(-.018, -.03, .01, .03, -3*Math.PI/4),

// sets how parts are attached to each other
fixtureDef.filter.groupIndex = -1

// set up static & dynamic types
addPhysics(anims.head[0], Box2D.Dynamics.b2Body.b2_staticBody, bodyDef, fixtureDef)
groups.slice(1).forEach(function(group) {
addPhysics(anims[group][0], Box2D.Dynamics.b2Body.b2_dynamicBody, bodyDef, fixtureDef)
})

					

Performance

HTML, CSS, & JS Based

  • Use Keyframes, Transitions & Transforms with CSS
  • Use requestAnimationFrame with JS
  • Web Animation API (WAAPI)

RAIL

  • Response 100ms
  • Animation 6ms
  • Idle 50ms
  • Load 1000ms
credit Paul Irish & Paul Lewis and Blink Team (bit.ly/blink-midnight-train)

Rendering

  • Clear & Reuse
  • Procedural Sprites
  • Keep States
  • Compositing

The future is... meow

Go play!

References & Credits

Courtney Hemphill
@chemphill
courtney@carbonfive.com