Animations beyond CSS
Prague 21 Sept18
Eduardo
San Martin Morote
Freelance Dev & Instructor
Vue core team
πββοΈ β¨οΈ π


Demo
Made with Nuxt!
Animations are hard

Activity monitor Jardson Almeida
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)
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
Prefer CSS Over
Javascript
Browsers + GPU β₯οΈ Pure CSS

Thanks! π

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.
- 2,506