Physics Buttons
v1.1.0A suite of four physics-driven action buttons — gooey magnetic (slime), elastic bezier, jelly, and impact — built on GSAP spring physics with style presets and deep prop customization.
Installation
npx vectorvesper add physics-buttonsRun npx vectorvesper init once first to set up your project.
Dependencies
npm install gsap @gsap/react- gsap
- @gsap/react
Also requires tailwindcss to be configured in your project.
Usage
Import
Usage
Client-only component — disable SSR
This component requires browser APIs and must be rendered client-side only.
Props
A suite of four GSAP spring-physics action buttons — SlimeButton (gooey magnetic), ElasticButton (bezier stretch), JellyButton (rounded-rect ripple), and ImpactButton (fall, shatter & rejoin). Each ships style presets via the variant prop and exposes deep prop overrides. Import any subset from @/components/vv/physics-buttons.
Shared Props
Common to all exported components in this suite.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | React.ReactNode | — | Button label or content. |
buttonColor | string | — (per preset) | Primary fill color. Falls back to the active variant's preset color. |
clickColor | string | "#FFFFFF" | Color flashed on click, then eased back to buttonColor. |
onClick | () => void | — | Click handler. |
disabled | boolean | false | Disable interaction (no animation, dimmed, not activatable). |
type | "button" | "submit" | "reset" | "button" | Native button type — each component renders a real <button>. |
aria-label | string | — | Accessible label, useful when children are icon-only. |
className | string | "" | Extra CSS classes. |
style | React.CSSProperties | {} | Inline style overrides. |
<SlimeButton />
Gooey magnetic button: a fluid body with droplets that attract the cursor and splash on click.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "slime" | "orbit" | "square" | "slime" | Style preset (see below). |
range | number | 150 | Proximity in px within which the button attracts the cursor. |
strength | number | 0.3 | Multiplier for body translation toward the cursor. |
particleColor | string | = buttonColor | Color of the gooey droplets. |
particleCount | number | — (per preset) | Number of fluid droplets. |
gravity | number | — (per preset) | Downward acceleration on droplets while active. |
haloSpeed | number | — (per preset) | Idle orbit rotation speed (used by the `orbit` preset). |
borderRadius | string | "9999px" | Body corner radius (`square` preset uses `16px`). |
minWidth | string | "160px" | Minimum body width (CSS length). |
height | string | "56px" | Body height (CSS length). |
releaseTimeSec | number | 2.0 | Delay before droplets snap back after the cursor leaves. |
recoilIntensity | number | 0.22 | Vertical wobble on release (splash recoil). |
stdDeviation | number | 8.5 | Gaussian blur for the gooey filter (lower = crisper). |
squishIntensity | number | -0.35 | Vertical squish impulse on click. |
Presets
| Preset | Description | Key Overrides |
|---|---|---|
"slime" | Lime, gravity-fed gooey drip. | buttonColor="#ADFA1D"gravity=0.55particleCount=8 |
"orbit" | Blue droplets orbiting a still body. | buttonColor="#3B82F6"haloSpeed=2.2gravity=0particleCount=6 |
"square" | Pink, square-boundary droplet field. | buttonColor="#EC4899"borderRadius="16px"gravity=0particleCount=8 |
<ElasticButton />
Bezier-edged button whose border stretches toward the cursor and plucks back on click.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "elastic" | "outlined" |
"tension" | "elastic" | Style preset (see below). |
width | number | 220 | Body width in px. |
height | number | 60 | Body height in px. |
range | number | 140 | Proximity in px that triggers edge elasticity. |
borderColor | string | — (per preset) | Stroke color of the elastic edge. |
borderWidth | number | — (per preset) | Stroke width in px. |
maxStretch | number | 28 | Max edge displacement on proximity. |
pluckForce | number | — (per preset) | Impulse applied to the edges on click. |
Presets
| Preset | Description | Key Overrides |
|---|---|---|
"elastic" | Solid red, soft pluck. | buttonColor="#FF1800"borderWidth=0pluckForce=38 |
"outlined" | Transparent body, cyan stroke. | buttonColor="transparent"borderColor="#00F0FF"borderWidth=2pluckForce=50 |
"tension" | Cyan, stiffer/snappier spring. | buttonColor="#00F0FF"pluckForce=60 |
<JellyButton />
Rounded-rect jelly blob that deforms toward the cursor and ripples outward on click.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "jelly" | "viscous" | "jelly" | Style preset (see below). |
width | number | 200 | Body width in px. |
height | number | 56 | Body height in px. |
radius | number | 14 | Corner radius of the rounded-rect blob. |
range | number | 130 | Proximity in px for hover deformation. |
maxStretch | number | — (per preset) | Max hover deformation distance toward the cursor. |
rippleForce | number | — (per preset) | Impulse injected into the blob on click. |
Presets
| Preset | Description | Key Overrides |
|---|---|---|
"jelly" | Violet, bouncy default. | buttonColor="#8B5CF6"maxStretch=26rippleForce=35 |
"viscous" | Emerald, slow and gooey. | buttonColor="#10B981"maxStretch=45rippleForce=20 |
<ImpactButton />
Drops on click, shatters into gooey chunks with a splat, then coalesces and springs back.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "impact" | "drop" | "sticky" | "impact" | Style preset (see below). |
width | number | 200 | Body width in px. |
height | number | 56 | Body height in px. |
fallDistance | number | — (per preset) | Distance in px the button falls before shattering. |
impactDelayMs | number | — (per preset) | Time the pieces stay shattered before rejoining. |
particleColor | string | = buttonColor | Color of the splat droplets. |
particleCount | number | — (per preset) | Number of droplets emitted on impact. |
minRadius | number | 5 | Minimum splat droplet radius. |
maxRadius | number | 11 | Maximum splat droplet radius. |
borderRadius | string | "16px" | Body corner radius. |
Presets
| Preset | Description | Key Overrides |
|---|---|---|
"impact" | Lime, short fall + quick rejoin. | buttonColor="#A3E635"fallDistance=60impactDelayMs=350particleCount=10 |
"drop" | Red, tall fall + heavy splatter. | buttonColor="#EF4444"fallDistance=150impactDelayMs=600particleCount=18 |
"sticky" | Blue, long pause before rejoin. | buttonColor="#3B82F6"impactDelayMs=1000 |
Examples
'use client'). They use refs/useId; render on the client. No dynamic(ssr:false) is strictly required (no WebGL), but they won't animate during SSR.prefers-reduced-motion (registry supportsReducedMotion: false). If you need it, gate the animated variants yourself. — keyboard-focusable with a focus-visible ring, and accepts disabled, type, and aria-label.