Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/the-craft/llms.txt
Use this file to discover all available pages before exploring further.
CursorTrail is a purely decorative React component that makes the mouse cursor feel like it’s trailing magical sparks across the grimoire. As the user moves their pointer, small teal glowing orbs materialize at the cursor’s position, drift downward with a gentle float, and fade out over about 600ms. The effect is subtle enough to stay out of the way of content while being vivid enough to reinforce the enchanted atmosphere of The Craft on every page.
How It Works
CursorTrail manages an array of particle objects in React state. Each particle carries an id, a position (x, y), and a randomly chosen size between 2px and 6px.
Listening for mouse movement
On mount,
CursorTrail attaches a mousemove listener to window. The handler is throttled so a new particle is only added when at least 30ms have elapsed since the last one — preventing hundreds of particles on fast mouse sweeps. Each valid event pushes a new particle object onto state, keeping only the most recent 15 particles in the array at any time (slice(-15)).Auto-expiring particles
A second
useEffect watches the particles array. Whenever particles exist, it schedules a setTimeout for 400ms that removes the oldest particle from the front of the array via slice(1). This creates a rolling FIFO queue: new sparkles appear at the cursor while old ones are continuously pruned from the tail.Animating with Framer Motion
Each particle is rendered as a
motion.div inside a Framer Motion AnimatePresence block. Particles enter with opacity: 0.8, scale: 1 at their spawn coordinates (x and y set via the initial prop), then animate to opacity: 0, scale: 0 while drifting 40px downward and up to ±20px horizontally — simulating the natural scatter of magical sparks. The animation runs for 0.6s with an easeOut curve.Visual Appearance
Each spark is arounded-full motion.div with:
- Color:
bg-spell— the teal accent color from the Tailwind theme. - Glow:
shadow-[0_0_8px_2px_rgba(45,212,191,0.6)]— a soft teal radial glow that halos each orb. - Size: Random, between 2px and 6px wide and tall, for a natural variation in sparkle intensity.
- Position: Absolute, offset by half its own size (
left: -size/2, top: -size/2) so the spark’s center aligns with the cursor’s hotspot.
Placement in the Component Tree
CursorTrail is rendered directly inside Layout.js, after the ambient blur blobs and before the MoonPhaseNav and <main> elements. Its root container is:
z-[9999] stacking context places the trail above all page content, navigation, and modals, so sparks always appear visually on top. The pointer-events-none class on the container ensures that every click, hover, and drag passes through to the interactive elements below — the trail is purely cosmetic.
Usage
BecauseCursorTrail self-attaches its own event listeners, no props or configuration are required. Simply render it once in your layout:
CursorTrail should be rendered once at the layout level, not inside individual pages. Rendering it multiple times would register duplicate mousemove listeners and spawn overlapping particles.Performance
CursorTrail is designed to stay lightweight:
- The 30ms throttle on the
mousemovehandler caps particle creation at roughly 33 particles per second, regardless of how fast the mouse moves. - The 15-particle cap (
slice(-15)) puts a hard ceiling on the number of DOM nodes in the animation layer at any given time. - Particles are automatically removed after 400ms, so the DOM never accumulates stale nodes during long idle periods.
- Framer Motion’s
AnimatePresencehandles exit animations without keeping invisible elements in the DOM.
Accessibility & Disabling
The cursor trail has no semantic meaning and does not affect focus, tab order, keyboard navigation, or screen readers. Itspointer-events-none container means it never intercepts ARIA interactions.