Pagefold

Motion

Animate page transitions with Motion (the engine behind Framer Motion), with a single function call per phase.

Motion is a small, MIT-licensed animation library. Its animate function returns something Pagefold can await, so you write each phase as one line.

npm install motion
import Pagefold from 'pagefold'
import PagefoldJs from 'pagefold/js'
import { animate } from 'motion'

new Pagefold({
  animationSelector: false,
  plugins: [
    new PagefoldJs({
      animations: [
        {
          out: () => animate('#pagefold', { opacity: 0 }, { duration: 0.4 }),
          in: () => animate('#pagefold', { opacity: [0, 1] }, { duration: 0.4 }),
        },
      ],
    }),
  ],
})

Because the function returns the animation, Pagefold waits until it finishes. There is no done to call.

Springs and several elements

in: () =>
  animate(
    '#pagefold h1, #pagefold p',
    { opacity: [0, 1], transform: ['translateY(20px)', 'none'] },
    { type: 'spring', stiffness: 200, damping: 20, delay: stagger(0.08) }
  )
import { animate, stagger } from 'motion'

A different animation per page

The same entries as any other engine, with patterns for the pages they apply to:

animations: [
  {
    from: '/',
    to: '/work/:slug',
    out: () => animate('#pagefold', { opacity: 0, scale: 0.96 }, { duration: 0.3 }),
    in: () => animate('#pagefold', { opacity: [0, 1], scale: [1.04, 1] }, { duration: 0.4 }),
  },
  { out: () => animate('#pagefold', { opacity: 0 }, { duration: 0.3 }), in: () => animate('#pagefold', { opacity: [0, 1] }, { duration: 0.3 }) },
]

The last entry has no patterns, so it is the fallback for every other visit. See JS for how entries are chosen.

Reduced motion

Check prefers-reduced-motion yourself and shorten the animations when the visitor asked for less motion:

const calm = matchMedia('(prefers-reduced-motion: reduce)').matches
const duration = calm ? 0 : 0.4

The A11y plugin can also skip animation for those visits altogether.

The two phases are tested in the project’s browser tests with the same fade shown at the top.