Skip to main content

Documentation Index

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

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

SpiderScare delivers a one-shot jump-scare: the first time a visitor clicks anywhere on the page, a SpiderIcon rappels down from off-screen on a gossamer thread, lingers at mid-viewport, then retreats back into the shadows. Because the trigger is captured by hasClicked from HauntContext and persisted via sessionStorage, the spider fires exactly once per browser session — closing and reopening the tab resets it, but a full-page refresh within the same session does not.

Prerequisites

SpiderScare must be rendered inside a HauntProvider. It consumes three values from useHaunt():
ValueTypePurpose
isHauntedbooleanGuards the click listener entirely
hasClickedbooleanPrevents retriggering after the first click
registerClick()functionMarks the click in state and sessionStorage
It also requires Framer Motion for the motion.div and AnimatePresence.

Trigger logic

A click listener is attached to window on mount and torn down on unmount. The handler only acts when isHaunted is true and hasClicked is false:
useEffect(() => {
  const handler = () => {
    if (isHaunted && !hasClicked) {
      setVisible(true);
      registerClick();          // sets sessionStorage + state
      setTimeout(() => {
        setVisible(false);
      }, 4000);
    }
  };
  window.addEventListener('click', handler);
  return () => window.removeEventListener('click', handler);
}, [isHaunted, hasClicked, registerClick]);
registerClick() is called immediately so that any subsequent clicks during the 4-second display window are ignored.
registerClick() writes "true" to sessionStorage under the key haunt-clicked. The spider will fire again on a fresh browser session (new tab, or after the session storage is cleared), but not on a simple page refresh within the same session.

Animation

The spider is a motion.div wrapped in AnimatePresence. It enters from y: '-100vh' (entirely above the viewport) and plays a four-keyframe sequence that simulates swinging on a thread before retreating:
animate: {
  y: ['-100vh', '20vh', '20vh', '-100vh'],
  x: ['50vw', '45vw', '55vw', '50vw'],
},
transition: {
  duration: 4,
  times: [0, 0.4, 0.6, 1],
  ease: 'easeInOut',
}
Breaking down the timeline across the 4-second duration:
TimeyxWhat the user sees
0 s (t=0)-100vh50vwSpider hidden above viewport, centred
1.6 s (t=0.4)20vh45vwSpider drops to 20 % down, swings left
2.4 s (t=0.6)20vh55vwSpider hangs at 20 %, swings right
4 s (t=1)-100vh50vwSpider retreats back off-screen
Change '20vh' in both keyframe arrays to control how far the spider descends. For example, '50vh' brings it to the exact vertical centre of the viewport for maximum impact.

Visual structure

The motion.div uses flex flex-col items-center to stack two children vertically: Thread
<div className="w-px h-[100vh] bg-haunt-bone/30 -mt-[100vh]" />
A single-pixel-wide column 100 vh tall pulled upward with -mt-[100vh], creating the illusion of an infinitely long silk thread receding above the spider. Spider icon
<div className="text-haunt-dark bg-haunt-bg rounded-full p-1
                shadow-[0_0_15px_rgba(94,234,212,0.3)]">
  <SpiderIcon className="w-16 h-16 text-haunt-moon" />
</div>
The icon is 64 × 64 px (w-16 h-16) in the teal haunt-moon colour, set on a dark rounded background with a teal glow shadow (rgba(94,234,212,0.3)).

z-index and pointer events

The entire motion.div is fixed top-0 left-0 z-[9999] pointer-events-none, placing the spider above all other page content while ensuring it never captures mouse events or prevents clicks on the underlying page.

Build docs developers (and LLMs) love