Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/dev-mode-arcade/llms.txt
Use this file to discover all available pages before exploring further.
PageTransition wraps each page’s content in a motion.div that plays a short CRT power-on effect whenever a route is entered or exited. On enter, brightness and contrast spike and the image is momentarily desaturated — mimicking the flash of a phosphor display warming up. The animation resolves in 300ms, keeping navigation snappy while still giving every page change a tactile, physical quality. It is designed to work in tandem with Framer Motion’s AnimatePresence and React Router’s Routes.
Props
The page content to animate.
PageTransition renders a full-height (min-h-screen w-full flex flex-col) wrapper, so children should fill naturally without needing to set their own height. Pass any JSX — layout components, sections, or an entire page tree.Animation
The transition is driven entirely by CSSfilter property interpolation. There are no opacity-fade crossfades or sliding panels — the effect is purely a brightness/contrast/grayscale spike that collapses to normal values as the page settles in.
Animation spec
| Phase | opacity | brightness | contrast | grayscale |
|---|---|---|---|---|
initial (before enter) | 0 | 2 | 2 | 1 (100%) |
animate (fully visible) | 1 | 1 | 1 | 0 (0%) |
exit (leaving) | 0 | 2 | 2 | 1 (100%) |
initial and exit states are identical — the page always flashes in and flashes out with the same CRT effect, giving route changes a symmetric, consistent feel.
Transition config
easeOut front-loads the motion, so the brightness spike resolves quickly at the start and gently settles at the end — matching the decay curve of a real phosphor display.
Usage
With React Router and AnimatePresence
AnimatePresence from Framer Motion is required to trigger the exit animation before the outgoing component unmounts. Without it, the exit filter effect will never play and route changes will cut hard.
Pass
mode="wait" to AnimatePresence so the outgoing page fully exits (completing its exit filter animation) before the incoming page begins its enter animation. Without mode="wait", both animations run simultaneously and the CRT effect loses its power-cycle rhythm.Key prop pattern
Thekey={location.pathname} on Routes is what tells React to unmount the old route component and mount a new one on each navigation. Framer Motion detects the unmount and triggers AnimatePresence’s exit sequence. Without it, navigating between routes at the same component tree depth won’t trigger a re-mount, and the animation won’t replay.
Wrapping a single page
If you only need the animation on one page (e.g. a landing page), you can usePageTransition standalone without AnimatePresence. The enter animation will still play on first mount — only the exit animation requires AnimatePresence.
Layout Behavior
Themotion.div rendered by PageTransition applies these layout classes:
| Class | Effect |
|---|---|
min-h-screen | Ensures the wrapper always fills at least the full viewport height |
w-full | Stretches to the full width of its containing block |
flex flex-col | Allows children to use flex-grow for sticky footers and full-height layouts |
How the CRT Effect Works
The animation targets the CSSfilter property with three simultaneous sub-filters:
brightness(2) — doubles the luminosity of all pixels, washing the screen out to near-white. Combined with the dark arcade background, this creates a sharp flare.
contrast(2) — doubles the difference between light and dark values during the brightness spike, making the flash feel harsher and more abrupt.
grayscale(1) — fully desaturates the image during the spike, stripping the neon colors away. As the animation eases out, saturation is restored and the arcade palette bleeds back in — this is the most visually distinctive part of the effect and the closest analogue to a phosphor tube coming up to temperature.
All three filters animate simultaneously via Framer Motion’s filter interpolation, which handles the compound filter string as a single animated value.
The filter animation is GPU-accelerated in modern browsers via the compositor. On low-power devices or browsers that don’t accelerate
filter, the 300ms duration is short enough that even a software-rendered fallback should not cause visible jank.Related
CRT Overlay
The fixed scanline and vignette layer rendered above all content including page transitions.
ArcadeButton
Pixel-font neon buttons used as navigation triggers that lead to page transitions.
Animations Reference
Full reference for all Framer Motion variants and CSS keyframes in the project.
Architecture: Routing
How React Router and AnimatePresence are wired together at the app level.