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.
CursorTrail is a purely cosmetic overlay that follows the user’s pointer across the viewport. It paints a teal circle directly under the cursor and leaves behind a dissolving procession of up to five GhostIcon sprites, giving the site a spectral feel without ever interrupting interaction. The component is self-contained: it reads mouse coordinates and the haunted flag from HauntContext, manages its own trail state, and renders nothing on touch devices or when Haunted Mode is off.
Prerequisites
CursorTrail must be rendered inside a HauntProvider so the useHaunt() hook can resolve. It also depends on Framer Motion (AnimatePresence, motion.div) for the ghost fade-out animation.
Rendering conditions
The component performs two checks before rendering anything:| Condition | How it is checked |
|---|---|
| Not a touch device | 'ontouchstart' in window || navigator.maxTouchPoints > 0 detects a touch device — the component renders only when this expression is false |
| Haunted Mode on | isHaunted === true (from useHaunt()) |
null — no DOM nodes are mounted at all.
Visual structure
When both conditions pass, two layers are rendered: 1 — Cursor dot A fixed16 × 16 px circle (w-4 h-4) styled with bg-haunt-moon rounded-full mix-blend-screen. It is repositioned on every mousemove via an inline transform: translate(...), offset by −8 px on each axis so the dot is centred on the pointer hotspot.
mix-blend-mode: screen (the mix-blend-screen Tailwind utility) means the teal dot adds its luminance to whatever is beneath it rather than covering it, producing a natural glow on dark backgrounds. On light backgrounds the effect will be barely visible.GhostIcon in the trail is wrapped in a Framer Motion motion.div inside AnimatePresence. The icon animates from nearly opaque (opacity: 0.8, scale: 1) to fully transparent and slightly smaller (opacity: 0, scale: 0.5), rising 20 px upward over 500 ms.
State management
The trail is held in a singleuseState array. Each entry is a plain object { id, x, y } where id is a Date.now() timestamp used as the React key and for later removal.
prev.slice(-4) keeps at most the four most-recent entries before appending the new one, capping the total trail length at 5 ghosts. The setTimeout schedules removal of each individual item after 500 ms, ensuring ghosts disappear even if the cursor stops moving.
z-index layering
| Layer | z-index | Purpose |
|---|---|---|
| Cursor dot | 9999 | Always on top |
| Ghost trail icons | 9998 | Just below the cursor dot |
pointer-events-none so they never block clicks on the underlying page.