Web Animations

LCA Multimedia Miniconf

Animations on the web today

  • CSS Animations
  • SVG Animations
  • JavaScript Animations (requestAnimationFrame, Canvas, WebGL, etc.)
  • Flash (becoming obsolete)

CSS Animations

Transitions and Keyframe animations

.red.square { transition: transform 2s ease-in-out; }
.red.square:hover { transform: rotate(360deg); }
.yellow.square:hover { animation: spin 2s ease-in-out; }
@keyframes spin {
  100% { transform: rotate(360deg); }
}

CSS Animations

Transitions and Keyframe animations

  • Simple & effective
  • Declarative
  • Not tied to the main thread
  • Simple play/pause controls for keyframe animations
  • No dynamic modification or definition of animation content
  • No primitives for synchronising different animations playing together
  • Cannot stack multiple animations on top of each other

SVG Animations

SMIL

<animatetransform
  attributeName="transform"
  attributeType="xml"
  type="rotate"
  from="0deg"
  to="360deg"
  dur="2s"
  repeatCount="indefinite"
></animatetransform>

SVG Animations

SMIL

  • Declarative
  • Has playback controls
  • Can synchronise animations together
  • Entire SVG is treated as a single animation
  • Cannot dynamically modify animation content
  • Sees very little use on the web
  • Does not integrate with HTML content
  • Implementations are lacking compared with CSS Animations
    • Missing cross browser support
    • Fewer performance optimisations

JavaScript

function frame(time) {
  document.querySelector('.blue.square').style.transform =
      'rotate(' + (Math.sin(time / 1000) * 360) + 'deg)';
  requestAnimationFrame(frame);
}
requestAnimationFrame(frame);

JavaScript

  • Total control over the animation
  • Access to powerful graphical tools (Canvas & WebGL)
  • Portable (even beyond the web)
  • Must run on the main thread
  • Procedural, not declarative

Problems

  • Different APIs have different models for animation
  • Unnecessary maintenance to support multiple ways of doing the same thing
  • A hassle for web developers to learn multiple techniques
  • No way to synchronise different animation techniques together
  • Not easy for JavaScript to set up declarative animations

Web Animations

A new general purpose animation model

Contributors

  • Mozilla
  • Google
  • Adobe
  • W3C: CSS-SVG Effects Task Force (FXTF)

Motivations

  • Provides a common model for CSS and SVG animations
  • Allows different animation technologies to coordinate together
  • Allows for future animation specs to integrate with the same model
    (media integration, Layout Animations)
  • Provides a JavaScript API for defining animations declaratively
  • Animations are not tied to the main thread
  • Makes HTML animations a more compelling alternative to Flash

JavaScript API

A simple example

element.animate({transform: 'rotate(360deg)'}, 2);

JavaScript API

More complex timing

element.animate(
    {transform: 'rotate(360deg)'},
    {
      direction: 'alternate',
      duration: 1,
      iterations: 4
    });

JavaScript API

More complex timing

element.animate(
    {transform: 'rotate(360deg)'},
    {
      direction: 'alternate',
      duration: 1,
      iterations: Infinity,
      easing: 'ease-in-out',
      playbackRate: 2
    });

JavaScript API

Without the syntactic sugar

document.timeline.play(
  new Animation(
    element,
    new KeyframeAnimationEffect([{transform: 'rotate(360deg)'}]),
    {duration: 2}));

JavaScript API

Parallel animation grouping

document.timeline.play(new ParGroup([
  new Animation(parItem1, [{width: '0px'}, {width: '600px'}], 1),
  new Animation(parItem2, [{width: '0px'}, {width: '800px'}], 1),
  new Animation(parItem3, [{width: '0px'}, {width: '200px'}], 1),
]));

JavaScript API

Sequential animation grouping

document.timeline.play(new SeqGroup([
  new Animation(seqItem1, [{width: '0px'}, {width: '300px'}], 1),
  new Animation(seqItem2, [{width: '0px'}, {width: '400px'}], 1),
  new Animation(seqItem3, [{width: '0px'}, {width: '100px'}], 1),
]));

JavaScript API

Nested grouped animations

JavaScript API

Nested grouped animations

document.timeline.play(new SeqGroup([
  new Animation(outerSeqItemFirst, [{width: '0px'}, {width: '300px'}], 1),
  new ParGroup([
    new Animation(innerParItem1, [{width: '0px'}, {width: '300px'}], 1),
    new Animation(innerParItem2, [{width: '0px'}, {width: '380px'}], 1),
    new Animation(innerParItem3, [{width: '0px'}, {width: '100px'}], 1),
  ]),
  new Animation(outerSeqItemLast, [{width: '0px'}, {width: '100px'}], 1)
]));

JavaScript API

Path animations

JavaScript API

Path animations

var svgPathData = 'M 100 200' +
                  'C 200 100 300   0 400 100' +
                  'C 500 200 600 300 700 200' +
                  'C 800 100 900 100 900 100';
var pathAnimation = new Animation(
    chromeLogo,
    new PathAnimationEffect(svgPathData, 'auto-rotate'),
    {
      duration: 1,
      direction: 'alternate',
      easing: 'ease-in-out',
      iterations: Infinity,
    });
document.timeline.play(pathAnimation);

JavaScript API

Playback control

var player = document.timeline.play(pathAnimation);
player.paused = true;
seekSlide.onmousemove = function(event) {
  player.currentTime = (event.clientX - seekSlide.offsetLeft) / seekSlide.clientWidth;
};

JavaScript API

Custom animation effects

function customAnimationEffect(timeFraction, iteration, target) {
  output.textContent = 'timeFraction: ' + timeFraction.toFixed(2);
                       'iteration: ' + iteration + '\n' +
}
document.timeline.play(
  new Animation(
    null,
    customAnimationEffect,
    { duration: 2,            direction: 'alternate',
      easing: 'ease-in-out',  iterations: Infinity }));

      
    

Timing Model

Timing Model

Timing inputs

dictionary TimingInput {
    double                             delay = 0;
    double                             endDelay = 0;
    FillMode                           fill = "auto";
    double                             iterationStart = 0.0;
    unrestricted double                iterations = 1.0;
    (unrestricted double or DOMString) duration = "auto";
    double                             playbackRate = 1.0;
    PlaybackDirection                  direction = "normal";
    DOMString                          easing = "linear";
    EasingTimesInput                   easingTimes = "distribute";
};

Timing Model

Timing calculations

Implementation Status

  • Specification at First Public Working Draft: www.w3.org/TR/web-animations
  • Chrome:
    • CSS Transitions & Animations rewritten on top of the Web Animations model
    • JavaScript API in development behind a flag
  • Firefox & Safari: Started implementation
  • IE: No public signals

Polyfill

Demos

Questions?

Thank You!