canvas-confetti

A zero-dependency JavaScript library for firing performant, physics-based confetti animations on an HTML canvas.

Library
npm
v1.9.4
12,831 stars
ISC

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
47 /100 Fair
Development Activity 0
Maintenance 32
Community 56
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
82 /100 Excellent
Architecture 82
Code Quality 78
Innovation 80
Learning Curve 88

canvas-confetti is a lightweight, dependency-free JavaScript library that renders celebratory confetti bursts on an HTML5 canvas. It exposes a single confetti() function with a rich set of physics parameters — particle count, angle, spread, velocity, gravity, drift, and decay — so a one-line call like confetti() produces a reasonable default burst while a fully-tuned call can drive multi-second, multi-origin animations.

Under the hood it reuses a single canvas element across calls, offloads rendering to a Web Worker with OffscreenCanvas when the browser supports it (falling back gracefully to the main thread), and supports custom shapes via SVG paths or rendered emoji/text. It also respects prefers-reduced-motion through an opt-in disableForReducedMotion flag, making it possible to add celebratory UI moments — checkout completions, form submissions, achievement unlocks — without pulling in an animation framework or paying much of a bundle-size or runtime-performance cost.

What You Get

  • A single confetti(options) function that returns a Promise resolving when the animation completes, so bursts can be sequenced or awaited
  • Fine-grained physics controls — particleCount, angle, spread, startVelocity, decay, gravity, drift, ticks, scalar, and origin coordinates — for tuning exactly how confetti behaves
  • Custom particle shapes via confetti.shapeFromPath (SVG path strings) and confetti.shapeFromText (emoji or text rendered as confetti), beyond the built-in square/circle/star shapes
  • A confetti.create(canvas, options) factory for scoping confetti to a specific canvas element instead of a full-page overlay, with optional automatic canvas resizing
  • Automatic Web Worker + OffscreenCanvas rendering when the browser supports it, falling back transparently to main-thread rendering elsewhere, plus a disableForReducedMotion option for accessibility
  • A prebuilt UMD/browser bundle (dist/confetti.browser.min.js) servable directly from a CDN like jsDelivr with zero build step required

Common Use Cases

  • Celebrating a successful checkout, signup, or payment completion in an e-commerce or SaaS flow
  • Rewarding users for hitting a milestone — completing an onboarding checklist, unlocking an achievement, or finishing a quiz
  • Adding a festive touch to New Year, birthday, or anniversary landing pages and countdown timers
  • Confirming a successful form submission or user action (e.g. “application submitted”) with a lightweight visual reward
  • Building confetti-cannon or fireworks-style interactive demos and game-over/victory screens

Under The Hood

Architecture: The entire library lives in a single UMD-style IIFE (src/confetti.js, ~880 lines) that detects at load time whether the browser supports Worker + OffscreenCanvas + transferControlToOffscreen, and if so lazily spins up a Web Worker running the same source (re-invoked via main.toString()) to do the actual per-frame canvas drawing off the main thread; otherwise it falls back to drawing directly on a lazily-created, reused <canvas> element positioned as a full-page fixed overlay. Animation state (particle positions, velocities, decay) is driven by a custom requestAnimationFrame scheduler (raf) that throttles to ~60fps and falls back to setTimeout when rAF is unavailable, and multiple concurrent confetti() calls are merged into the same in-flight animation rather than spawning competing loops.

Tech Stack: Runtime has zero dependencies — pure vanilla JavaScript targeting both <script>/CDN usage (UMD global confetti) and bundler usage (require/import, with module/jsdelivr build fields pointing at dist/confetti.module.mjs and dist/confetti.browser.js). The dev/build toolchain uses Browserify for bundling, Terser for minification, ESLint for linting, and a custom build/build.js script; tests run via AVA driving headless Puppeteer against a local static server, with Jimp used for pixel-level screenshot assertions.

Code Quality: The test suite (test/index.test.js, ~1250 lines, plus a dedicated ssr.test.js) exercises the library end-to-end in a real browser via Puppeteer rather than unit-testing internals in isolation, capturing and comparing rendered canvas output — a pragmatic choice for a purely visual library, though it means test correctness depends on Chromium rendering stability. Source code favors small, well-named internal closures (bitmapMapper, getWorker, raf) with inline comments explaining non-obvious browser-compatibility decisions (e.g. why bitmaps are cached, why disableForReducedMotion defaults to off), and defensive feature-detection guards every advanced code path (OffscreenCanvas, Path2D, DOMMatrix) with try/catch fallbacks so the library degrades rather than throwing on older browsers.

API Design: The public surface is deliberately minimal — a single callable confetti(options) plus three focused helpers (create, shapeFromPath, shapeFromText) — and every option has a sensible default, so confetti() with no arguments produces a usable result while power users can tune a dozen physics parameters. The README documents every option with type and default inline, and the Promise-based return value (with a pluggable confetti.Promise for legacy environments) makes sequencing multiple bursts straightforward without callback plumbing.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers