Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/the-craft/llms.txt

Use this file to discover all available pages before exploring further.

PageTransition is the shared animation wrapper that every page in The Craft uses as its outermost element. When you navigate from one route to another, the current page blurs out and slides upward off the screen while the incoming page blurs in and rises into position. This consistent enter/exit choreography makes the portfolio feel like turning pages in a spellbook rather than loading a new URL — and because PageTransition is a single reusable component, the same motion applies everywhere without duplicating animation code.

How It Works

PageTransition renders a single Framer Motion motion.div that carries three animation states:
Stateopacityfiltery
initial (enter start)0blur(10px)20px
animate (resting)1blur(0px)0px
exit (leave)0blur(10px)-20px
The page enters from slightly below (y: 20) and blurred, then settles into focus. On exit, it blurs and rises upward (y: -20). The asymmetry between enter (+20) and exit (-20) creates a sense of upward momentum — as though each page is lifted away and the next one floats up into its place. The transition uses a custom cubic-bezier easing curve [0.22, 1, 0.36, 1] at a duration of 0.8 seconds, which gives the animation a fast initial burst that eases into a smooth landing — perceptually snappy without feeling rushed.
The blur animation relies on Framer Motion interpolating the CSS filter property as a string. This is hardware-accelerated in modern browsers and performs well even on mid-range devices. If you see performance issues, reducing the blur radius from 10px to 4px in both initial and exit can help.

AnimatePresence and mode="wait"

PageTransition is designed to be used inside a Framer Motion <AnimatePresence mode="wait"> block. In wait mode, the exiting page’s animation must fully complete before the entering page begins its animation — so you will never see two pages on screen simultaneously. This is handled in the routing layer by wrapping <Routes> in <AnimatePresence mode="wait"> and keying it on the current location pathname.

Props

PropTypeDefaultDescription
childrenReactNodeThe page content to render inside the motion wrapper.
classNamestring""Additional Tailwind classes merged onto the motion.div. The base classes min-h-screen w-full are always applied.

Usage

Wrap your page component’s return value in <PageTransition> as the outermost element:
import { P as PageTransition } from '../components/PageTransition';

export function MyPage() {
  return (
    <PageTransition className="min-h-screen p-8">
      {/* page content */}
    </PageTransition>
  );
}
Every page in The Craft follows this pattern. The className prop is optional — use it to add page-specific padding, background color overrides, or layout utilities that should live on the outermost container:
import { P as PageTransition } from '../components/PageTransition';

// Home page — no extra padding needed, full bleed background
export function Home() {
  return (
    <PageTransition>
      <HeroSection />
    </PageTransition>
  );
}

// About page — constrained readable width with padding
export function About() {
  return (
    <PageTransition className="max-w-4xl mx-auto px-6 py-16">
      <AboutContent />
    </PageTransition>
  );
}
Because PageTransition always applies min-h-screen w-full, you do not need to add those utilities yourself. Any className you pass is merged with those base classes, not a replacement for them.
Do not nest <PageTransition> inside itself. If a parent page already uses PageTransition as its wrapper, section components inside it should not also use PageTransition — that would produce double-blurred, double-animated content during route changes.

Build docs developers (and LLMs) love