Skip to main content

Documentation Index

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

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

The Foyer is the first thing visitors encounter when they arrive at Mystery Haunting. It sets the tone immediately: a darkened viewport dominated by a haunted house silhouette, a pulsing ghost-teal orb, and a welcome message that materializes one letter at a time. The page exists to make an impression before anything else — it is atmosphere first, portfolio second. A single call-to-action button invites the visitor deeper into the experience.

Visual Overview

The background is anchored by a full-width haunted house silhouette rendered as an SVG, positioned at the bottom of the viewport with jagged rooflines and darkened windows. Overlaid on the scene is a large ghost-teal glowing orb — a radial gradient that pulses softly and casts an eerie ambient light across the silhouette below. Scattered across the screen are floating ghost icons, each drifting upward on an independent looping animation path. The ghosts use the animate-float-ghost Tailwind utility class, which applies a keyframe sequence cycling through vertical translation and subtle opacity shifts to give each ghost its own weightless, wandering feel. At the center of the viewport, the welcome text renders in two lines:
  • Primary title: WELCOME, MORTAL — displayed in a large display font, each character animated independently
  • Subtitle: Full-Stack Developer & Digital Poltergeist — fades in beneath the title after the letter sequence completes

Animation Details

The title animation is driven by Framer Motion. The string 'WELCOME, MORTAL' is split into individual characters, and each character is wrapped in a motion.span. Every span receives a spring-based entrance animation with a staggered delay based on its index position.
PropertyValue
Animation typeSpring (type: 'spring')
Stiffness100
Delay per letterindex * 0.1s
Initial stateopacity: 0, y: 40
Animate stateopacity: 1, y: 0
The ghost icons use a separate CSS-based loop animation via the animate-float-ghost class. Each ghost starts at a different vertical offset and cycles through a continuous upward drift, resetting when it exits the top of the frame.

CTA Button

Below the subtitle sits the ENTER IF YOU DARE button. It is styled with a pumpkin-colored border, transparent background, and spaced uppercase lettering. On hover, the background fills with a ghost-teal tint and the border shifts to match, giving it a “charging up” feel before the user clicks. Clicking the button navigates to the /about route using a React Router <Link> component.
<Link to="/about">
  <button className="border border-pumpkin px-8 py-3 uppercase tracking-widest hover:bg-ghost-teal/20 hover:border-ghost-teal transition-all duration-300">
    ENTER IF YOU DARE
  </button>
</Link>

Customization

The title is split into individual characters at render time using JavaScript’s .split('') method. To change the welcome message, update the string passed to .split(). Each resulting character becomes its own animated motion.span, so the stagger animation applies automatically regardless of message length.
const letters = 'WELCOME, MORTAL'.split('');
// Each letter rendered as animated span

{letters.map((letter, index) => (
  <motion.span
    key={index}
    initial={{ opacity: 0, y: 40 }}
    animate={{ opacity: 1, y: 0 }}
    transition={{
      type: 'spring',
      stiffness: 100,
      delay: index * 0.1
    }}
  >
    {letter === ' ' ? '\u00A0' : letter}
  </motion.span>
))}
Spaces in the string are preserved as non-breaking spaces (\u00A0) so the layout does not collapse mid-animation.
The button uses a React Router <Link> component. Update the to prop to point to any route in the application.
// Current destination — leads to the About/Attic page
<Link to="/about">
  <button>ENTER IF YOU DARE</button>
</Link>

// Example: send visitors directly to the Projects page instead
<Link to="/projects">
  <button>ENTER IF YOU DARE</button>
</Link>
The button label itself is plain text inside the <button> element — update it to any string to match the new destination.

Build docs developers (and LLMs) love