Choose Your Destiny solves one of the classic problems of single-page apps on static hosts: making every URL work on a direct browser visit without a server that can rewrite paths toDocumentation 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.
index.html. The solution is a combination of React Router’s HashRouter — which puts all navigation in the URL fragment after # — and a set of pre-built static HTML shells in the /pages/ directory, each of which bootstraps the React app at the correct route automatically.
Why Hash Routing?
StandardBrowserRouter requires a web server configured to return index.html for every unknown path. On a static host (GitHub Pages, Netlify free tier with no redirect rules, S3), a request to /projects will return a 404 because there is no file at that path.
HashRouter sidesteps this entirely. The full URL looks like:
/choose-your-destiny/ to the server. Everything after # is handled entirely in the browser by React Router. No server configuration is ever needed.
How Each Static Page Shell Works
The/pages/ directory contains one HTML file per route. When a user navigates directly to, for example, https://username.github.io/choose-your-destiny/pages/About.html, the shell:
- Sets
window.__STATIC_PAGE_ROUTE__to the intended route path. - Checks whether the URL already has a hash fragment.
- If there is no hash (or it is just
#), it replaces the current URL to append the route’s hash — redirecting the browser to load the React app at the right place.
pages/About.html:
| File | __STATIC_PAGE_ROUTE__ | Hash fragment |
|---|---|---|
index.html | / | #/ |
pages/Home.html | / | #/ |
pages/About.html | /about | #/about |
pages/Projects.html | /projects | #/projects |
pages/Skills.html | /skills | #/skills |
pages/Writing.html | /writing | #/writing |
pages/CaseStudies.html | /case-studies | #/case-studies |
pages/Contact.html | /contact | #/contact |
canvas.manifest.js mirrors this same route table in a machine-readable format. It is consumed by useScreenInit to resolve the ?mp_screen= query parameter to a route path when the app is launched from a design-tool canvas. The manifest and the static shells must stay in sync — if you add a route, add a corresponding entry to both.React Router Route Definitions
All seven routes are registered inside theNm app root. The Sm redirect component runs first (reading the canvas manifest), followed by the sm layout shell which wraps the Routes tree:
| Path | Component alias | Section |
|---|---|---|
/ | cm | Home |
/about | fm | About |
/projects | hm | Projects |
/skills | gm | Skills |
/writing | xm | Writing |
/case-studies | wm | Case Studies |
/contact | km | Contact |
The Sm Redirect Component
Sm is a headless component that runs one side effect on mount. It calls useScreenInit to get an initial path from the canvas manifest (via the ?mp_screen= query param) and, if the path is not /, it calls React Router’s useNavigate to navigate there with replace: true so no extra history entry is created.
?mp_screen= param is present, useScreenInit returns {} and Sm does nothing.
Adding a New Route
Create the page component in source
Add your new page component in the React source project. It should follow the same pattern as the existing pages — a
div with min-h-screen, a PageHeader with a matching neon color prop, and your content wrapped in NeonCard components.Register the route in the app root
Import your component and add a
<Route> inside the Routes block in the Nm app root:Add the route to canvas.manifest.js
Add a new entry to the The
screens object. Pick a unique ID in the same format as the existing ones:position values only matter if you are using the manifest inside a canvas-based design tool. Set them to any unused coordinate.Add the link to the navigation
Include the route in the nav-links array in the app source so it appears in the header navigation and mobile menu: