Each frame, measure the distance between the button's center and the cursor. Inside a radius, nudge the button toward the cursor with `transform: translate()` — closer means more pull, and it springs back once the cursor leaves the radius.
Moving the inner label a bit further than the button itself (say 40% for the button, 18% for the text) creates a layered, parallax feel. Keep the transition short (0.1–0.2s) so it reads as instant, finger-like response.
Set the radius and max offset too generously and the button starts jumping around distractingly. A radius of 1.5–2x the button size and a max offset of 30–40% of it is a safe range.
When to use
Reserve it for one or two focal CTAs — a hero action, a "click here" moment. Apply it to every button in a list and it becomes fatiguing.