PhysicsProps Friction Pucks — Free GSAP Physics Snippet

PhysicsProps Friction Pucks · Animations · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Per-property physics
x gets velocity and friction independently.
Controlled experiment
One variable changes; outcomes diverge.
Exponential decay
Friction removes a share of speed per tick.
No destinations
Stopping points are outcomes, not inputs.
Kill-set-launch resets
The standard physics replay idiom.
Physics as easing
ease: 'none' keeps the decay honest.
Mixed-mode motion
Simulated x beside choreographed spin.
Acceleration-ready
Add gravity or headwinds per property.

About this UI Snippet

PhysicsProps Friction Pucks — Velocity and Friction Instead of End Values

Screenshot of the PhysicsProps Friction Pucks snippet rendered live

This demo is a physics lesson as UI: three hockey pucks receive the *same* 620px/s launch velocity, but different friction coefficients — 0.02, 0.08, 0.2 — so they glide to three very different stopping points. Nothing specifies where any puck ends; friction decides. That's GSAP's PhysicsPropsPlugin (free on the CDN since 3.13): per-property physics simulation where motion comes from velocity, acceleration, and friction rather than destinations.

physicsProps vs physics2D: the mental model

Where Physics2D simulates a *point moving through 2D space* (one velocity vector plus an angle and gravity), physicsProps applies independent physics to *any individual properties*: give x a velocity and friction, give rotation its own, even drive opacity or a filter value with simulated momentum. It's the general-purpose form — each property gets its own tiny simulation, and they don't need to agree with each other.

Friction is exponential decay, and it shows

Each tick, friction removes a fraction of the remaining velocity — so speed decays exponentially, which is why the pucks' deceleration looks so different from an eased tween's. The 0.02 puck coasts nearly frictionlessly across the lane; 0.08 pulls up around two-thirds in; 0.2 dies within the first stretch. Same push, three visibly honest physics outcomes — the comparison *is* the demo, and it's why identical velocity matters: change one variable, see its effect.

No end values means kill-and-relaunch is the reset pattern

Because physics tweens don't know their destinations, "replay" can't rewind to defined endpoints. The launch handler calls gsap.killTweensOf(puck) then gsap.set(puck, { x: 0 }) — kill whatever simulation is running, teleport home, launch fresh. The reset button does the same but tweens home smoothly. This kill-set-launch idiom is standard for any launch-condition animation.

ease: 'none' again — friction is the easing

As with all physics plugins, easing would remap simulation time and corrupt the decay curve. Linear time in, physics out: the deceleration users see is purely the friction model, which is exactly what makes it look like ice instead of animation.

The spin is a deliberate contrast

Each puck also rotates — but via a plain power2.out tween whose total spin is *derived from* its friction value (slipperier pucks spin more). It demonstrates the boundary: rotation here is choreography (a known end angle, eased), while x is simulation (no known end). Mixing both on one element is normal GSAP practice — properties are independent.

Where acceleration fits

This demo uses velocity + friction, but physicsProps also accepts acceleration per property — a constant force. y with positive acceleration is gravity; x with negative acceleration is a headwind. Velocity + acceleration + friction covers thrown, falling, launched, and decaying motion for any property you can tween.

Customizing it

Make friction user-editable, add lanes, or apply the same model to a scroll position or slider value. Related motion: momentum dragging in drag throw notes (InertiaPlugin is this idea attached to gestures), parabolic bursts in physics 2d burst, bouncing in custom bounce ball, and collision toys in physics balls.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't need to reverse-engineer the friction model on your own. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the physicsProps object applies velocity and friction independently to the x property while a separate power2.out tween handles rotation on the same element, and why ease none is required for the x simulation to look right. The same assistant can help optimize it, for example checking whether killTweensOf plus a fresh gsap.set is the cleanest reset pattern here, or whether the rotation amount formula (derived from each puck's friction value) actually produces a visually consistent relationship across all three lanes. It's also useful for extending the effect: ask it to make the friction values user-editable with a slider per lane, add a fourth lane demonstrating acceleration (a headwind or gravity), or turn this into a mini physics quiz where users guess which puck has the lowest friction. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a side-by-side friction comparison demo in plain HTML, CSS, and vanilla JavaScript using GSAP and its PhysicsPropsPlugin (load both from a CDN) — the horizontal motion must come from per-property physics simulation, not from tweening to a fixed end position.

Requirements:
- At least three parallel "lanes," each containing one puck element and a visible label showing that lane's friction coefficient (for example 0.02, 0.08, 0.2).
- A "Launch" button that, for every puck simultaneously, kills any currently running tween on it, resets its x position to zero, and starts a new tween whose physicsProps configuration gives the x property an identical launch velocity across all pucks but a different friction value read from each puck's own data attribute.
- The launch tween's ease must be set to none, since the friction value itself must produce all of the deceleration — document in a comment why adding a separate easing curve would corrupt the simulated decay curve.
- In the same launch action, also spin each puck via a separate, ordinary eased tween (not physics-driven) whose total rotation amount is mathematically derived from that puck's friction value, so slipperier pucks (lower friction) end up spinning more — demonstrating that a physics-simulated property and a normal choreographed property can coexist on one element.
- A "Reset" button that kills any running simulations and smoothly eases every puck back to its starting x position and rotation of zero.
- Style the lanes to look like a rink or track, with a distinct color per puck, so the difference in stopping distance between the three friction values is visually obvious at a glance.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Add the GSAP CDNsInclude gsap and PhysicsPropsPlugin from the CDN panel.
  2. 2
    Paste HTML, CSS, and JSThree labeled lanes render with pucks at the start.
  3. 3
    Click LaunchAll pucks fire with identical 620px/s velocity.
  4. 4
    Compare the stopsFriction alone produces three distances.
  5. 5
    Hit ResetPucks tween home, simulations killed cleanly.
  6. 6
    Edit the frictionsEach puck's data-friction is its physics.

Real-world uses

Common Use Cases

Physics explainers
Teach friction visually; pair gravity's version with physics 2d burst.
Game UI
Air-hockey and shuffleboard motion, next to physics balls.
Momentum widgets
Coasting carousels and dials — the gesture version is drag throw notes.
Decay meters
Values that bleed off naturally, like a draining gradient progress.
Slot mechanics
Spin-downs for wheels, cousin to spin wheel.
Bounce contrasts
Show restitution instead via custom bounce ball.

Got questions?

Frequently Asked Questions

physics2D simulates a point in 2D space — one velocity with an angle, plus gravity — ideal for particles and projectiles. physicsProps runs an independent simulation per property: x can have velocity and friction while rotation has its own, and any tweenable property (even opacity) can carry momentum. It's the general-purpose plugin; physics2D is the specialized ballistic one.

Each tick, friction removes a proportional share of the remaining velocity, producing exponential decay — fast at first, asymptotically settling. That's why 0.02 coasts across the lane while 0.2 dies early despite identical launches, and why the motion reads as ice rather than an eased tween: eases are time-symmetric curves; decay is a force.

Physics tweens have no recorded end values — the destination emerges from simulation. So replays use the kill-set-launch idiom: killTweensOf clears any running simulation, set() teleports the puck home, and a fresh tween launches new physics. Reversing or seeking a physics tween replays its integrated history, but "restart from rest" requires the explicit reset.

To demonstrate that simulated and choreographed properties coexist on one element: x is physics (unknown end), rotation is a standard power2.out tween whose total spin is derived from the friction value, so slipperier pucks visibly spin longer. GSAP treats each property independently, letting you mix simulation with designed motion freely.

Yes — each property accepts acceleration alongside velocity and friction. Positive acceleration on y is gravity (a thrown-up element rises, slows, and falls), negative acceleration on x is a headwind fighting the launch, and combining all three per property models most everyday motion without a physics engine.

Register the plugin at module scope and trigger launches from event handlers against refs — no mount effect needed for click-driven physics, though a cleanup should killTweensOf each puck so simulations die on unmount. Keep positions out of framework state entirely; the simulation owns x. Lanes, pucks, and buttons all express directly as Tailwind utilities.