[wip] Switch from Anime to Motion One for page animations

This commit is contained in:
2022-08-14 00:45:44 +02:00
parent a044cf3939
commit f771a73b67
13 changed files with 295 additions and 222 deletions

View File

@@ -3,14 +3,15 @@
</style>
<script lang="ts">
import { navigating, page } from '$app/stores'
import { page, navigating } from '$app/stores'
import { onMount } from 'svelte'
import anime, { type AnimeTimelineInstance } from 'animejs'
import { timeline } from 'motion'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime.js'
import { getAssetUrlKey } from '$utils/helpers'
import { quartOut } from '$animations/easings'
import { fetchAPI } from '$utils/api'
import { DURATION } from '$utils/contants'
import { DELAY, DURATION } from '$utils/contants'
import { photoFields } from '.'
// Components
import Metas from '$components/Metas.svelte'
@@ -146,43 +147,51 @@
/**
* Animations
*/
// Transition in
const timeline: AnimeTimelineInstance = anime.timeline({
duration: 1600,
easing: 'easeOutQuart',
autoplay: false,
const animationDelay = $navigating ? DURATION.PAGE_IN : 0
const animation = timeline([
// Title word
['.location-page__intro .word', {
y: ['110%', 0],
}, {
at: 0.2 + animationDelay,
}],
// Illustration
['.location-page__illustration', {
scale: [1.06, 1],
opacity: [0, 1],
}, {
at: 0.4 + animationDelay,
duration: 2.4,
}],
// Title of
['.location-page__intro .of', {
opacity: [0, 1],
}, {
at: 0.95 + animationDelay,
duration: 1.2,
}],
// Description
['.location-page__description', {
y: ['10%', 0],
opacity: [0, 1],
}, {
at: 0.9 + animationDelay,
duration: 1.2,
}]
], {
delay: DELAY.PAGE_LOADING / 1000,
defaultOptions: {
duration: 1.6,
easing: quartOut,
},
})
animation.stop()
// Title word
timeline.add({
targets: '.location-page__intro .word',
translateY: ['110%', 0],
delay: anime.stagger(200)
}, 200 + ($navigating ? DURATION.PAGE_IN : 0))
// Illustration
timeline.add({
targets: '.location-page__illustration',
scale: [1.06, 1],
opacity: [0, 1],
duration: 2400,
}, 400 + ($navigating ? DURATION.PAGE_IN : 0))
// Title of
timeline.add({
targets: '.location-page__intro .of',
opacity: [0, 1],
duration: 1200,
}, 950 + ($navigating ? DURATION.PAGE_IN : 0))
// Description
timeline.add({
targets: '.location-page__description',
translateY: ['10%', 0],
opacity: [0, 1],
}, 900 + ($navigating ? DURATION.PAGE_IN : 0))
requestAnimationFrame(timeline.play)
// Run animation
requestAnimationFrame(animation.play)
// Destroy

View File

@@ -4,7 +4,9 @@
<script lang="ts">
import { onMount } from 'svelte'
import anime, { type AnimeTimelineInstance } from 'animejs'
import { stagger, timeline } from 'motion'
import { DELAY } from '$utils/contants'
import { quartOut } from 'svelte/easing'
// Components
import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
@@ -19,39 +21,40 @@
/**
* Animations
*/
// Setup animations
const timeline: AnimeTimelineInstance = anime.timeline({
duration: 1600,
easing: 'easeOutQuart',
autoplay: false,
const animation = timeline([
// Heading
['.heading .text', {
y: [24, 0],
opacity: [0, 1],
}],
// Categories
['.credits__category', {
opacity: [0, 1],
}, {
at: 0,
delay: stagger(0.35, { start: 0.5 }),
}],
// Names
['.credits__category > ul > li', {
y: [24, 0],
opacity: [0, 1],
}, {
at: 1.1,
delay: stagger(0.35),
}],
], {
delay: DELAY.PAGE_LOADING / 1000,
defaultOptions: {
duration: 1.6,
easing: quartOut,
},
})
animation.stop()
anime.set('.heading .text, .credits__category > ul > li', {
opacity: 0,
translateY: 24,
})
anime.set('.credits__category', {
opacity: 0,
})
// Elements
timeline.add({
targets: '.heading .text, .credits__category',
opacity: 1,
translateY: 0,
delay: anime.stagger(350),
}, 500)
// Names
timeline.add({
targets: '.credits__category > ul > li',
opacity: 1,
translateY: 0,
delay: anime.stagger(350),
}, 1100)
// Transition in
requestAnimationFrame(timeline.play)
// Run animation
requestAnimationFrame(animation.play)
})
</script>

View File

@@ -5,10 +5,11 @@
<script lang="ts">
import { page } from '$app/stores'
import { getContext, onMount } from 'svelte'
import anime, { type AnimeTimelineInstance } from 'animejs'
import { timeline, stagger } from 'motion'
import { DELAY } from '$utils/contants'
import { sleep, smoothScroll } from '$utils/functions'
import { smoothScroll } from '$utils/functions'
import { reveal, fade as animeFade } from '$animations/index'
import { quartOut } from '$animations/easings'
// Components
import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
@@ -30,36 +31,42 @@
const { settings, locations }: any = getContext('global')
let scrollY: number, innerHeight: number
let timeline: AnimeTimelineInstance
onMount(() => {
timeline = anime.timeline({
duration: 1600,
easing: 'easeOutQuart',
autoplay: false,
})
/**
* Animations
*/
const animation = timeline([
// Reveal text
['.homepage__headline', {
y: [16, 0],
opacity: [0, 1],
}, {
at: 0.75,
}],
// Reveal text
timeline.add({
targets: '.homepage__headline',
translateY: [16, 0],
opacity: [0, 1],
}, 750)
// Animate collage photos
timeline.add({
targets: '.collage .photo-card',
translateY: ['33.33%', 0],
rotate (item: HTMLElement) {
return [-4, getComputedStyle(item).getPropertyValue('--rotation')]
// Animate collage photos
['.collage .photo-card', {
y: ['33.33%', 0],
rotate: [-4, 0],
opacity: [0, 1],
}, {
at: 0,
duration: 1.2,
delay: stagger(0.075),
}]
], {
delay: DELAY.PAGE_LOADING / 1000,
defaultOptions: {
duration: 1.6,
easing: quartOut,
},
opacity: [0, 1],
duration: 1200,
delay: anime.stagger(75),
}, 0)
})
animation.stop()
sleep(DELAY.PAGE_LOADING).then(timeline.play)
// Run animation
requestAnimationFrame(animation.play)
})
</script>

View File

@@ -7,11 +7,13 @@
import { goto } from '$app/navigation'
import { getContext, onMount } from 'svelte'
import { fly } from 'svelte/transition'
import { quartOut } from 'svelte/easing'
import dayjs from 'dayjs'
import { quartOut as quartOutSvelte } from 'svelte/easing'
import relativeTime from 'dayjs/plugin/relativeTime.js'
import anime, { type AnimeTimelineInstance } from 'animejs'
import { stagger, timeline } from 'motion'
import { DELAY } from '$utils/contants'
import { fetchAPI } from '$utils/api'
import { quartOut } from '$animations/easings'
import { map, lerp, throttle } from '$utils/functions'
// Components
import Metas from '$components/Metas.svelte'
@@ -282,37 +284,30 @@
const existingPhotos = photosGridEl.querySelectorAll('.photo')
existingPhotos.forEach(el => observerPhotos.observe(el))
/**
* Animations
*/
// Transition in
const timeline: AnimeTimelineInstance = anime.timeline({
duration: 1600,
easing: 'easeOutQuart',
autoplay: false,
const animation = timeline([
// Reveal text
['.photos-page__intro .discover, .photos-page__intro .filters__bar', {
y: [16, 0],
opacity: [0, 1],
}, {
at: 0.4,
delay: stagger(0.25),
}]
], {
delay: DELAY.PAGE_LOADING / 1000,
defaultOptions: {
duration: 1.6,
easing: quartOut,
},
})
animation.stop()
// Reveal text
timeline.add({
targets: '.photos-page__intro .discover',
translateY: [16, 0],
opacity: [0, 1],
}, 900)
// Filters
timeline.add({
targets: '.photos-page__intro .filters',
translateY: [16, 0],
opacity: [0, 1],
complete ({ animatables }) {
const element = animatables[0].target
// Remove style to not interfere with CSS when scrolling back up over photos
element.removeAttribute('style')
}
}, 1300)
// Play animation
requestAnimationFrame(timeline.play)
// Run animation
requestAnimationFrame(animation.play)
// Destroy
@@ -351,9 +346,8 @@
class:is-transitioning={filtersTransitioning}
class:is-visible={filtersVisible}
>
<span class="text-label filters__label">Filter photos</span>
<div class="filters__bar">
<span class="text-label filters__label">Filter photos</span>
<ul>
<li>
<Select
@@ -418,7 +412,7 @@
{#if filtered}
<button class="reset button-link"
on:click={resetFiltered}
transition:fly={{ y: 4, duration: 600, easing: quartOut }}
transition:fly={{ y: 4, duration: 600, easing: quartOutSvelte }}
>
Reset
</button>

View File

@@ -4,8 +4,10 @@
<script lang="ts">
import { onMount } from 'svelte'
import { stagger, timeline } from 'motion'
import dayjs from 'dayjs'
import anime, { type AnimeTimelineInstance } from 'animejs'
import { DELAY } from '$utils/contants'
import { quartOut } from '$animations/easings'
// Components
import Metas from '$components/Metas.svelte'
import PageTransition from '$components/PageTransition.svelte'
@@ -22,37 +24,36 @@
/**
* Animations
*/
// Setup animations
const timeline: AnimeTimelineInstance = anime.timeline({
duration: 1600,
easing: 'easeOutQuart',
autoplay: false,
const animation = timeline([
// Elements
['.heading .text, .subscribe__top .newsletter-form, .subscribe__issues', {
y: [24, 0],
opacity: [0, 1],
}, {
at: 0.5,
delay: stagger(0.35),
}],
// Reveal each issue
['.subscribe__issues > ul > li', {
y: [16, 0],
opacity: [0, 1],
}, {
duration: 1,
at: 1.5,
delay: stagger(0.15),
}],
], {
delay: DELAY.PAGE_LOADING / 1000,
defaultOptions: {
duration: 1.6,
easing: quartOut,
},
})
animation.stop()
anime.set('.heading .text, .subscribe__top .newsletter-form, .subscribe__issues', {
opacity: 0,
translateY: 24,
})
// Elements
timeline.add({
targets: '.heading .text, .subscribe__top .newsletter-form, .subscribe__issues',
opacity: 1,
translateY: 0,
delay: anime.stagger(200),
}, 500)
// Reveal each issue
timeline.add({
targets: '.subscribe__issues .issue',
opacity: [0, 1],
translateY: [16, 0],
delay: anime.stagger(150),
duration: 1000,
}, 1000)
// Transition in
requestAnimationFrame(timeline.play)
// Run animation
requestAnimationFrame(animation.play)
})
</script>
@@ -75,22 +76,24 @@
<h2 class="title-small">Past Issues</h2>
<ul>
{#each issues as { issue, title, date_sent, link, thumbnail: { id } }}
<li class="issue">
<a href={link} target="_blank" rel="external noreferrer noopener" tabindex="0">
<Image
id={id}
sizeKey="issue-thumbnail-small"
width={160} height={112}
alt="Issue {issue} thumbnail"
/>
<dl>
<dt>Issue #{issue}</dt>
<dd>
<p>{title}</p>
<time>{dayjs(date_sent).format('DD/MM/YYYY')}</time>
</dd>
</dl>
</a>
<li>
<div class="issue">
<a href={link} target="_blank" rel="external noreferrer noopener" tabindex="0">
<Image
id={id}
sizeKey="issue-thumbnail-small"
width={160} height={112}
alt="Issue {issue} thumbnail"
/>
<dl>
<dt>Issue #{issue}</dt>
<dd>
<p>{title}</p>
<time>{dayjs(date_sent).format('DD/MM/YYYY')}</time>
</dd>
</dl>
</a>
</div>
</li>
{/each}
</ul>