v1.0.0-beta

iPad Cursor for Web

A physics-based cursor engine that faithfully recreates the iPadOS interaction model. Zero-config magnetic snapping, auto-radius detection, and scroll-aware tracking.

View Source

Interactive Playground

Button Variants

The cursor adapts to the shape and size of interactive elements.

Smart Text Handling

Vertical bar cursor matches line-height and font-size automatically.

Display Heading

Section Title

This is a standard paragraph showing how the cursor flows over body text. It morphs into a thin vertical bar that aids in text selection and readability.

How It Works

Motion Spring Physics

The cursor core is built on Motion (formerly Framer Motion). We use independent useSpring hooks for X/Y coordinates, width, height, and radius. This ensures that every state transition—whether entering a button or moving between text lines—is interpolated with fluid, organic momentum (stiffness: 300, damping: 25) rather than linear tweening.

Reconciliation Loop

To handle scroll-aware hit testing without performance overhead, we run a single requestAnimationFrame loop. This loop constantly polls document.elementFromPoint to determine the active target, bypassing the need for thousands of onMouseEnter listeners. This decouples the physics engine from React's render cycle, ensuring 60fps performance even on complex pages.

Magnetic Projection

The magnetic effect isn't just a CSS transform. We calculate the delta between the mouse pointer and the element's center, then apply a clamped spring force. We directly manipulate the DOM element's transform: translate3d(...) property inside the physics frame, allowing the button to "pull" towards the cursor up to a defined limit (e.g., 40% of its size) before breaking free.

ExampleUsage.tsx
import { CursorTarget } from "@ipad-cursor/react";

export function MyComponent() {
  return (
    <div className="flex gap-4">
      {/* Interactive Button (Block Cursor) */}
      <CursorTarget>
        <button className="btn-primary">
          Submit Form
        </button>
      </CursorTarget>

      {/* Text Content (Bar Cursor) */}
      <CursorTarget type="text">
        <h1>Welcome to the future</h1>
      </CursorTarget>
    </div>
  );
}