Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/blairxu13/persona3-website/llms.txt

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

The portfolio is a single-page application where every screen is a discrete route rendered by React Router v7. Navigation happens through the Persona 3-style menu UI as well as the keyboard, and Framer Motion’s AnimatePresence listens for route changes so it can play cinematic transition animations between pages without any visible flicker or unmounted-component artifacts.

Provider hierarchy

BrowserRouter is mounted once in main.jsx, wrapping the entire React tree so that every component in the app can call hooks like useLocation and useNavigate freely.
// src/main.jsx
import { BrowserRouter } from 'react-router-dom'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>,
)
App renders <AnimatedRoutes />, which is the only place that reads the current location and maps it to page components.

AnimatedRoutes and AnimatePresence

AnimatedRoutes uses useLocation() to capture the live location object and passes it down to both <Routes> and <AnimatePresence> as a stable key.
// src/App.jsx
import { Routes, Route, useLocation, useNavigate } from 'react-router-dom'
import { AnimatePresence } from 'framer-motion'

function AnimatedRoutes() {
  const location = useLocation()
  return (
    <AnimatePresence mode="wait">
      <Routes location={location} key={location.pathname}>
        <Route path="/"        element={<PageTransition><MenuScreen /></PageTransition>} />
        <Route path="/about"   element={<PageTransition variant="about"><AboutMe /></PageTransition>} />
        <Route path="/resume"  element={<PageTransition><ResumePage src={main2} /></PageTransition>} />
        <Route path="/socials" element={<PageTransition variant="socials"><Socials /></PageTransition>} />
      </Routes>
    </AnimatePresence>
  )
}
The key={location.pathname} prop on <Routes> is essential. Without it, React treats the same component tree as a simple update rather than an unmount-remount cycle, so AnimatePresence never fires the exit animations. Changing the key whenever the pathname changes forces React to unmount the old route tree and mount the new one — which is exactly what AnimatePresence needs to detect in order to orchestrate enter and exit sequences.

Route table

Each route is wrapped in a <PageTransition> that receives an optional variant prop controlling the cinematic wipe style. Routes that omit variant fall back to the default three-panel sweep.
PathPage componentPageTransition variant
/MenuScreen"default"
/aboutAboutMe"about"
/resumeResumePage"default"
/socialsSocials"socials"

Programmatic navigation

The root menu screen renders <P3Menu> and passes it an onNavigate callback. When the user selects an item — either by pressing Enter on the keyboard or clicking a menu row — the callback fires useNavigate to push the target path onto the history stack.
function MenuScreen() {
  const navigate = useNavigate()
  return (
    <div id="menu-screen">
      <video src={menuVideo} autoPlay loop muted playsInline />
      <P3Menu onNavigate={(page) => navigate(`/${page}`)} />
    </div>
  )
}
P3Menu exposes onNavigate as a prop so the component itself stays decoupled from routing — it only knows about abstract page identifiers like "about" or "socials", not full URL paths.

Keyboard navigation per page

Every page registers its own keydown handler via useEffect so that the interactive elements feel like a real JRPG menu system. Handlers are cleaned up when the component unmounts.
PageKeyAction
Menu (/) / Move selection up or down through menu items
Menu (/)EnterNavigate to the selected page
About Me (/about) / Move selection between character cards
About Me (/about)Enter or Reveal the detail panel for the active card
About Me (/about)Collapse the detail panel (or go back if already collapsed)
About Me (/about)Escape / BackspaceNavigate back (navigate(-1))
Resume (/resume) / Move selection between resume sections
Resume (/resume) or Escape / BackspaceNavigate back
Socials (/socials) — left panel / Move between social platform items
Socials (/socials) — left panelEnterOpen the platform link in a new tab
Socials (/socials) — left panelSwitch focus to the right info-bar panel
Socials (/socials) — left panelNavigate back (navigate(-1))
Socials (/socials) — right panel / Move between content bars
Socials (/socials) — right panelEnterOpen the selected bar’s link in a new tab
Socials (/socials) — right panelSwitch focus back to the left panel
Socials (/socials) — anyEscape / BackspaceNavigate back
The Socials page tracks focus state as a "left" / "right" string so the same key events produce different actions depending on which panel is currently active.

Build docs developers (and LLMs) love