Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/magical/llms.txt

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

Magical Portfolio is a fully client-side React SPA built with Vite. Running npm run build compiles the entire application — React components, Tailwind CSS, and the React Router runtime — into a self-contained dist/ folder of plain HTML, JavaScript, and CSS files. Because all navigation is handled in the browser via hash-based routing (#/), there is no server-side rendering required and no special server configuration needed. The output drops straight onto any static file host: GitHub Pages, Netlify, Vercel, an S3 bucket, or a plain nginx server.

Build steps

1

Install dependencies

If you haven’t already, install the project’s Node dependencies before running any build or dev commands:
npm install
This installs Vite, React, React Router, Tailwind CSS, and every other package listed in package.json into a local node_modules/ folder.
2

Run the production build

Compile and bundle the application for deployment:
npm run build
Vite performs tree-shaking, minification, and asset fingerprinting, then writes the complete output to dist/. A successful build prints the generated file sizes to your terminal.
3

Preview the build locally

Before uploading anything, spin up Vite’s built-in static preview server to make sure the production bundle behaves exactly as expected:
npm run preview
The preview server starts at http://localhost:4173. Click through every page — Home, About, Projects, Skills, Writing, Case Studies, Contact — and confirm the mystical animations, custom cursor, and sigil effects all load correctly.
4

Inspect the output

Take a look at what was generated:
ls dist/
You should see the full tree described below. Every file is static and self-contained — nothing in dist/ needs a Node.js runtime to serve.

Output structure

After a successful build, the dist/ directory contains the following files:
dist/
├── index.html           # Root entry — serves the / route
├── .nojekyll            # Prevents GitHub Pages Jekyll processing
├── canvas.manifest.js   # Vite asset manifest
├── useScreenInit.js     # React init module
├── assets/
│   ├── main.js          # Bundled React app
│   ├── main.css         # Compiled Tailwind CSS
│   └── proxy.js         # React + Router runtime
├── components/          # Pre-built component modules
│   ├── Navigation.js
│   ├── BackgroundEffects.js
│   ├── CustomCursor.js
│   └── Sigil.js
└── pages/               # Static HTML shims per route
    ├── About.html        # /about
    ├── Projects.html     # /projects
    ├── Skills.html       # /skills
    ├── Writing.html      # /writing
    ├── CaseStudies.html  # /case-studies
    ├── Contact.html      # /contact
    └── Home.html         # alternate / entry

How hash routing makes this work

Magical Portfolio uses hash-based routing: every client-side route is encoded as a URL fragment beginning with #/ (for example, #/about, #/projects). Because the fragment is never sent to the server, the server always delivers the same HTML file regardless of which page the visitor requested, and then React Router reads the hash to render the correct view. Each file in pages/ is a thin HTML shim that loads the React application and sets a window.__STATIC_PAGE_ROUTE__ hint. For example, pages/About.html contains:
<script>
  window.__STATIC_PAGE_ROUTE__ = "/about";

  (function () {
    if (!window.location.hash || window.location.hash === "#") {
      window.location.replace(
        window.location.pathname +
        window.location.search +
        "#/about"
      );
    }
  })();
</script>
When a visitor lands on /pages/About.html directly — say, from a search engine or a shared link — the inline script detects the missing hash and immediately redirects the browser to /pages/About.html#/about. React Router then picks up #/about and renders the About page. All routes converge on the same JS bundle; no separate server-side rendering is involved.
The .nojekyll file is required for GitHub Pages — and it’s already in the repository. By default, GitHub Pages runs every site through Jekyll, its static site generator. Jekyll intentionally ignores files and directories whose names begin with an underscore — which would silently strip _ prefixed assets if any existed. More critically for Magical Portfolio, Jekyll would attempt to re-process the HTML shims and may fail on Vite’s module-type <script> tags. The empty .nojekyll file already present in the repo root tells GitHub Pages to skip Jekyll processing entirely and serve the output as-is. You do not need to create it.
Environment variables must be prefixed with VITE_ to be included in the bundle. Vite statically replaces import.meta.env.VITE_* references at build time, so any variable you want accessible in client-side code — an API base URL, a public analytics key, etc. — must be named VITE_MY_VARIABLE in your .env file. Variables without the VITE_ prefix are intentionally excluded from the bundle to prevent secrets from leaking to the browser.
# .env.production
VITE_API_BASE_URL=https://api.example.com
VITE_ANALYTICS_ID=UA-XXXXXXX

Build docs developers (and LLMs) love