Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/the-beach-mystery/llms.txt

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

The Beach Mystery is a fully static React application. It makes no API calls, reads no environment variables, and requires no server-side runtime. All story data, artwork, and game logic ship in a single vite build output. This makes deployment to GitHub Pages straightforward: build once, push the output, enable Pages in your repository settings, and the app is live. This guide walks through every step from forking the repository to serving a production URL.
1

Fork the repository

Visit apursley2012/the-beach-mystery on GitHub and click Fork. This creates a copy of the repository under your own account that you have full write access to, including the ability to enable GitHub Pages.
Give your fork a descriptive repository name — that name becomes the URL path segment on GitHub Pages (e.g. https://your-username.github.io/the-beach-mystery/), and you will need to match it in vite.config.js in a later step.
2

Clone locally and install dependencies

git clone https://github.com/your-username/the-beach-mystery.git
cd the-beach-mystery
npm install
The project uses Vite and React. No additional tooling is required beyond Node.js and a package manager.
3

Run the development server

npm run dev
Vite starts a local development server, typically at http://localhost:5173. Hot module replacement is enabled — edits to story nodes, scene images, or components appear in the browser immediately without a full reload.
4

Configure the base path

GitHub Pages serves repositories from a subdirectory path by default: https://your-username.github.io/the-beach-mystery/. Vite needs to know this prefix so it can write the correct paths into the built HTML for scripts, stylesheets, and asset URLs.Create vite.config.js in the project root and set the base option to match your repository name:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  base: '/the-beach-mystery/',   // set to '/' if deploying to a root domain
});
If you are deploying to a custom domain (e.g. https://mysite.com) and pointing DNS directly at GitHub Pages, set base: '/' instead. GitHub Pages will serve the app from the domain root and no prefix is needed.
5

Build for production

npm run build
Vite bundles the app into the dist/ directory. The output is a set of static files — one index.html, fingerprinted JavaScript and CSS chunks, and all PNG scene illustrations with hashed filenames. No server is needed to serve them.You can preview the production build locally before deploying:
npm run preview
This starts a local static file server that serves dist/ at http://localhost:4173, including the correct base path.
6

Deploy to GitHub Pages

GitHub Pages can serve static files from two sources: a dedicated gh-pages branch, or a GitHub Actions workflow. Either approach works.Option A — GitHub Actions (recommended)Create .github/workflows/deploy.yml:
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

permissions:
  contents: read
  pages: write
  id-token: write

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm install
      - run: npm run build
      - uses: actions/configure-pages@v4
      - uses: actions/upload-pages-artifact@v3
        with:
          path: dist
      - id: deployment
        uses: actions/deploy-pages@v4
Then go to Settings → Pages in your repository, set Source to GitHub Actions, and push to main. The workflow builds and deploys automatically on every push.Option B — gh-pages branchInstall the gh-pages helper package and add a deploy script to package.json:
{
  "scripts": {
    "deploy": "npm run build && gh-pages -d dist"
  }
}
Run npm run deploy. Then in Settings → Pages, set Source to Deploy from a branch and choose gh-pages / / (root).

HashRouter and Client-Side Routing

GitHub Pages is a static file host. When a visitor navigates directly to a URL like https://your-username.github.io/the-beach-mystery/play, the server looks for a file at that path, finds nothing, and returns a 404. This breaks any application that uses the HTML5 History API for routing. The Beach Mystery avoids this problem by using React Router’s HashRouter. All routes are encoded in the URL fragment — the part after # — which the browser never sends to the server:
HashRouter URLWhat the server sees
https://your-username.github.io/the-beach-mystery/#/play/the-beach-mystery/ — the index.html
https://your-username.github.io/the-beach-mystery/#/endings/the-beach-mystery/ — the index.html
https://your-username.github.io/the-beach-mystery/#/gallery/the-beach-mystery/ — the index.html
Every request resolves to index.html, React Router reads the fragment, and the correct page component mounts client-side. No server configuration, 404.html redirect tricks, or _redirects files are needed.
If you ever migrate to a host that supports server-side rewrites (Netlify, Vercel, Cloudflare Pages), you can switch to BrowserRouter and add a catch-all rewrite rule instead. For GitHub Pages, keep HashRouter.

Asset URL Resolution

Scene illustrations are referenced in data/sceneImages.js using the import.meta.url pattern:
const a = n => new URL(`../assets/story-art/${n}`, import.meta.url).href;
This is not a simple string concatenation — Vite statically analyses new URL(..., import.meta.url) calls during the build and treats them as asset imports. Each referenced PNG is:
  1. Copied into dist/assets/story-art/
  2. Given a content-hash suffix (e.g. beach-shore-a3f92b.png)
  3. Have its URL rewritten to the final hashed path, respecting the base option
This means the base setting in vite.config.js is the only configuration change needed for a subdirectory deployment. You do not need to manually prefix asset URLs, update HTML <link> tags, or maintain separate environment config files.
All story content — node text, choice labels, riddle text, ending descriptions, and personalization questions — is hardcoded in data/story.js. There are no external API calls, no CMS integrations, and no secret keys to manage. A fork of this repository deploys as-is without any .env configuration.

Troubleshooting

The most common cause is a missing or incorrect base in vite.config.js. Open DevTools, check the Network tab for 404s on .js or .css files, and compare the requested paths to your repository name. Update base to match the exact repository name including leading and trailing slashes, then rebuild and redeploy.
The PNG filenames in data/sceneImages.js do not match the files in assets/story-art/. Filenames are case-sensitive on Linux (the GitHub Actions runner). Ensure beach-shore.png in the map matches beach-shore.png on disk exactly — not Beach-Shore.png or beach_shore.png.
Check the Node.js version. The workflow above pins Node 20. If your local environment is different, the package-lock.json may have been generated with a different resolver. Commit a package-lock.json generated with the same Node version the workflow uses, or add a .nvmrc file and switch to node-version-file: '.nvmrc' in the workflow.

Build docs developers (and LLMs) love