Mouse Cursor Confetti (GSAP Physics2D)

Clicking anywhere on the page bursts 3–10 coloured dot particles from the cursor position. Each dot pops in, then scatters outward in a random direction under simulated gravity before fading away.

GSAPPhysics2DConfettiClickInteractive

Setup — External Scripts

GSAP CDN
html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js"></script>
Physics2DPlugin CDN
html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/Physics2DPlugin.min.js"></script>

Code

styles.css
css
body {
  overflow: clip;
}

.dot {
  position: absolute;
  background-color: #D3DCCD;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  will-change: transform, opacity;
  pointer-events: none;
}
script.js
javascript
gsap.registerPlugin(Physics2DPlugin);

document.addEventListener("click", (event) => {
  const dotCount = gsap.utils.random(3, 10, 1);
  const colors = ["#D3DCCD", "#F5FEEF", "#6C7E5F", "#818A7B", "#94A787"];

  for (let i = 0; i < dotCount; i++) {
    const dot = document.createElement("div");
    dot.classList.add("dot");
    document.body.appendChild(dot);

    gsap.set(dot, {
      backgroundColor: gsap.utils.random(colors),
      top: event.clientY,
      left: event.clientX,
      scale: 0,
    });

    gsap.timeline({ onComplete: () => dot.remove() })
      .to(dot, {
        scale: gsap.utils.random(0.5, 1),
        duration: 0.3,
        ease: "power3.out",
      })
      .to(dot, {
        duration: 2,
        physics2D: {
          velocity: gsap.utils.random(200, 650),
          angle: gsap.utils.random(0, 360),
          gravity: 500,
        },
        autoAlpha: 0,
        ease: "none",
      }, "<");
  }
});

Notes

  • Each dot is created as a fresh DOM element on click and removed via the timeline's `onComplete` callback — no pooling needed for this particle count.
  • `overflow: clip` on `body` prevents scrollbars appearing when dots fly near the edges; use a scoped wrapper element instead if you don't want to constrain the whole page.
  • The `"<"` position parameter starts the physics tween at the same time as the scale-in tween, so the dot moves and pops simultaneously.
  • Swap the `colors` array and dot size to match your brand — or replace the `.dot` div with an SVG or image element for custom shapes.