Motion One Spring Cards — Free Spring-Physics Card Grid Snippet

Motion One Spring Cards · Cards · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Spring-based easing
spring({ stiffness, damping }) replaces bezier curves entirely.
Staggered entrance
stagger(0.08) delays each card's animation in sequence.
Snappy hover pop
Higher stiffness, lower damping gives a lively overshoot.
Pointer-driven drag
Cards drag horizontally and rotate slightly while dragging.
Spring drag-back
Releasing a card springs it back to center, not an instant snap.
Replayable shuffle
A button fades cards out then replays the staggered entrance.
Tiny dependency
Motion One's core is a few KB, built on the native WAAPI.
No build step needed
Loaded as a UMD global straight from a CDN script tag.

About this UI Snippet

Motion One Spring Cards — Spring Physics Entrances, Hover Pops & Drag-Back with Motion One

Screenshot of the Motion One Spring Cards snippet rendered live

Most CSS and JS animation relies on easing curves — bezier functions that approximate motion but never quite capture the springy overshoot-and-settle of a real physical object. This snippet uses Motion One, a small (under 5KB core) animation library built directly on the native Web Animations API, to drive card entrances, hover states, and drag interactions entirely with spring() easing instead of duration-based curves.

Why spring easing instead of bezier curves

A cubic-bezier easing curve is defined by four fixed control points and always takes the same shape regardless of how far an element travels. A spring, by contrast, is defined by physical parameters — stiffness and damping — and its motion emerges from simulating those forces frame by frame. This means a spring naturally travels faster over a longer distance and settles at a consistent, physical rate, which is why UI built with real device-like motion (iOS, native apps) tends to feel more responsive than web UI relying purely on timed curves. Motion One's spring() helper exposes this as a drop-in easing option for its animate() calls, so this snippet uses the exact same pattern as Scroll Reveal Grid's stagger, just with spring physics instead of a power curve.

Staggered spring entrance

On load, animate(cards, {...}, { delay: stagger(0.08), easing: spring({ stiffness: 220, damping: 18 }) }) animates every card's opacity, scale, and y-offset together, with each card's start delayed by 0.08s more than the previous one via Motion One's stagger() helper — the same staggered-wave idea as a GSAP-based reveal, but expressed with a two-line API and no separate plugin.

Hover pop and drag-back

Hovering a card triggers a snappier spring (stiffness: 300, damping: 14) that lifts and scales it slightly — high stiffness with low damping produces a small overshoot, giving the hover a lively "pop" rather than a flat linear lift. Dragging a card horizontally via pointer events, then releasing it, animates it back to x: 0, rotate: 0 using another spring — so letting go of a card doesn't just snap it back instantly, it bounces back the way a card on a real desk would.

Loading Motion One from a CDN

This snippet loads Motion One's UMD build directly via a <script> tag from jsDelivr, which exposes a global Motion object with animate, stagger, and spring — no bundler or import statement required, matching how this snippet library loads other CDN-based effects. If you're working in a module-based project instead, the same functions are available as named exports from the motion npm package or its ESM CDN build.

Customizing it

Tune stiffness/damping for snappier or looser motion (higher stiffness = faster, lower damping = more bounce), change the stagger delay, or swap the horizontal-only drag for a full 2D drag using Motion One's built-in drag utilities. Pair this with Feature Cards or a Product Card grid for a livelier catalog entrance.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to tune spring parameters by trial and error. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how stiffness and damping in spring({ stiffness: 220, damping: 18 }) combine to produce the entrance motion's settle time and how that differs from what a cubic-bezier easing curve of similar duration would look like. The same assistant can help you tune the feel — asking whether the hover spring's stiffness: 300, damping: 14 is too bouncy for a dense grid of many cards, or whether the drag-back spring should use different values than the entrance spring. It's also useful for extending the interaction: ask it to add full 2D drag instead of horizontal-only, constrain the drag to the grid's bounding box, or replace the shuffle button's instant fade-out with its own spring-based exit animation. 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 "spring cards" grid in plain HTML, CSS, and JavaScript using the Motion One library (loaded as a global via its CDN UMD build), where every animation — entrance, hover, and drag release — uses spring() easing instead of duration-based bezier curves.

Requirements:
- A responsive grid of card elements (name, role, avatar), initially hidden (opacity 0, scaled down) via CSS, that animate into place on page load using Motion One's animate() targeting all cards at once.
- The entrance animation must use Motion One's stagger() helper to delay each card's start by a small fixed amount relative to the previous card, and must use spring() (not a named easing string or bezier curve) as the easing option, combining opacity, scale, and a vertical offset.
- On mouseenter, each card should independently animate to a slightly larger scale and a small upward y-offset using a snappier spring configuration (higher stiffness, lower damping than the entrance), and animate back to its resting state with a different spring on mouseleave.
- Implement horizontal pointer-driven dragging on each card: track pointerdown/pointermove to move the card and apply a subtle rotation proportional to the drag distance directly via a CSS transform, then on pointerup use Motion One's animate() with spring() easing to animate the card's position and rotation back to zero — it must visibly bounce back rather than snap instantly.
- Add a "shuffle" button that quickly fades and scales all cards out, waits for that animation to finish (using the returned animation's .finished promise), then re-triggers the original staggered spring entrance.
- Load Motion One only via a CDN script tag (no bundler, no import statement) and access its animate, stagger, and spring functions from the resulting global object.

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 Motion One CDNInclude the motion.js UMD build from the CDN panel — it exposes a global Motion object.
  2. 2
    Paste HTML, CSS, and JSA team card grid and a shuffle button render.
  3. 3
    Watch the entranceCards spring in with a staggered 0.08s delay between each.
  4. 4
    Hover a cardIt springs up and scales slightly with a snappy pop.
  5. 5
    Drag a card sidewaysRelease it — it springs back to center with a slight bounce.
  6. 6
    Click Shuffle inCards fade out quickly, then replay the staggered spring entrance.

Real-world uses

Common Use Cases

Team and about pages
Introduce a team card grid with springy motion.
Product catalogs
Animate a product card grid entrance.
Feature showcases
Give feature cards a physical, tactile feel.
Kanban / sortable boards
Use the drag-and-spring-back pattern as a base for reorderable cards.
Onboarding carousels
Spring-driven card stacks feel more alive than duration-based fades.
Testimonial rotators
Pair with Testimonial Card for springy transitions.

Got questions?

Frequently Asked Questions

stiffness controls how strongly the spring pulls toward its target — higher values move faster and more urgently. damping controls how much the motion is resisted as it approaches the target — lower damping allows more oscillation and overshoot before settling, higher damping approaches smoothly with little or no bounce. Motion One simulates these forces frame by frame rather than interpolating along a fixed curve, which is why the resulting motion looks different depending on how far the element travels.

Motion One is a much smaller library (a few KB versus GSAP's larger core plus plugins) built directly on the browser's native Web Animations API, which makes it a good fit when spring easing and simple entrance/hover/drag animations are all you need. GSAP remains the stronger choice for complex timelines, scroll-triggered sequencing, or SVG morphing — see Scroll Reveal Grid for a GSAP-based example doing exactly that.

Pointer events (pointerdown/pointermove/pointerup) track horizontal movement and directly set a translateX/rotate transform on the card while dragging, giving instant 1:1 feedback. On pointerup, Motion One's animate() call takes over, animating x and rotate back to 0 using spring() easing — so the release feels like a physical snap-back rather than an abrupt jump.

Yes. This snippet loads the UMD build via a <script> tag so animate, stagger, and spring are available as the global Motion object with no bundler. In a module-based project, install the motion npm package and import { animate, stagger, spring } from 'motion' directly, or import from an ESM CDN like esm.sh/motion if you're not using a bundler but want ES module syntax.

Import animate, stagger, and spring from the motion package (or reference the CDN global if not bundling), then call animate() inside a mount effect (useEffect, onMounted, or ngAfterViewInit) targeting refs to your card elements rather than querySelectorAll. Attach the pointer event handlers as React/Vue/Angular event bindings instead of addEventListener, keeping the same spring() easing values.