JoshWComeau

The Whimsical Animation Toolkit

FITC Web Unleashed 2025 talk

Thanks for checking out my talk!

I’ll share some links to various resources below, but first, here’s the final playground from my talk, with all of the optimizations we made to the “Like” button:

Code Playground

Open in CodeSandbox
import { random, times } from 'lodash';
import './reset.css';
import './styles.css';

const btn = document.querySelector('.particleButton');

function generateParticle() {
  const particle = document.createElement('span');
  particle.classList.add('particle');

  const distance = random(32, 64);

  const popDuration =
    normalize(distance, 32, 64, 400, 800) +
    random(400, 800);
  const fadeDuration = popDuration * 0.75;
  const fadeDelay = random(150, 450);

  particle.style.setProperty('--angle', random(1, 360) + 'deg');
  particle.style.setProperty('--distance', distance + 'px');
  particle.style.setProperty('--pop-duration', popDuration + 'ms');
  particle.style.setProperty('--fade-duration', fadeDuration + 'ms');
  particle.style.setProperty('--fade-delay', fadeDelay + 'ms');
  particle.style.setProperty('--size', random(11, 13) + 'px');

  btn.appendChild(particle);
}

btn.addEventListener('click', () => {
  btn.classList.toggle('liked');

  const isLiked = btn.classList.contains('liked');
  if (!isLiked) {
    return;
  }

  const particles = [];
  times(10, generateParticle);
});


export const normalize = (
  value,
  currentScaleMin,
  currentScaleMax,
  newScaleMin,
  newScaleMax
) => {
  const standardNormalization =
    (value - currentScaleMin) / (currentScaleMax - currentScaleMin);

  return (
    (newScaleMax - newScaleMin) * standardNormalization + newScaleMin
  );
};

This effect is covered in much more detail, along with lots of other cool stuff, in my upcoming course, Whimsical Animations(opens in new tab). Follow that link to learn more about the course!

Slides

I presented this talk using a lil’ webapp I built into my course platform. They’re not really intended to be viewed by anyone else, and so they won’t work well on mobile, and may not work across all browsers.

That said, you’re welcome to give it a shot! You can access the slides here:

Protip: You can use Ctrl + D to move forward in the slides, and Ctrl + A to move back.

Talk Recording

When the talk recording is published online, I’ll update this section with a link to the video. You can subscribe to my newsletter to be notified when it's available!

Related Blog Posts

  • Color Shifting in CSS — a deep dive into the surprisingly-hard problem of animating color changes in CSS, along with the best solutions I’ve found.
  • An Interactive Guide to Keyframe Animations — this blog post introduces keyframe animations, and explains how they work. Honestly, I think keyframe animations are one of the most underrated CSS features!
  • Partial Keyframes — in my talk, I included some pretty fancy tricks with keyframe animations. In this blog post, we go beyond the basics and explore some of the advanced things we can do with keyframes.

My Courses

In addition to my upcoming Whimsical Animations(opens in new tab) course, I have two other courses that you can register for right now:

  • CSS for JavaScript Developers(opens in new tab) — A comprehensive course about CSS! I’ll help you build robust mental models for how CSS works at a deeper level, so that you can stop memorizing snippets and start relying on your intuition! This course is specifically built for folks who use a component-based framework like React/Angular/Vue.
  • The Joy of React(opens in new tab) — I’ve been using React for over a decade now, and I think it’s one of the best frameworks for building dynamic web applications. In this course, I’ll share the patterns and practices I’ve developed so that you can enjoy building with React too!