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
Made with Slides.com