+ - 0:00:00
Notes for current slide
Notes for next slide

Co-building and maintaining
animations over time

Thibault Mahé - may 2017 - v1

1 / 56

Bringing UI to life

Why animating an interface can enhance the UX?


  • Convey meaning: "Motion is meaningful" (Material Design)
  • Focus attention
  • Maintain continuity
  • Reduce cognitive load
  • Describe components relationships
  • Explain the intent of a functionality
  • Is part of the Identity: character, beauty and delight
2 / 56

Designing over time

Animating is...

  • ...bringing an element from a state to another
  • ...bringing the concept of time to a UI



An animation is
a set of values
over time

3 / 56

Designing over time


Loader

4 / 56

Designing over time


Parallax

5 / 56

EX: how CSS manages values over time

  • Set of values: transform property values
  • Time: animation-duration, animation-delay, animation-iteration-count, ...
  • Repartition over time: [0%, ..., 50%, ..., 100%]
  • Easing: animation-timing-function
6 / 56

EX: how SMIL manages values over time

  • Set of values: values, from, to, ...
  • Time: dur, repeatCount, begin, end, ...
  • Repartition over time: keytimes, ...
  • Easing: calcMode, keySplines, ...
7 / 56

Different methods of animation

  • CSS
  • SVG (SMIL)
  • JavaScript
    • Vanilla
    • Web Animation API (new)
    • jQuery
    • canvas, Webgl
    • Libraries: D3, Greensock, ...
    • ...
8 / 56
  • Toutes permettent de manipuler des données (des positions, des facteurs de couleurs, etc.) sur du temps

Different methods of animation

  • CSS is great for managing styles...
    • made for it
    • performance (CSSOM)
    • native animation (keyframes)
  • ... but JavaScript allows more configuration
    • events
    • variables
    • dynamic values
    • loop, condition, ...
9 / 56
  • M'appesantir sur une (pas si) nouvelle techno

Observables

10 / 56

The (not so) new hype tech


angular 2

Angular 2

cycle JS

Cycle JS

11 / 56
  • Pourquoi ca peut nous intéresser

The (not so) new hype tech

 material motion

Material Motion

12 / 56
  • Pourquoi ca peut nous intéresser
  • Material motion a (notamment) 3 ambitions:
    • construire un langage de concept autour des animations
    • que ces concepts correspondent à des "composants" concrets et réutilisables
    • que ca permettent de faire le pont entre designers et ingénieurs
  • On reviendra plus tard sur ces ambitions

Overview

  • What is an Observable
  • How to use it
  • Concrete sample
  • Advantages
  • Concept of "Reactive animation"
13 / 56

What is an Observable?

  • Value:
14 / 56
  • Value = valeur seule, comme un nombre, un boolean, un objet, ...

What is an Observable?

  • Value:
  • Array:

[ ]

15 / 56
  • Value = valeur seule, comme un nombre, un boolean, un objet, ...
  • Array ou iterable = tableau fini de valeur

What is an Observable?

  • Value:
  • Array:

[ ]

  • Promise:

...

16 / 56
  • Value = valeur seule, comme un nombre, un boolean, un objet, ...
  • Array ou iterable = tableau fini de valeur
  • Intervention du temps !
  • Promise = une valeur qui va arriver après un certain temps

What is an Observable?

  • Value:
  • Array:

[ ]

  • Promise:

...

  • Observable:

-- -->

17 / 56
  • Value = valeur seule, comme un nombre, un boolean, un objet, ...
  • Array ou iterable = tableau fini de valeur
  • Intervention du temps !
  • Promise = une valeur qui va arriver après un certain temps
  • Observable (ou stream) = un nombre fini ou indéfini de valeurs qui arrivent dans le temps
  • Un observable est donc assez similaire à un Array: une collection de valeurs, qui peut être manipuler par des fonctions comme map, filter, reduce, ...
  • MAIS un Observable intègre la notion de temps: il y a un temps et une fin, et les valeurs arrivent à différents moments

What is an Observable?

  • Value:
  • Array:

[ ]

  • Promise:

...

  • Observable:

-- -->


An Observable is a set of values over time

18 / 56
  • Value = valeur seule, comme un nombre, un boolean, un objet, ...
  • Array ou iterable = tableau fini de valeur
  • Intervention du temps !
  • Promise = une valeur qui va arriver après un certain temps
  • Observable (ou stream) = un nombre fini ou indéfini de valeurs qui arrivent dans le temps
  • Un observable est donc assez similaire à un Array: une collection de valeurs, qui peut être manipuler par des fonctions comme map, filter, reduce, ...
  • MAIS un Observable intègre la notion de temps: il y a un temps et une fin, et les valeurs arrivent à différents moments
  • Exactement la même définition que les animations
  • Ce qui signifie que l'on pourrait traduire des animations en observables

What is an Observable?

Observables are:

  • Asynchronous: data comes at any time
  • Immutable: transforming an observable doesn't modify it but creates instead a new one
  • Subscribable: an observable don't store data, an Observable is a bridge, connecting an event source to a listener (Observer) so we can know when things change.
19 / 56

What is an Observable?

An observable is an "interface" that can:

  • Catch some data
  • Transform these data
  • Let these data be read
20 / 56

What is an Observable?


  • Catch some data

1- Create an Observable

  • Transform these data

2- Manipulate a stream: the operators

  • Let these data be read

3- Listen to a stream: the subscription

21 / 56
  • 3 concepts à voir

1. Create an Observable

Streams can be created from anything:

  • Variables,
  • DOM Events,
  • Mouse / Keyboard interactions,
  • Animations,
  • Caches,
  • Data structures,
  • Anything.


We can listen to those streams and react accordingly

22 / 56
  • je précise bien "anything" car ca aura son importance plus tard

1. Create an Observable


var myvariable = 'foo';
// The observable emits that value, then completes.
var variableStream$ = Rx.Observable.of(myvariable);
// The observable emits each item from the array, then completes.
var arrayStream$ = Rx.Observable.from([1, 2, 3, 4, 5]);
// The observable emits the promise result eventually, then completes (or errors).
var promiseStream$ = Rx.Observable.fromPromise(fetch('http://example.com/users'));
// The observable continuously emits events from the event listener.
var mouseMove$ = Rx.Observable.fromEvent(window, 'mousemove');


Using Rx.js, a JavaScript implementation of ReactiveX

23 / 56

RX Marbles

rx marbles

https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

--a---b---c---d---X---|->

Visualizing Observables

Shematisation

24 / 56
  • Visualiser les streams avec des billes
  • On voit par ailleurs ici la dimension asynchrone de l'Observable ainsi que sa dimension immuable

2. Manipulate a stream: the operators

map

filter

  • Transforming: delay, map, scan (reduce), debounce, ...
  • Combining: concat, merge, withLatestFrom, zip, ...
  • Filtering: filter, first, last, takeWhile, average, ...
  • Mathematical operators: count, max, min, sum, ...
  • and many many more...
25 / 56
  • Un Observable seul ne sert pas à grand chose. Des opérateurs vont permettre de manipuler chaque stream pour en créer des nouveaux.
  • Ces manipulations sont très proches de celles que propose l'API des tableaux JavaScript (map, reduce, filter, ...).
  • 1 ou plusieurs stream(s) peut être utilisé comme un input pour un autre stream

2. Manipulate a stream: the operators

  • Example 1: observe a click on a button and use the scan operator to get the number of time the button is clicked.
    From --{e}--{e}--{e}--{e}--{e}--> to --0--1--2--3--4-->


26 / 56
  • Je vous donne un exemple concret pour ne pas que vous saignez du nez trop tôt
  • Je transform le stream d'event en un nombre en partant de 0, et j'incrémente de 1 à chaque valeur

2. Manipulate a stream: the operators

  • Example 2: observe the mouse position and use the map operator to transform the X coordinate into a 0 to 360 value for the hue parameter of a gradient on the UI.
    From --{e}--{e}--{e}--{e}--{e}--> to --126--8--267--98--350-->


27 / 56
  • Je récupère les valeurs X et Y (pos)
  • Je divise le X par la taille de l'écran pour avoir une valeur entre 0 et 1, et je mulitplie par 360 pour avoir les valeurs nécessaires de teinte

3. Subscribing to an observable

https://gist.github.com/staltz/868e7e9bc2a7b8c1f754

  • A stream can emit 3 things:
    • a value
    • an error
    • a "completed" signal
stream$.subscribe(
(value) => doSomething(value),
(error) => console.error(error),
() => console.log('complete')
);
28 / 56

Animation from Observables

Example of a basic non-reactive animation: a moving ball


  • a frame rate
  • a duration
  • a velocity
  • an easing?
29 / 56
  • Comment définir une animation?
  • commencer par une animation simple

Animation from Observables

Example of a basic non-reactive animation: a moving ball


  • a frame rate

Schedule a stream on animation frame

  • a duration

Limit a stream with takeWhile

  • a velocity

Map a velocity function (px / ms)

  • an easing?

Map an easing function

30 / 56

Animation from Observables

Rx.Observable ...


  • a frame rate

.interval( 0, Rx.Scheduler.animationFrame )

  • a duration

.takeWhile( (t) => t <= duration )

  • a velocity

.map( (t) => velocity(t) )

  • an easing?

.map( (t) => elasticOut(t) )

31 / 56
  • Grossièrement c'est ce qui va se passer
  • Petits détails d'adaptation plus tard

Animation from Observables

--0--1--2--3--4--5--6--7--8--9--10--[...]->


  • a frame rate

Stream of intervals: --0--1--2--3--4--5--6--7--8--9--10--[...]->

  • a duration

Stream of ms: --2--6--17--18--31--32--48--[...]--1998--2012--|->

  • a velocity

Stream of px: --2--4--8--[...]--123--125--[...]--297--300--|-->

  • an easing?

Stream of px: --1--2--4--[...]--61--65--[...]--297--300--|-->

32 / 56

Animation from Observables

33 / 56
  • Defer: pour calculer la durée on récupère l'heure actuelle et on fait des différences à chaque intervalle. Defer permet de récupérer l'heure au moment de la subscription plutôt qu'au moment où le JS est parsé.
  • Duration: pour arrêter le stream, il a d'abord fallu transformer ses valeurs en intervalles de temps.
  • Easing: la fonction attend es valeurs entre 0 et 1 donc il a fallu adapter ces valeurs

Animation from Observables

  • Another example: loader


34 / 56

Animation from Observables


  • Listen to the animation frames given by the browser
  • Create a set of time differences on animation frame
  • Map those time differences into position differences
  • Subscribe and manipulate the DOM
35 / 56
  • Exemple qui nous permet de comprendre un peu mieux les Observables
  • Mais les Observables ne sont pas forcément le meilleur outils pour gérer ce type d'animation.
  • Les CSS keyframes sont natives et très pratiques pour ce genre d'animation
  • Greensock est très performant et sa timeline est très claire
  • Canvas permet de faire du raster plutôt que des px et est très performant pour les animations complexes
  • Etc.
  • Pourquoi Material motion alors?
  • Les animations avec des Observables peuvent être à mon sens essentielles pour 2 raisons : leur réactivité et leur modularité

1. Reactivity

  • Animation on input change


36 / 56

1. Reactivity

37 / 56

1. Reactivity

  • Animation on mousemove


38 / 56

1. Reactivity

39 / 56

1. Reactivity

  • Animation on scroll


40 / 56
  • Effet de parallax et de fading

1. Reactivity

  • Discrete changes caused by any number of events
  • Already widely used in mobile environment

reactive mobile sample

reactive mobile sample

41 / 56
  • Definition de la réactivité
  • Le premier intérêt des Observables pour les animations est qu'ils permettent d'"observer" les actions des utilisateurs et de réagir en fonction.
  • Une animation réactive utilise des valeurs dynamiques directement émises par les actions des utilisateurs.

2. Modularity

  • Interface any event source to any listener
  • Make uniform the way we deal with fetched data, WebSockets communication, external events from multiple sources, or even animations, ...
// Event
document.getElementById('foo')
.addEventListener('click', listener);
// Promise
fetch('/foo/1')
.then(listener)
// Array
[1, 2, 3, 4]
.forEach(listener)
clickStream$.subscribe({
next: listener
});
fetchResponseStream$.subscribe({
next: listener
});
arrayStream$.subscribe({
next: listener
});
42 / 56
  • Chaque méthode met son listener à différentes places
  • L'Observable est un wrapper qui leur donne à tous la même interface

2. Modularity

  • Promote "Separation of concerns"
  • We declaratively represent the data we expect using Observables and operators, and then deal with side effects in a single .subscribe().
var mouseStream$ = Rx.Observable
.fromEvent(document, 'mousemove');
var manipulateStream$ = moveStream$
.map(function(pos) {
return changeData(pos)
});

Manage data

manipulateStream$.subscribe(function(value) {
updateUI(value);
});

Manage rendering

43 / 56

2. Modularity

  • It's not a framework
  • It can be used in many frameworks (React, Angular, and Vue)
  • It can be used in many languages (Java, PHP, Python, Ruby, C#, Swift, ...)
  • React, Elm (~Signals)
44 / 56

2. Modularity

  • Foster reusability
  • Declarative and Functional approach: abstraction
  • Observables can have multiple subscription, meaning they can be reused
45 / 56
  • Dans cet exemple donné plus tôt, l'Observable hueStream$ est utilisé à 2 reprises : pour changer le bkg et pour changer le label central

2. Modularity

  • Examples of Material Motion:

Arc move from one location to another

Arc transition in which the center of the context moves along an arc path.

Choreographed transition to create a perception of contextual expansion

A dialog that expands from a location and reveals contents

46 / 56
  • Dans ses guidelines, Material design définit quelques concepts applicables aux animations : montrer une continuité entre 2 interfaces, créer de nouveaux composants en réaction à un événement, montrer une relation spaciale entre 2 composants, etc. Avec des easing et des durations pré-définies.
  • Le projet Material motion est de créer un catalogue de mouvement pour construire des animations et favoriser leur cohérence.

2. Modularity

Material Motion: "eliminate the concept of a design/engineering “hand off” by encouraging both designers and engineers to think of motion in a common language".

"V1 ideal journey"
The "handoff" is still here, but the Material Motion language helps the motion designers to describe their concept. Source

47 / 56
  • L'idée est qu'en définissant un langage commun et des mouvements prédéfinis, il sera plus facile de tester des animations et de les mettre en production.
  • Pour cela Material Motion mise sur les Observables car ils sont facilement manipulable, reactif et "highly-coordinated"

2. Modularity

Material Motion: "eliminate the concept of a design/engineering “hand off” by encouraging both designers and engineers to think of motion in a common language".

"V2 ideal journey"
There is no more "handoff", the motion designer (or anyone else) directly use the Material Motion language to prototype the concept. Source

48 / 56
  • L'idée est qu'en définissant un langage commun et des mouvements prédéfinis, il sera plus facile de tester des animations et de les mettre en production.
  • Pour cela Material Motion mise sur les Observables car ils sont facilement manipulable, reactif et "highly-coordinated"

Beyond

var $target = document.querySelector('...');

With Event listener:

document.addEventListener('mousemove', function(e) {
$target.innerHTML = `(${e.clientX})`;
});

With Observable subscription:

mouseMove$.subscribe(function(val) {
$target.innerHTML = `(${val.clientX})`;
});

Issues in both cases:

  • DOM dependency (read / write)
  • Multiple event listener on the same component
  • Conflicts (overwritten transform property, media queries not considered, ...)
  • Performance ("the DOM is slow")
  • ...
49 / 56

Functional Reactive Animation with CSS

  • David Khourshid (@davidkpiano)
  • Using CSS variables with JS Observables

js to css

50 / 56
  • L'idée derrière est de véritablement séparer les rôles
  • Les Observables capturent des événements et émettent des valeurs
  • Le variables CSS les retranscrivent sur le front

RxCSS

const mouse$ = Rx.Observable
.fromEvent(document, 'mousemove')
.map(({ x, y }) => ({ x, y }));
const style$ = RxCSS({
mouse: mouse$,
})
style$.subscribe(...);
:root {
--mouse-x: 0;
--mouse-y: 0;
}
.ball {
transform:
translate(calc(var(--mouse-x) * 1px))
translateY(calc(var(--mouse-y) * 1px));
}


Elements from http://slides.com/davidkhourshid/reactanim#/

51 / 56

Functional Reactive Animation with CSS

  • CSS Variables are easily debuggable in the dev tools
  • Maintainable
  • No excessive DOM manipulation
  • DOM node independent
  • Full power of CSS: pseudo-selectors, media queries, calc(), theming, ...
  • Easy fallbacks
52 / 56

Functional Reactive Animation with CSS

  • "Alex the CSS Husky" by @davidkpiano
  • The reactivity to the mouse is given by a subscription writing only in 2 CSS variables (--mouse-x and --mouse-y)
53 / 56

What is left to do?

  • Experiment RxJS
  • Design animation
  • Experiment RxJS
  • Agreed on concepts and on our own motion catalog
  • Experiment RxJS
  • Play more with CSS custom properties...
  • ...and PostCSS!
  • Follow Material Motion project evolution
  • Experiment RxJS

Let's go !


54 / 56

Thanks

56 / 56

Bringing UI to life

Why animating an interface can enhance the UX?


  • Convey meaning: "Motion is meaningful" (Material Design)
  • Focus attention
  • Maintain continuity
  • Reduce cognitive load
  • Describe components relationships
  • Explain the intent of a functionality
  • Is part of the Identity: character, beauty and delight
2 / 56
Paused

Help

Keyboard shortcuts

, , Pg Up, k Go to previous slide
, , Pg Dn, Space, j Go to next slide
Home Go to first slide
End Go to last slide
Number + Return Go to specific slide
b / m / f Toggle blackout / mirrored / fullscreen mode
c Clone slideshow
p Toggle presenter mode
t Restart the presentation timer
?, h Toggle this help
Esc Back to slideshow