The Aurora Borealis portfolio is a single-page React 18 application built with Vite, where every visual element is deliberately layered: a Canvas-rendered starfield and three animated gradient blobs sit at the bottom of the stacking context, a constellation-style navigation floats above them, and React Router mounts page content on top. This document traces each layer, the components responsible for it, and how Framer Motion, React Router DOM, and the Canvas 2D API interact at runtime.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/aurora-borealis/llms.txt
Use this file to discover all available pages before exploring further.
Layer Model
The app composes three distinct visual layers stacked by z-index. Each layer is always present in the DOM — only the content layer swaps its children as the user navigates.| Layer | z-index | Component(s) | Responsibility |
|---|---|---|---|
| Background | z-0 | AuroraBackground, StarField | Ambient visual atmosphere — animated aurora gradients and a twinkling star canvas |
| Navigation | above background | ConstellationNav | Persistent site navigation styled as constellation nodes |
| Content | topmost | Routes + page components | Route-matched page content with enter/exit transitions |
pointer-events-none so they never intercept clicks or keyboard focus intended for the content layer.
Prose Description of the Layer Stack
Imagine the screen as a night sky. At the very back, a full-screen<canvas> element draws stars and occasional shooting-star trails using requestAnimationFrame. Directly in front of it, three absolutely-positioned motion.div elements emit soft radial gradients in teal, cyan-violet, and magenta — these are the aurora curtains. Together these two components form the background layer, fixed to the viewport and never scrolling. On the next plane up sits ConstellationNav, which renders navigation links as nodes connected by subtle lines, always visible regardless of the active route. Finally, the foreground plane holds the <Routes> tree; <AnimatePresence> unmounts the outgoing page and mounts the incoming one with a coordinated fade-and-blur transition.
Visual Components
AuroraBackground
Renders three Framer Motion
motion.div gradient layers (teal at 20 s, cyan-violet at 25 s, magenta at 30 s) plus an SVG wave with an animated d attribute. Fixed, full-viewport, z-0, opacity-60, and pointer-events-none. Responsible for all ambient color in the scene.StarField
A Canvas 2D full-screen renderer that populates stars at a density of one star per 4 000 pixels of viewport area. Each star twinkles (opacity oscillation) and drifts slowly upward. Shooting stars spawn at 0.5 % chance per frame up to a maximum of three concurrent trails. Reinitialises on
window resize.ConstellationNav
The persistent navigation component. Styled as a constellation — navigation destinations appear as nodes with connecting lines — and sits above the background layer so it is always reachable regardless of route.
PageTransition
A thin Framer Motion wrapper applied to every route element. Animates
opacity from 0 → 1 and filter: blur(10px) → blur(0) on enter; reverses on exit. Keyed by location.pathname so React unmounts and remounts it on every navigation.Single-Bundle Approach
The Vite build emits one primary JavaScript bundle —assets/main.js — that contains every page component (Home, About, Projects, Skills, Writing, CaseStudies, Contact), all three visual components, React Router configuration, and Framer Motion animation definitions. There is no route-level code splitting; the entire application is available immediately after the initial script load. This trades a larger initial parse cost for zero waterfall latency when navigating between pages.
The entry point index.html loads assets/main.js and mounts the React tree. Each of the seven route destinations also has its own static HTML shell under pages/ (for example pages/about.html); those shells exist solely to support direct URL access on static file hosts and are described in detail in the Routing guide.
How the Technologies Interact
App mounts
ReactDOM.render mounts the application from assets/main.js into the #root element in index.html. BrowserRouter wraps the entire tree, making useLocation and useNavigate available to all descendants.Background layer initialises
AuroraBackground renders its three motion.div gradient layers and begins their looping Framer Motion animations immediately. StarField obtains a 2D canvas context and starts the requestAnimationFrame render loop, sizing the canvas to window.innerWidth × window.innerHeight.Navigation renders
ConstellationNav renders once and stays mounted for the entire session. Because it is placed outside <AnimatePresence> it is never unmounted during route transitions.Route match and transition
React Router matches
location.pathname to a <Route>. <AnimatePresence mode="wait"> is keyed by location.pathname, so changing the path triggers an exit animation on the current PageTransition node, React unmounts it, then mounts and plays the enter animation for the new route’s PageTransition node.Framer Motion and the Canvas 2D API run on separate animation systems: Framer Motion uses its own internal RAF scheduler for
motion.div elements, while StarField manages its own requestAnimationFrame loop directly. They never share a clock, which keeps the canvas renderer decoupled from any Framer Motion pause or stagger logic.Technology Summary
| Technology | Role in the app |
|---|---|
| React 18 | Component model, legacy render API |
| Vite | Build toolchain, single-bundle output |
| React Router DOM v6 | BrowserRouter, Routes, Route, useLocation |
| Framer Motion | motion.div aurora layers, AnimatePresence, page transitions |
| Canvas 2D API | StarField star and shooting-star renderer |
| Tailwind CSS | Utility classes for layout, spacing, and typography |