# Cursor Puck

A weighted puck on a short spring, under the pointer. It never sits where the pointer is: it lags behind, then catches up, with a coiled spring, not a dotted line, showing the stretch and compression.

Object · With a Pass · https://tactileui.dev/objects/cursor-puck

> The code and styling for this object come with the Pass. Sign in if you have one. Sign in: https://tactileui.dev/auth/sign-in The price: https://tactileui.dev/pricing

## Use it

With a Pass, install it with npx shadcn add @tactile/cursor-puck (https://tactileui.dev/docs/registry-and-mcp). It lands in tactile/cursor-puck/.

Load the stylesheet as well as the module, or it renders unstyled: tactile/cursor-puck/cursor-puck.css. In a bundler such as Vite, import each CSS file next to the module import; in plain HTML, link it.

Then new CursorPuck(element, options) from tactile/cursor-puck/cursor-puck.mjs. Every option has a default; tactile/cursor-puck-example.html shows it running. The sample copy (headings, labels, figures) is placeholder: replace it with the page's own.

## Anatomy

Mass spring damper, Fixed substep integration, Pointer or keyboard target, Rest position recentre, Sleeping loop, Reduced motion snap

## Usage notes

Give a hero, a cursor trail or a playful corner of a page a pointer that behaves like it has real weight on the end of a leash: a disc on a 2D mass-spring-damper, tied to wherever the pointer is, that lags when the pointer moves fast and settles once it stops. A coiled spring between the pointer's own mark and the puck makes the stretch and compression visible rather than implied, and the puck itself is turned, with lathe rings, a knurled rim and a cast shadow, so it reads as a real weight, not a flat disc. The same free end is reachable from the keyboard, so the lag is never pointer-only.

## Options

| Option | Type | Description |
| - | - | - |
| size | number | The diameter of the weighted disc. |
| stiffness | number | How quickly the spring pulls the puck toward the pointer. Low is a slow, heavy puck; high is quick and light. |
| damping | number | Below 1 the puck overshoots and swings before it settles; 1 catches up with no overshoot; above 1 is slow and heavy. |
| tether | boolean | A coiled spring drawn between the pointer's own mark and the puck, so its stretch and compression are visible, not a dotted line. |
| label | text | Read by a screen reader before the keyboard instructions. Empty uses the default. |

## Methods

- update
- state
- stats
- destroy

## States

1. **At rest**: The puck sits still at the centre of its stage; the loop is asleep and costs nothing.
2. **Following the pointer**: The pointer's own mark jumps to the cursor at once; the puck is pulled toward it by the spring and lags behind, closing the gap as the pointer slows or stops. How quickly it catches up and whether it overshoots on the way are both controls.
3. **Pointer leaves**: The free end returns to the stage's centre; the puck catches up there over the same spring, and the loop sleeps once it is still.
4. **Keyboard**: The stage takes focus.
5. **Off screen or hidden tab**: The loop stops requesting frames; a returning tab cannot fling the spring with a long frame, because the frame gap is clamped before it is sub-stepped.
6. **Reduced motion**: The puck sits on the free end at every change; nothing is stepped and no frame is requested.

## How it works

Original. No colour of its own.
