Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/sorcerer/llms.txt

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

CursorTrail swaps the browser’s default pointer for a hand-crafted cat silhouette that floats across the screen, softly lagging behind the real cursor position. The effect is achieved with a requestAnimationFrame loop and linear interpolation, giving the cat a dreamy, weightless quality that suits the portfolio’s mystical atmosphere. The component is mounted once inside Layout and runs continuously for the lifetime of the page.

The Cat Cursor

The cursor is a 64×64px <div> rendered at position: fixed, pointer-events-none, and z-50. Inside it sits a hand-drawn SVG cat composed of five distinct shapes:
ShapeSVG ElementDescription
Body<path d="M30 80 Q30 50 50 50 Q70 50 70 80 Z">A rounded, slightly tapered torso shape using quadratic Bézier curves.
Head<circle cx="50" cy="45" r="15">A circular head centred above the body.
Left ear<polygon points="38,35 42,20 48,32">A small triangular ear on the left side.
Right ear<polygon points="62,35 58,20 52,32">A mirrored triangular ear on the right side.
Left eye<circle cx="45" cy="43" r="2" fill="#2dd4bf">A turquoise dot eye.
Right eye<circle cx="55" cy="43" r="2" fill="#2dd4bf">A mirrored turquoise dot eye.
Tail<path d="M70 75 Q90 75 85 55">A single Bézier curve sweeping up from the base of the body.
The eyes use Tailwind’s teal-400 equivalent — hex #2dd4bf — as a direct fill attribute, anchoring the cat to the same turquoise accent color used for the candle flame throughout the portfolio.
<svg width="64" height="64" viewBox="0 0 100 100" fill="currentColor">
  {/* Body */}
  <path d="M30 80 Q30 50 50 50 Q70 50 70 80 Z" />

  {/* Head */}
  <circle cx="50" cy="45" r="15" />

  {/* Ears */}
  <polygon points="38,35 42,20 48,32" />
  <polygon points="62,35 58,20 52,32" />

  {/* Eyes — turquoise accent */}
  <circle cx="45" cy="43" r="2" fill="#2dd4bf" />
  <circle cx="55" cy="43" r="2" fill="#2dd4bf" />

  {/* Tail */}
  <path d="M70 75 Q90 75 85 55" fill="none" stroke="currentColor" strokeWidth="4" />
</svg>

Smooth Following

Rather than snapping the cat element directly to the mouse coordinates, CursorTrail maintains a separate position object that is updated each animation frame using linear interpolation (lerp):
// Called every frame via requestAnimationFrame
position.x += (target.x - position.x) * 0.05;
position.y += (target.y - position.y) * 0.05;
Each frame, the displayed position moves 5 % of the remaining distance toward the real cursor. This means the cat accelerates quickly when the cursor moves far and decelerates gracefully as it approaches the target — producing the characteristic “floating” easing without any external animation library. The loop runs via requestAnimationFrame, so it is tied to the display’s refresh rate and automatically pauses when the tab is hidden.

Directional Flip

To give the cat a sense of physical direction, the SVG is flipped horizontally whenever the cursor is moving to the left. The component compares target.x to position.x each frame:
// If the mouse is to the left of the cat's current position, mirror the SVG
const facingLeft = target.x < position.x;
catElement.style.transform = facingLeft ? 'scaleX(-1)' : 'scaleX(1)';
scaleX(-1) is a pure CSS transform applied inline, so no additional class toggling or re-render is required. The tail and ear asymmetry make the directional flip clearly visible to users.

Hidden Native Cursor

The browser’s built-in cursor is hidden globally so that only the cat SVG is visible:
/* assets/main.css */
body {
  cursor: none;
}
This rule is applied in assets/main.css and affects the entire document. The pointer-events-none flag on the cat <div> ensures the custom cursor itself does not interfere with hover states or click targets on underlying elements.

Disabling the Cursor Trail

If you need to remove the custom cursor — for accessibility reasons, reduced-motion preferences, or a different aesthetic — follow these two steps:
1

Remove CursorTrail from Layout.js

Open components/Layout.js and delete the <CursorTrail /> line:
// Before
<CursorTrail />
<MoonPhaseNav />

// After
<MoonPhaseNav />
You can also remove the import statement at the top of the file:
// Remove this line
import CursorTrail from './CursorTrail';
2

Restore the native cursor in CSS

Open assets/main.css and remove or override the cursor: none declaration on the body selector:
/* Before */
body {
  cursor: none;
}

/* After — remove the rule entirely, or set a specific cursor */
body {
  cursor: auto;
}
Without this step, the browser cursor will remain invisible even after the component is removed.

Build docs developers (and LLMs) love