Skip to main content

Documentation Index

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

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

Choose Your Destiny is a single-page application built with React, delivered as a fully static bundle that runs on any file host — no server required. The repository you are reading contains the pre-built output — there is no src/ directory, no package.json, and no build step to run. The app combines React Router v6’s hash-based navigation with a set of pre-rendered HTML shell pages so that deep links work out of the box on platforms like GitHub Pages. Framer Motion drives all animations, and every piece of component state lives locally — there is no global store.

High-Level Architecture

The application has three layers that work together:
  1. Static HTML shells — one per route in index.html and /pages/, each setting window.__STATIC_PAGE_ROUTE__ and redirecting the browser to the correct #/ hash URL before loading assets/main.js.
  2. React SPA — a single compiled bundle that mounts on <div id="root"> and renders every page component via React Router.
  3. Canvas manifestcanvas.manifest.js provides a machine-readable map of routes and their canvas positions, consumed at runtime by useScreenInit.
Static Host (GitHub Pages / Netlify / Vercel)

├── index.html              ← Root shell (#/)
├── pages/
│   ├── Home.html           ← Duplicate root shell (also sets __STATIC_PAGE_ROUTE__ = "/")
│   ├── About.html          ← Shell for /about
│   ├── Projects.html       ← Shell for /projects
│   ├── Skills.html         ← Shell for /skills
│   ├── Writing.html        ← Shell for /writing
│   ├── CaseStudies.html    ← Shell for /case-studies
│   └── Contact.html        ← Shell for /contact
├── assets/
│   ├── main.js             ← Full React app bundle (React Router + Framer Motion)
│   ├── main.css            ← Custom neon styles + Tailwind utilities
│   ├── index.js            ← React + ReactDOM runtime
│   ├── jsx-runtime.js      ← JSX transform runtime
│   ├── UIComponents.js     ← Module preload copy of UIComponents
│   └── VisualEffects.js    ← Module preload copy of VisualEffects
├── components/
│   ├── UIComponents.js     ← NeonCard, NeonButton, TerminalLine, Cursor exports
│   └── VisualEffects.js    ← Background grid, scan-line, glitch effect exports
├── canvas.manifest.js      ← Route → canvas-position mapping (exports m)
├── useScreenInit.js        ← Hook: reads mp_screen param → initial route state (exports u)
└── .nojekyll               ← Prevents GitHub Pages from ignoring underscore-prefixed files
This is a pre-built static site. To make changes to content, styles, or routes you need the original source project. The files in this repository are the compiled output ready for deployment.

Component Hierarchy

The app root (Nm) wraps everything in HashRouter (th), mounts the redirect handler (Sm), and passes children through the shared layout wrapper (sm) before rendering the route tree:
Nm (App Root)
└── HashRouter (th)           ← React Router v6 hash-based router
    ├── Sm                    ← Redirect handler (reads canvas.manifest path)
    └── sm (Layout Shell)     ← Header, mobile menu, background effects
        └── Routes (Yp)
            ├── Route "/"              → cm  (Home)
            ├── Route "/about"         → fm  (About)
            ├── Route "/projects"      → hm  (Projects)
            ├── Route "/skills"        → gm  (Skills)
            ├── Route "/writing"       → xm  (Writing)
            ├── Route "/case-studies"  → wm  (Case Studies)
            └── Route "/contact"       → km  (Contact)
Each route component is a self-contained page that renders its own heading, content, and Framer Motion entrance animations. Shared UI primitives — NeonCard (Eu), NeonButton (Lu), TerminalLine (Fu), and Cursor (Bu) — are exported from components/UIComponents.js.

Key Dependencies

React Router v6 provides HashRouter, Routes, and Route components. The app uses HashRouter (aliased as th in the minified bundle) so that all navigation lives in the URL fragment — no server-side routing rules are needed. useNavigate drives programmatic navigation inside Sm.
Framer Motion (motion.div and AnimatePresence) handles entrance animations for every page, skill progress bars, and the case-study stage reveals. Elements animate with initial, animate, and exit props. The library is bundled into assets/main.js.
Tailwind utilities are compiled into assets/main.css. The font-arcade, font-terminal, and font-code utility classes map to Press Start 2P, VT323, and JetBrains Mono respectively. Custom neon glow classes (glow-cyan, glow-magenta, etc.) are defined alongside the Tailwind output.
Four font families are loaded via a single @import at the top of main.css:
  • Inter (400, 600, 800) — body text (font-sans)
  • JetBrains Mono (400, 700) — code snippets (font-code)
  • Press Start 2P — pixel arcade headings (font-arcade)
  • VT323 — terminal-style UI labels (font-terminal)

Deployed File Structure

The repository contains the fully self-contained static site ready for deployment. There is no separate build step — the files here are what get served directly:
choose-your-destiny/          ← Deploy this directory to your static host
├── index.html                ← Entry point loaded at the repo's root URL
├── .nojekyll                 ← Required for GitHub Pages
├── pages/
│   └── *.html                ← Static route shells
├── assets/
│   ├── main.js               ← React app + React Router + Framer Motion
│   ├── main.css              ← Neon CSS styles + Tailwind utilities
│   ├── index.js              ← React + ReactDOM
│   ├── jsx-runtime.js        ← JSX transform
│   ├── UIComponents.js       ← Preload copy
│   └── VisualEffects.js      ← Preload copy
├── components/
│   ├── UIComponents.js
│   └── VisualEffects.js
├── canvas.manifest.js
└── useScreenInit.js
index.html uses <link rel="modulepreload"> tags for assets/index.js, assets/jsx-runtime.js, components/VisualEffects.js, components/UIComponents.js, canvas.manifest.js, and useScreenInit.js, so the browser can prefetch them in parallel with assets/main.js.

State Management

Choose Your Destiny uses local component state only — there is no Redux, Zustand, Jotai, or any other global store. Each page component manages exactly what it needs:
Two useState calls control the form:
// Field values
const [fields, setFields] = useState({ name: "", email: "", message: "" });

// Submission lifecycle
const [status, setStatus] = useState("idle"); // "idle" | "submitting" | "success"
On submit, status moves to "submitting" for 1 500 ms (simulated delay), then to "success", then resets to "idle" after 3 000 ms.

The canvas.manifest.js Routing Manifest

canvas.manifest.js exports a manifest object as m that maps internal screen IDs to route paths and canvas positions. It is used by useScreenInit to look up the initial route state when the app is launched from a specific canvas screen via the ?mp_screen= query parameter. The actual minified source is:
// canvas.manifest.js (minified — exports variable t as m)
const t = {
  screens: {
    scr_4sn1by: { name: "Home",         route: "/", state: { path: "/" },             position: { x: 160,  y: 220  } },
    scr_19km4h: { name: "About",        route: "/", state: { path: "/about" },        position: { x: 160,  y: 2200 } },
    scr_0bnpxq: { name: "Projects",     route: "/", state: { path: "/projects" },     position: { x: 160,  y: 4180 } },
    scr_80kfn3: { name: "Skills",       route: "/", state: { path: "/skills" },       position: { x: 1560, y: 2200 } },
    scr_kzf9pd: { name: "Writing",      route: "/", state: { path: "/writing" },      position: { x: 160,  y: 6160 } },
    scr_8bs0at: { name: "Case Studies", route: "/", state: { path: "/case-studies" }, position: { x: 1560, y: 4180 } },
    scr_8lc2o4: { name: "Contact",      route: "/", state: { path: "/contact" },      position: { x: 160,  y: 8140 } },
  }
};
export { t as m };
Each screen entry contains:
  • name — human-readable label
  • route — always "/" (the hash router handles actual routing client-side)
  • state.path — the React Router path that useScreenInit passes to useNavigate
  • positionx/y canvas coordinates used by design-tool canvas integrations

The useScreenInit Hook

useScreenInit reads the ?mp_screen= query parameter on first render, looks up the matching screen in the manifest, and returns the screen’s state object (which contains the path to navigate to). The value is memoized with useMemo so it never re-runs after mount. The hook is exported as u in the minified bundle. The actual source of useScreenInit.js is:
// useScreenInit.js (minified — imports React as s, manifest as o, exports function c as u)
import { r as s } from "./assets/index.js";
import { m as o } from "./canvas.manifest.js";

function c() {
  return s.useMemo(() => {
    if (typeof window === "undefined") return {};
    const e = new URLSearchParams(window.location.search).get("mp_screen");
    return e
      ? o?.screens?.[e]?.state ?? {}
      : {};
  }, []);
}

export { c as u };
The Sm redirect component calls useScreenInit on mount and uses React Router’s useNavigate to push the resolved path into the history stack, landing the user on the correct page without a full reload.

Build docs developers (and LLMs) love