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,377