THE Future of WEB Animation

Before we begin.. @sarah_edo

@sarah_edo

@sarah_edo

@sarah_edo

THE Future of WEB Animation

@sarah_edo

Communicating @sarah_edo

? @sarah_edo

Happiness sadness Fear curiosity @sarah_edo

Happiness sadness Fear curiosity @sarah_edo

@sarah_edo

@sarah_edo

Anything can happen

SARAH DRASNER @SARAH_EDO

page transitions

@sarah_edo

Vue Single File Components <template> <div></div> </template> <script> export default { } </script> <style scoped> </style> @sarah_edo

<nuxt-link to=”/product”>Product</nuxt-link> Livecode Nuxt Resource @sarah_edo

@sarah_edo

Transition hook already available name=“page” .page-enter-active, .page-leave-active { transition: all .25s ease-out; } .page-enter, .page-leave-active { opacity: 0; transform: scale(0.95); transform-origin: 50% 50%; } @sarah_edo

@sarah_edo

Js hooks export default { transition: { mode: ‘out-in’, css: false, enter (el, done) { let tl = new TimelineMax({ onComplete: done }), spt = new SplitText(‘h1’, { type: ‘chars’ }), chars = spt.chars; TweenMax.set(chars, { transformPerspective: 600, perspective: 300, transformStyle: ‘preserve-3d’ }) } tl.add(‘start’) tl.from(el, 0.8, { scale: 0.9, transformOrigin: ‘50% 50%’, ease: Sine.easeOut }, ‘start’) … tl.timeScale(1.5) @sarah_edo

@sarah_edo

@sarah_edo

Repo https://github.com/sdras/nuxt-type @sarah_edo

Native-like page transitions

@sarah_edo

Cognitive Load Kathy Sierra: Badass, Making Users Awesome @sarah_edo

@sarah_edo

@sarah_edo

@sarah_edo

In store/index.js import Vuex from ‘vuex’ const createStore = () =>” { return new Vuex.Store({ state: { page: ‘index’ }, mutations: { updatePage(state, pageName) { state.page = pageName } } }) } export default createStore @sarah_edo

In middleware/pages.js: export default function(context) { // go tell the store to update the page context.store.commit(‘updatePage’, context.route.name) } register the middleware in nuxt.config.js: module.exports = { … router: { middleware: ‘pages’ } } @sarah_edo

In layouts/default.vue: <template> <div> <app-navigation /> <nuxt/> </div> </template> In AppNavTransition.vue: <h2 key=”profile-name” class=”profile-name”> <span v-if=”page ===$$ ‘group’” class=”user-trip”>{{ selectedUser.trip }}</span> <span v-else>{{ selectedUser.name }}</span> </h2> @sarah_edo

<transition-group /> Flip under the hood Rosario’s article @sarah_edo

Transition Group wraps it… <transition-group name=”layout” tag=”g”> <rect class=”items rect” ref=”rect” key=”rect” width=”171” height=”171”/> … </transition-group> Styles: .items, .list-move { transition: all 0.4s ease; } .active { .rect { transform: translate3d(0, 30px, 0); } … } @sarah_edo

//animations .place { .follow { transform: translate3d(-215px, -80px, 0); } .profile-photo { transform: translate3d(-20px, -100px, 0) scale(0.75); } .profile-name { transform: translate3d(140px, -125px, 0) scale(0.75); color: white; } .side-icon { transform: translate3d(0, -40px, 0); background: rgba(255, 255, 255, 0.9); } .calendar { opacity: 1; } } @sarah_edo

@sarah_edo

My Demo vue/nuxt css-tricks.com/native-like-animations-for-page-transitions-on-the-web/ github.com/sdras/page-transitions-travelapp Simona Cotin fork angular/typescript github.com/simonaco/page-transitions-travelapp Shawn wang (swyx) fork react/next github.com/sw-yx/page-transitions-react-travelapp @sarah_edo

Next-level responsive

@sarah_edo

@sarah_edo

@sarah_edo

@joshcarpenter @sarah_edo

@joshcarpenter @sarah_edo

@joshcarpenter @sarah_edo

@joshcarpenter @sarah_edo

Index page design inspired from this dribbble shot @sarah_edo

methods: { startDrag() { this.dragging = true this.x = this.y = 0 }, stopDrag() { this.dragging = false }, coords(e) { if (this.page ===$$ ‘vrview’ && this.dragging) { this.x = (e.clientX || e.touches[0].clientX) / 60 + 4 this.y = (e.clientY || e.touches[0].clientY) / 100 + 5 } }, … } @sarah_edo

<div v-if=”page ===$$ ‘vrview’” :style=”{ perspectiveOrigin: `${x}% ${y}%`, transform: `rotateY(${x * 4}deg)` }”> <app-nav /> </div> <app-nav v-else/> <nuxt /> <div class=”movearound” v-if=”page ===$$ ‘indview’ || page ===$$ ‘vrview’” :style=”{ perspectiveOrigin: `${x/2}% ${y/2}%`, transform: `rotateY(${x*4}deg) translate3d(0, 0, 0)` }”> <app-bottommain :x=”x” :y=”y” /> </div> @sarah_edo

this.scene = new THREE.Scene() var geometry = new THREE.SphereBufferGeometry(500, 60, 40) // invert the geometry on the x-axis so that all of the faces point inward geometry.scale(-1, 1, 1) var material = new THREE.MeshBasicMaterial({ map: new THREE.TextureLoader().load(imgsrc) }) mesh = new THREE.Mesh(geometry, material) this.scene.add(mesh) @sarah_edo

update() { lat = Math.max(-85, Math.min(85, lat)) phi = THREE.Math.degToRad(90 - lat) theta = THREE.Math.degToRad(lon) camera.target.x = 500 * Math.sin(phi) * Math.cos(theta) camera.target.y = 500 * Math.cos(phi) camera.target.z = 500 * Math.sin(phi) * Math.sin(theta) camera.lookAt(camera.target) renderer.render(scene, camera) } @sarah_edo

div { width: 500px; height: 500px; } border-radius: 50%; } @media vr { div { material: grass; } } @sarah_edo

sphere { material: envmap(0.9) reflectivity(0.5); } threejs.org/examples @sarah_edo

@joshcarpenter @sarah_edo

@sarah_edo

@sarah_edo

supermedium.com @sarah_edo

supermedium.com/supercraft @sarah_edo

ARKit 2.0 @OsFalmer @sarah_edo

@sarah_edo

@sarah_edo

Daniel @danielkuntz0 @sarah_edo

AR Expedition @sarah_edo

static 2d is an abstraction

Minh Pham on Dribbble @sarah_edo

@sarah_edo

@sarah_edo

How Virtual Reality Benefits Seniors Aditi Khazanchi @sarah_edo

seaheroquest.com @sarah_edo

The Art of Journey @sarah_edo

Hands-free experiences

@sarah_edo

@sarah_edo

@sarah_edo

@sarah_edo

@sarah_edo

SLOW DOWN @sarah_edo

BIOFEEDBACK

@sarah_edo

@sarah_edo

In store.js (Vuex) export default new Vuex.Store({ state: { counter: 0, intent: ‘None’, intensity: ‘None’, score: 0, // idle - awaiting user input // listening - listening to user input // fetching - fetching user data from the API uiState: ‘idle’, zoom: 3 }, getters: { intentStr: state => { var str = state.intent str = str.replace(/\b(App.)\b/gi, ”) return str }, @sarah_edo

In store.js (Vuex) actions: { getSpeech({ dispatch, commit, state }) { commit(‘setUiState’, ‘listening’) //keep recording speech all the time or activate it//for the first screen no, press a button. second screen yes. state.intent === ‘None’ ? (recognition.continuous = true) : (recognition.continuous = false) recognition.start() … }, recognition.onresult = function(event) { const last = event.results.length - 1 const phrase = event.results[last][0].transcript dispatch(‘getUnderstanding’, phrase) } @sarah_edo

In store.js (Vuex) getUnderstanding({ commit }, utterance) { commit(‘setUiState’, ‘fetching’) const url = https://westus.api.cognitive.microsoft.com/luis/v2.0/apps /4aba2274-c5df-4b0d-8ff7-57658254d042 https: axios({ method: ‘get’, url, params: { verbose: true, timezoneOffset: 0, q: utterance }, headers: { ‘Content-Type’: ‘application/json’, ‘Ocp-Apim-Subscription-Key’: ‘XXXXXXXXXXXXXXXXXXX’ } }) @sarah_edo

@sarah_edo

@sarah_edo

In store.js (Vuex) mutations: { newIntent: (state, {intent, score}) => { if (intent.includes(‘Intensity’)) { state.intensity = intent if (intent.includes(‘More’)) { state.counter++ } else if (intent.includes(‘Less’)) { state.counter-} } else { state.intent = intent } state.score = score }, … } @sarah_edo

In Base.vue (Components) createShapes() { this.bufferCamera.position.z = this.shapeZoom if (this.torusKnot !== null) { this.torusKnot.material.dispose() this.torusKnot.geometry.dispose() this.bufferScene.remove(this.torusKnot) } var shape = new THREE.TorusKnotGeometry( this.tConfig.a, this.tConfig.b, this.tConfig.c, this.tConfig.d ), material … this.torusKnot = new THREE.Mesh(shape, material) this.torusKnot.material.needsUpdate = true this.bufferScene.add(this.torusKnot) }, @sarah_edo

In Base.vue (Components) animate() { this.storeRAF = requestAnimationFrame(this.animate) this.bufferScene.rotation.x += 0.01 this.bufferScene.rotation.y += 0.02 this.renderer.render( this.bufferScene, this.bufferCamera, this.bufferTexture ) this.renderer.render(this.scene, this.camera) }, @sarah_edo

In Base.vue (Components) watch: { shapeZoom() { this.createShapes() cancelAnimationFrame(this.storeRAF) this.animate() } }, Repo: github.com/sdras/three-vue-pattern @sarah_edo

@sarah_edo

Charlie Gerard, @devdevcharlie @sarah_edo

“We are in a rut. A rut shaped like this” -Jen Simmons @sarah_edo

Take up space

Think bigger

Thank you! @sarah_edo