Animations beyond CSS

Prague 21 Sept18

GitHub icon
Twitter icon

Eduardo

San Martin Morote

Freelance Dev & Instructor

Vue core team

๐ŸŠโ€โ™‚๏ธ โŒจ๏ธ ๐ŸŒ

GitHub icon

Demo

Made with Nuxt!

Animations are hard

Activity monitor

Animations should be fast

Hi there ๐Ÿ‘‹

I'm taking

my time

to appear...

Animating when...

  • The user does something
  • We need user's attention
  • We want to make things fun

<Transition/>ย 

<Transition-group/>

Based on

  • Entering/Leaving the page (v-if, v-show, key)
  • Reordering (v-for)

Using

CSS or

Javascript

CSS transitions

.fade-in, .fade-out {
  transition: opacity 300ms;
}

.fade-out {
  opacity: 0;
}

CSS animations

.my-element {
  animation: moving 1s infinite alternate;
}

@keyframes moving {
  0% { transform: translateX(0); }
  100% { transform: translateX(200px); }
}

Transition + Animate.css

๐Ÿ‘Ž rotation, translation, scaling

๐Ÿ‘ opacity, colours, etc

๐Ÿ‘‰ Basic Transition

Transition + ANimate.css

<transition
  enter-active-class="animated slideInLeft"
  leave-active-class="animated slideOutRight fadeOut"
>
  <div v-if="on" key="onDiv">On</div>
  <div v-else>Off</div>
</transition>

Limited to

  • Elements appearing
  • Elements disappearing
  • Elements reordering
  • CSS properties

CSS animations

  • transition
  • animation
transition: opacity 1s;
0
1
animation: fade 1s;
0
1
.8

(keyframes)

State Animations

What is it?

How to go from one state to another

ย 

  • Easings
  • Physicsย 

Easing

Go from 10ย to 100 Bouncing outย in 1 second

10: initial value

100: target value

Bouncing out: Easing

1s: duration

๐Ÿ‘‰ Easing graph

Inspired by easings.net

SPRING

Go to 100ย quickly and no oscillation

100: target value

quickly: high stiffness

no oscillation: low damping

๐Ÿ‘‰ Motion graph

Easing

  • highly customisable
  • many existing easings
  • custom duration
  • easy to chain
  • playback control

Spring

  • only two parameters
  • always feels natural
  • handles interruptions/changes

Let's create a State animation with Tween.js

(or any other tweening lib)

// setup the animation loop
// (do it somewhere, but only once)
function animate(time) {
  requestAnimationFrame(animate)
  TWEEN.update(time)
}
requestAnimationFrame(animate)

const container = { x: 0 } // Tween modifies this
const tween = new TWEEN.Tween(container)
  .to({ x: 300 }, 1000) // change to 300 in 1s
  .easing(TWEEN.Easing.Quadratic.Out)
  .onUpdate(() => {
    // container.x is updated
  })
  .start() // Start the tween immediately.

Necessary boilerplate to create one single tween ๐Ÿ˜ฑ

Tweening with

Vue tweezing

Polygon example

Originally from docs

by @chrisvfritz

๐Ÿ‘‰ Polygon

โœจ Declarative Tweening

<Tweezing
  :to="stats"
  :duration="updateInterval"
  :easing="easing"
>
  <polygon
    slot-scope="pointsArray"
    :points="transformToPoints(pointsArray)"
  ></polygon>
</Tweezing>

Declarativity

Focus on how the state maps to your components, not on how to keep everything in sync

Easings controlled by scroll/Mouse

Using the scroll instead of time as input

๐Ÿ‘‰ Easing with mouse

โœจ Declarative Tweening

<Tweezing
  :to="1" tween="custom"
  :time="mouseYPer"
>
  <div slot-scope="value">
    <pre>{{ mouseYPer }}%</pre>
    <div class="ball" :style="ballStyle(value)">
    </div>
  </div>
</Tweezing>

Tweezing component

  • Watch target value โžก๏ธ create Tween

  • Provide tweened value with a scoped slot

this.rotation // 10
this.rotation = 220
// triggers a new tweening

Tween engines

import {
  Tweezing,
  tweenjsHelper,
} from 'vue-tweezing'
import TWEEN from '@tweenjs/tween.js'

Vue.use(Tweezing, {
  tweenjs: tweenjsHelper(TWEEN),
})

Tween.js

export function tweenjsHelper (TWEEN) {
  return function (value, end, opts) {
    const container = { value }
    // cancel previous tween
    return new TWEEN.Tween(container)
      .to({ value: end }, opts.duration)
      .interpolation(opts.interpolation || TWEEN.Interpolation.Linear)
      .easing(opts.easing || TWEEN.Easing.Quadratic.Out)
    // TODO should probably emit the name of the property too
    // default could be the name if only one value is provided
      .onStart(() => this.$emit('start'))
      .onUpdate(() => {
        opts.$setValue(container.value)
      })
      .onComplete(() => this.$emit('end'))
      .start()
  }
}

Tweezing

๐Ÿ—œ< 1kb

Springs

with

vue motion

svg Chart

๐Ÿ‘‰ Plot

โœจ Declarative Spring

<Motion tag="g" :values="selectedValues">
  <template slot-scope="values">
    <g v-for="(y, i) in values" class="bars">
      <rect
        :x="i * 10 + 20"
        :y="getMax - y * 10"
        width="10"
        :height="y * 10"
      />
    </g>
  </template>
</Motion>

Lazy sudoku example

Originally from docs

by @chrisvfritz

๐Ÿ‘‰ Sudoku

"Original"

with springs

โœจ Declarative Spring

<Motion :values="positions" spring="wobbly">
  <template slot-scope="positions">
    <div v-for="cell in cells"
      :style="{\
        transform: `translate(\
          ${positions[cell.id].x}px,\
          ${positions[cell.id].y}px)\
      `}"
    >
      {{ cell.number }}
    </div>
  </template>
</Motion>

๐Ÿคจ

๐Ÿ”ˆ Sounds

๐Ÿ™‰

Declarative Music

<Music
  src="meatball-parade.mp3"
  :rate="rate"
/>

Declarative Animated Music

<Motion :value="rate" :spring="springConfig">
  <Music
    scoped-slot="{ value }"
    src="meatball-parade.mp3"
    :rate="value"
  />
</Motion>

Other
visual renderers

Declarative 3D Scene

<Renderer :width="width" :height="height">
  <Scene>
    <Camera :position="camPos"/>
    <AmbientLight/>
    <SpotLight :position="lightPosition"/>
    <Cube
      v-for="cube in cubes"
      :key="cube.id"
      :position="cube.position"
    />
    <Ground/>
  </Scene>
</Renderer>

๐Ÿ•บDancing Cubes

<Motion v-for="(cube, i) in cubes"
  :values="cube" :key="i"
>
  <Cube
    slot-scope="cube"
    :position="cube.position"
  />
</Motion>

Getting started

GitHub icon

Prefer CSS Over
Javascript

Browsers + GPU โ™ฅ๏ธ Pure CSSย 

Thanks! ๐Ÿ––

GitHub icon

Animations beyond CSS - Webexpo

By Eduardo San Martin Morote

Animations beyond CSS - Webexpo

Aah, animations. Moving things on the screen will either fascinate your users or make them close your app right away. Add no animations and your users will feel sometimes lost. Add too much and they will be disgusted. But, to make it harder, animations by themselves have to be configured just right to have a meaning. Speed, duration and the object being animated have to be set just right. Now, Vue already provides us with two nice components: transition and transition-group that are based on CSS animations. But what about the state? Numerical values that change and you want to animate. During my talk, I will explain what state transitions are, how they differ from CSS transitions, what are they used for and show some practical implementations. We will cover good and bad practices while we delight ourselves with some demos.

  • 680
Loading comments...

More from Eduardo San Martin Morote