Esc
  • Design SystemsFrom Figma Variables to Tailwind, Without the Copy-PasteDesign tokens only help if design and code read from the same source. Here's how I set up a pipeline where Figma variables become Tailwind theme values and React props, and what I learned about naming along the way.
  • Next.jsBuilding a Like Button, From Database to DelightThe heart at the bottom of every article on this site is a tiny full-stack feature. Here's how it works, from the SQLite table and API route to optimistic updates and batched requests.
  • AnimationA Friendly Introduction to Spring PhysicsSprings make interfaces feel alive. Instead of picking a duration and an easing curve, you describe how something should move, and physics does the rest. Let's build an intuition for stiffness and damping with a live playground.
  • UI DesignDesigning Dashboards People Can Actually ScanData-heavy screens fail when every number shouts at once. A practical guide to hierarchy, tables, filters and progressive disclosure for dashboards that engineers and analysts use all day.
  • CSSUnderstanding Flexbox Alignment, Visuallyjustify-content or align-items? Main axis or cross axis? If you still guess which property to use, this interactive guide will fix that for good.
  • BrandA Brand System Is More Than a LogoA logo is the smallest part of a brand. What makes a brand recognizable is the system around it, from type and color to iconography, voice and the way the product itself behaves. Here's how I approach building one that survives contact with real products.
Animation

A Friendly Introduction to Spring Physics

Springs make interfaces feel alive. Instead of picking a duration and an easing curve, you describe how something should move, and physics does the rest. Let's build an intuition for stiffness and damping with a live playground.

3 min read…

Most CSS animations are built on time. You say "move this box 200 pixels over 300 milliseconds, using ease-out," and the browser draws the frames in between.

That works great, until the animation gets interrupted. Hover over a button, then move away halfway through the transition, and the motion reverses with an abrupt change in speed. It feels mechanical, because real objects don't work that way. They have momentum.

Spring animations take a different approach. Instead of a duration, you describe a physical system, and the motion falls out of the simulation.

The two numbers that matter

A spring animation is mostly controlled by two values:

  • Stiffness is how strongly the spring pulls toward its target. A stiff spring snaps into place quickly; a loose one drifts lazily.
  • Damping is friction. It drains energy from the system. Low damping means lots of wobble; high damping means the object glides to a stop without overshooting.

The best way to understand them is to play. Try a low damping value (around 5) with high stiffness, then crank damping up to 40:

Drag the sliders, then press the button. Low damping wobbles; high stiffness is quick.

Notice how you never chose a duration. The animation takes as long as the physics says it should.

What's happening under the hood

Every frame, we calculate the force acting on the ball using Hooke's law, plus a friction term:

JS
const springForce = -stiffness * (position - target);
const dampingForce = -damping * velocity;
const acceleration = springForce + dampingForce; // mass = 1

velocity += acceleration * deltaTime;
position += velocity * deltaTime;

That's the entire engine! Six lines. We keep running it with requestAnimationFrame until the ball is practically at rest.

Interruptions for free

Here's the magic. Because the simulation tracks velocity, changing the target mid-flight just works. The ball keeps its momentum and smoothly curves toward the new destination. Press the button rapidly in the demo above and see for yourself.

With keyframe animations, you'd need to calculate where the element currently is, cancel the old animation, and start a new one with a matching speed. Springs handle all of that automatically.

When should you reach for springs?

I use them whenever an animation is triggered by the user and could be interrupted: drag-and-drop, toggles, drawers, modals, hover effects. For purely decorative, looping animations (like a loading spinner), regular CSS keyframes are simpler and just as good.

Respect reduced motion

Bouncy motion can be uncomfortable for people with vestibular disorders. Always check the prefers-reduced-motion media query and swap springs for an instant change or a short fade:

JS
const prefersReducedMotion = window.matchMedia(
  "(prefers-reduced-motion: reduce)"
).matches;

if (prefersReducedMotion) {
  element.style.transform = `translateX(${target}px)`;
} else {
  animateWithSpring(element, target);
}

Springs are one of those ideas that seem intimidating until you see how little code they need. Once they click, it's hard to go back to plain easing curves.

Want to know when I publish something new?

I send a short email when there's a new article or project, usually a couple of times a month. No spam, and you can unsubscribe whenever you like.