Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/a-master-artificer/llms.txt

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

The CustomCursor component replaces the browser’s default pointer with a two-layer animated cursor that fits the grimoire visual identity. At rest it shows a small teal dot. When the pointer moves over any interactive element it morphs into a four-pointed star rendered as an inline SVG. A soft glow blob trails the cursor on a slower spring, giving the impression that the pointer is dragging a faint luminous wake behind it across the page. The component mounts at the React tree root and registers its own mousemove and mouseover listeners on window, so no props or configuration are required wherever it is placed.
CustomCursor is a purely desktop enhancement. On touch devices there is no mouse pointer, so the component’s DOM elements are never visible. The custom cursor does not interfere with touch navigation, tap targets, or mobile layout in any way.

How It Works

// No props needed — drop it anywhere near the root
<CustomCursor />
On mount, two useMotionValue instances track the raw mouse clientX and clientY co-ordinates (initialised off-screen at -100). Four useSpring values derived from those motion values drive the two rendered DOM layers with different physics configs, producing the fast-cursor / slow-glow separation.

Spring Physics Configs

The cursor uses two independent sets of spring parameters applied to the same underlying x / y motion values.

Fast Cursor Dot

Applied to the cursor dot layer (z-[9999]). Tracks the pointer with minimal lag, keeping the interactive feel snappy.
{
  damping:   25,
  stiffness: 300,
  mass:      0.5,
}

Slow Glow Trail

Applied to the glow blob layer (z-[9998]). Lags behind intentionally, creating the trailing luminous wake effect.
{
  damping:   40,
  stiffness: 150,
  mass:      1,
}
Higher stiffness and lower mass in the fast config make it snap to the pointer quickly. The glow config’s lower stiffness and higher mass cause it to ease in and overshoot slightly, producing the organic trailing motion.

Rendered Layers

The component renders two motion.div elements inside a React Fragment. Both are fixed top-0 left-0 and pointer-events-none so they never block clicks.

Layer 1 — Glow Blob (z-[9998])

fixed top-0 left-0
w-8 h-8
rounded-full
bg-grimoire-glow/20
blur-md
pointer-events-none
z-[9998]
Driven by the slow spring values. Translates −50% on both axes so the blur centre tracks the co-ordinates rather than the top-left corner.

Layer 2 — Cursor Dot (z-[9999])

fixed top-0 left-0
pointer-events-none
z-[9999]
flex items-center justify-center
Driven by the fast spring values. Contains a Framer Motion child div that switches between two shapes depending on hover state.

Cursor States

Default — Teal Dot

When the pointer is not over an interactive element:
w-2 h-2
rounded-full
bg-grimoire-glow
shadow-[0_0_8px_2px_rgba(45,212,191,0.6)]
A 8px circle with a soft teal glow shadow.

Hover — Four-Pointed Star

When the pointer enters an interactive element, the dot is replaced with an inline SVG star and the container scales up with a slight rotation:
<svg
  width="24"
  height="24"
  viewBox="0 0 24 24"
  fill="none"
  xmlns="http://www.w3.org/2000/svg"
  className="text-grimoire-glow drop-shadow-[0_0_5px_rgba(45,212,191,0.8)]"
>
  <path
    d="M12 2L14.5 9.5L22 12L14.5 14.5L12 22L9.5 14.5L2 12L9.5 9.5L12 2Z"
    fill="currentColor"
  />
</svg>
The parent motion.div animates to scale: 1.5 and rotate: 90° with a duration: 0.2 transition when hover is active, and returns to scale: 1, rotate: 0 when hover ends.

Hover Detection

The hover state is toggled by a mouseover listener that walks the DOM upward from the hovered target using Element.closest():
const selector = 'a, button, [role="button"], input, textarea, select';

window.addEventListener("mouseover", (e) => {
  e.target.closest(selector) ? setHover(true) : setHover(false);
});
Any element matching the selector — or any of its children — will trigger the star shape. This covers the AstrolabeNav links, form fields on the contact page, and any custom interactive elements that carry role="button".

Z-Index Layers

Layerz-indexDescription
Glow blob9998Blurred teal trail, driven by slow spring
Cursor dot / star9999Sharp foreground cursor, driven by fast spring
Both layers sit above the AstrolabeNav ring (z-50) and PageChrome header (z-10), ensuring the cursor is never obscured by UI chrome.

Accessibility

The cursor is purely decorative. It renders no text, conveys no information, and receives no focus. Keyboard navigation is completely unaffected — the component only listens to mousemove and mouseover, neither of which fires during keyboard or assistive-technology use. The SVG element has no title or aria-label, and both rendered layers carry pointer-events-none, so they cannot accidentally intercept click or focus events.

Build docs developers (and LLMs) love