catdad/canvas-confetti
π performant confetti animation in the browser
Healthy across all four use cases
weakest axisPermissive license, no critical CVEs, actively maintained β safe to depend on.
Has a license, tests, and CI β clean foundation to fork and modify.
Documented and popular β useful reference codebase to read through.
No critical CVEs, sane security posture β runnable as-is.
- βLast commit 6mo ago
- β4 active contributors
- βISC licensed
- βCI configured
- βTests present
- β Slowing β last commit 6mo ago
- β Small team β 4 contributors active in recent commits
- β Single-maintainer risk β top contributor 96% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the βHealthyβ badge
Paste into your README β live-updates from the latest cached analysis.
[](https://repopilot.app/r/catdad/canvas-confetti)Paste at the top of your README.md β renders inline like a shields.io badge.
βΈPreview social card (1200Γ630)
This card auto-renders when someone shares https://repopilot.app/r/catdad/canvas-confetti on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: catdad/canvas-confetti
Generated by RepoPilot Β· 2026-05-06 Β· Source
Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale β STOP and ask the user to regenerate it before proceeding. - Treat the AI Β· unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/catdad/canvas-confetti shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything β but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
Verdict
GO β Healthy across all four use cases
- Last commit 6mo ago
- 4 active contributors
- ISC licensed
- CI configured
- Tests present
- β Slowing β last commit 6mo ago
- β Small team β 4 contributors active in recent commits
- β Single-maintainer risk β top contributor 96% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live catdad/canvas-confetti
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale β regenerate it at
repopilot.app/r/catdad/canvas-confetti.
What it runs against: a local clone of catdad/canvas-confetti β the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in catdad/canvas-confetti | Confirms the artifact applies here, not a fork |
| 2 | License is still ISC | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit β€ 223 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of catdad/canvas-confetti. If you don't
# have one yet, run these first:
#
# git clone https://github.com/catdad/canvas-confetti.git
# cd canvas-confetti
#
# Then paste this script. Every check is read-only β no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of catdad/canvas-confetti and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "catdad/canvas-confetti(\\.git)?\\b" \\
&& ok "origin remote is catdad/canvas-confetti" \\
|| miss "origin remote is not catdad/canvas-confetti (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(ISC)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"ISC\"" package.json 2>/dev/null) \\
&& ok "license is ISC" \\
|| miss "license drift β was ISC at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "src/confetti.js" \\
&& ok "src/confetti.js" \\
|| miss "missing critical file: src/confetti.js"
test -f "package.json" \\
&& ok "package.json" \\
|| miss "missing critical file: package.json"
test -f "build/build.js" \\
&& ok "build/build.js" \\
|| miss "missing critical file: build/build.js"
test -f "test/index.test.js" \\
&& ok "test/index.test.js" \\
|| miss "missing critical file: test/index.test.js"
test -f ".github/workflows/ci.yml" \\
&& ok ".github/workflows/ci.yml" \\
|| miss "missing critical file: .github/workflows/ci.yml"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 223 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~193d)"
else
miss "last commit was $days_since_last days ago β artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) β safe to trust"
else
echo "artifact has $fail stale claim(s) β regenerate at https://repopilot.app/r/catdad/canvas-confetti"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
TL;DR
canvas-confetti is a high-performance JavaScript library that renders animated confetti particles directly to an HTML5 Canvas element. It creates visually striking burst/explosion effects with fine-grained control over particle physics (velocity, gravity, drag, rotation), timing, and colors β solving the problem of adding delightful celebratory animations without heavy DOM manipulation or third-party animation frameworks. Simple single-file core: src/confetti.js contains the main animation engine and particle physics logic. The build pipeline (build/build.js, build/serve.js) outputs three distributions: ES module (dist/confetti.module.mjs), browser global (dist/confetti.browser.js), and minified CDN variant. Fixtures in /fixtures/ provide integration examples (browserify, module, minified). Tests use AVA and Puppeteer for visual regression against generated images.
Who it's for
Frontend developers and product teams building web applications that need celebratory effects for user milestones (form submissions, achievements, celebrations). Used by developers who want drop-in confetti animations without learning animation libraries, and by designers who need to add polish to interactive moments.
Maturity & risk
Production-ready and actively maintained. The project is at v1.9.4 with established distribution across NPM and CDN (jsdelivr), CI/CD via GitHub Actions, comprehensive test suite (test/index.test.js, test/ssr.test.js), and evidence of regular updates. The codebase shows professional polish with ESLint, Browserify bundling, and minification pipelines.
Low risk overall. Dependencies are minimal and stable (browserify, terser, ava, puppeteer for dev only). Single maintainer (Kiril Vatev) creates some concentration risk, but the project is feature-complete and receives infrequent but consistent updates. No critical unresolved issues visible in the repo structure.
Active areas of work
The project appears in steady-state maintenance. The CI workflow (workflows/ci.yml) runs tests on commits. No active major feature development is visible, but the codebase is structured to accept contributions: linting rules are in place (.eslintrc.yml), pre-test build steps ensure consistency, and the SSR test suggests interest in Node.js compatibility.
Get running
git clone https://github.com/catdad/canvas-confetti.git
cd canvas-confetti
npm install
npm run dev
This starts the development server (via build/serve.js). Open http://localhost:PORT (check terminal output) to see the demo.
Daily commands:
Development: npm run dev starts a local server (build/serve.js) serving fixtures. Testing: npm test runs AVA tests (pretest hook triggers build + browserify + minify). Linting: npm run lint checks src/, test/, and build/ with ESLint. Visual dev: CONFETTI_SHOW=1 npm test runs tests with a visible browser window (devtest).
Map of the codebase
src/confetti.jsβ Core entry point and main library implementation; defines the confetti animation engine, particle physics, and canvas rendering logic that all consumers depend on.package.jsonβ Defines build targets (browser, module, minified), main entry points, and test/lint scripts that structure the entire development workflow.build/build.jsβ Build orchestration script that generates dist/ outputs in multiple formats (UMD, ESM, browser); critical for release distribution.test/index.test.jsβ Primary test suite validating animation behavior, particle physics, and canvas rendering; gates all releases..github/workflows/ci.ymlβ GitHub Actions CI/CD pipeline that runs tests, linting, and builds on every commit; ensures code quality and deployment readiness.fixtures/page.htmlβ Demo and integration test page; real-world usage example showing how consumers invoke the confetti library.
Components & responsibilities
- confetti.js (main module) (Canvas API, requestAnimationFrame, JavaScript Array/Math) β Entry point; exports the
confetti()function. Manages canvas creation, particle initialization, physics simulation, rendering, and animation loop lifecycle.- Failure mode: Missing or broken canvas, incorrect particle trajectories, dropped frames, memory leaks if animation never stops.
- Particle system (Array, Object literals, Math (sin, cos, sqrt)) β Maintains array of active particles; updates positions each frame based on gravity and drag; removes expired particles.
- Failure mode: Particles linger indefinitely if lifetime logic breaks, or removed prematurely if update incorrectly decreases lifetime.
- Canvas renderer (CanvasRenderingContext2D (fillRect, arc, transform, fillText)) β Draws all particles to canvas each frame; handles shapes (circles, rectangles, emojis), colors, rotation, and transformations.
- Failure mode: Particles invisible (bad color/alpha), rotations wrong (incorrect matrix math), emoji not rendering (font issues).
- Animation loop (requestAnimationFrame) (requestAnimationFrame, setTimeout fallback) β Schedules rendering at ~60 FPS; continues until all particles expire.
- Failure mode: Animation stutters or stops if RAF is not called; memory leak if loop never exits (infinite particle generation).
- Build system (Node.js, Browserify, Terser, ESLint, AVA) β Transforms source into multiple distribution formats; runs linting and tests before release.
- Failure mode: Build output missing or corrupted; tests fail but build still publishes (if CI skipped); CDN delivery breaks if UMD wrapper malformed.
Data flow
User codeβconfetti(options)β User calls confetti() with animation options (duration, particle count, shapes, colors, gravity, etc.).
How to make changes
Add a new confetti animation preset or option
- Add new parameter to the confetti() function signature or to the options object in src/confetti.js (
src/confetti.js) - Implement physics logic (particle behavior, velocity, lifetime) for the new option within the particle update loop (
src/confetti.js) - Write unit test to validate new option behavior, particle trajectories, or rendering (
test/index.test.js) - Add example usage to demo fixture with visual validation (
fixtures/page.html) - Run
npm run build && npm run pretest && npm testto rebuild, bundle, minify, and validate (package.json)
Update the build output format or tooling
- Modify build script to add new output target, bundler, or transformation step (
build/build.js) - Update package.json main, module, or jsdelivr fields to point to new output files (
package.json) - Create or update fixture file to test the new bundle format (
fixtures/page.html) - Run
npm run build && npm run browserify && npm run minifyto verify all output variants (build/build.js)
Fix a bug or improve physics simulation
- Identify and reproduce the bug in a fixture or test (
fixtures/page.html) - Modify the particle system or animation loop logic in the main source (
src/confetti.js) - Add or update test cases to prevent regression (
test/index.test.js) - Run
npm run lint && npm testto ensure code quality and tests pass (package.json)
Why these technologies
- Canvas API β Direct pixel-level rendering provides performant animation without DOM reflow; ideal for thousands of particles.
- requestAnimationFrame β Synchronizes animation to browser refresh rate (60 FPS typically) for smooth motion and efficient battery usage.
- AVA test runner β Lightweight, fast test framework suitable for concurrent testing; serial mode enforces canvas/DOM state isolation.
- Browserify / Terser β Bundles and minifies for CDN distribution; supports multiple formats (UMD, ESM, browser-ready) for maximum compatibility.
Trade-offs already made
-
Single canvas element (global or reused) rather than per-confetti instance
- Why: Reduces DOM overhead and improves rendering performance when multiple confetti calls occur.
- Consequence: Multiple confetti calls share the same canvas, so particles from different calls composite together; cannot easily isolate or hide individual batches.
-
Physics simulation via simple gravity and drag rather than collision detection
- Why: Keeps computation lightweight; avoids O(nΒ²) particle interaction costs.
- Consequence: Particles pass through each other; no realistic collision behavior or stacking.
-
Particle lifetime fixed by initial options rather than dynamic removal by user code
- Why: Simplifies API and avoids callback overhead; animation fully automated.
- Consequence: User cannot programmatically stop or manually remove particles mid-animation.
-
No animation state exposed to user code (e.g., progress %, active particle count)
- Why: Keeps library lightweight and focused on firing-and-forgetting confetti.
- Consequence: Hard to synchronize confetti with external events or conditionally end animations early.
Non-goals (don't propose these)
- Real-time particle collision or interaction simulation.
- Server-side confetti rendering (library requires DOM/canvas; SSR tests only validate no errors, not visual output).
- Fine-grained control over individual particle lifecycle post-launch.
- Accessibility features (screen reader announcements, keyboard triggers) β purely visual, decorative effect.
- 3D or WebGL rendering β 2D canvas only.
Traps & gotchas
No required env vars or external services. However: (1) Tests require Puppeteer which downloads Chromium on install β can be slow on first run. (2) npm run dev uses build/serve.js which listens on a dynamic port; check terminal output for the actual URL. (3) The dist/ directory is generated by npm run build and not committed, so running npm run build before testing locally is mandatory. (4) ESLint config in test/.eslintrc.yml and build/.eslintrc.yml override the root config for those directories β be aware when adding new rules.
Architecture
Concepts to learn
- Canvas 2D Particle System β Core to understanding src/confetti.js: particles are simulated objects with position, velocity, and decay updated each frame and rendered to canvas β this pattern is foundational to all animation in the library
- Velocity Verlet Integration β The physics engine in src/confetti.js likely uses some form of numerical integration to update particle positions over time with gravity and drag β understanding this explains why particles follow realistic curves
- requestAnimationFrame (RAF) β src/confetti.js uses RAF for smooth 60fps animation synchronization instead of setTimeout/setInterval β critical to performance and visual smoothness
- Browserify/UMD Bundling β The build pipeline (build/build.js) uses Browserify to convert Node-style exports into UMD format for browser globals β required to understand multi-platform distribution
- prefers-reduced-motion Media Query β The library respects the CSS @media (prefers-reduced-motion) accessibility standard via disableForReducedMotion option β understanding this shows user-centric design for motion-sensitive users
- Visual Regression Testing β test/index.test.js uses Puppeteer + jimp to compare rendered canvas output against baseline images β this is non-trivial for animation testing and worth studying for pixel-perfect validation
- Server-Side Rendering (SSR) Compatibility β test/ssr.test.js indicates the library gracefully handles Node.js environments where canvas doesn't exist β understanding this guard pattern is useful for universal JavaScript libraries
Related repos
jashkenas/underscoreβ Utility library reference for minimal-dependency philosophy this repo exemplifiesmattdesl/canvas-sketchβ Companion tool for generative canvas art; users of canvas-confetti often combine it with custom canvas sketchespixijs/pixi.jsβ Heavy-weight alternative for complex particle systems using WebGL; canvas-confetti is lighter but PixiJS offers more advanced rendering controlsquirrelmaster/parcelsβ Similar celebratory particle effect library but with different physics; useful reference for alternate approaches to confetti animationwebpack/webpackβ Ecosystem tool mentioned in README as required for npm usage; understanding Webpack bundling helps with integrating canvas-confetti into larger projects
PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add browser compatibility matrix tests using Puppeteer
The repo has Puppeteer in devDependencies and fixture HTML files (fixtures/page.html, fixtures/page.module.html, fixtures/page.minified.html, fixtures/page.browserify.html) but no automated cross-browser testing. Currently test/index.test.js and test/ssr.test.js exist, but there's no visual regression or browser-specific rendering tests. This would catch canvas API compatibility issues across browsers and ensure the animation performs consistently.
- [ ] Create test/browser.test.js to use Puppeteer to load each fixture file
- [ ] Add screenshots/visual diff assertions comparing confetti rendering output
- [ ] Test across different canvas contexts (2D, WebGL if applicable) and browser APIs
- [ ] Integrate into pretest or citest npm scripts to run automatically
Add ESLint rule enforcement for src/confetti.js complexity and performance markers
The main source file src/confetti.js likely contains performance-critical code for the animation loop, but build/.eslintrc.yml and test/.eslintrc.yml exist separately from the root config. There's no specific linting ruleset for performance concerns (complexity thresholds, avoiding memory allocations in hot paths). Add a dedicated src/.eslintrc.yml with stricter rules to catch regressions.
- [ ] Create src/.eslintrc.yml with complexity limits and performance-focused rules
- [ ] Add rules like max-depth, max-nested-callbacks, and no-inner-declarations to prevent hidden performance issues
- [ ] Update lint npm script to explicitly include src/ with verbose output
- [ ] Document performance constraints in README or CONTRIBUTING guide
Add TypeScript definition file generation and type tests
The package is widely used (high npm downloads per badges) but there's no dist/confetti.d.ts or src/confetti.ts type definitions visible. With multiple export formats (main, module, jsdelivr), TypeScript users and IDE autocomplete are unsupported. Add type definitions and a type-checking test to ensure the API surface matches the implementation.
- [ ] Generate dist/confetti.d.ts manually or via JSDoc @typedef comments in src/confetti.js
- [ ] Create test/types.test.ts using tsd or similar to verify exported types match actual API
- [ ] Update package.json with 'types' field pointing to the generated .d.ts file
- [ ] Add TypeScript checking to the pretest or lint script using tsc --noEmit
Good first issues
- Add TypeScript type definitions (create src/confetti.d.ts) β the library is widely used but lacks .d.ts exports, blocking TypeScript users. Start by documenting the confetti() function signature and options object from src/confetti.js.
- Expand test coverage for edge cases in src/confetti.js: test particles with zero velocity, test canvas resize during animation, test repeated rapid calls to confetti(). Currently test/index.test.js focuses on happy paths.
- Document the physics model: add a PHYSICS.md file explaining gravity, drag coefficient, decay, and particle trajectory math in src/confetti.js. This lowers the barrier for contributors wanting to tune or extend particle behavior.
Top contributors
- @catdad β 96 commits
- @Bwc9876 β 2 commits
- @Gavin-Hofer β 1 commits
- @mozi47 β 1 commits
Recent commits
20eebadβ oops, forgot version update in the readme (catdad)5f77cdeβ bumping version to 1.9.4 (catdad)f0027c6β updating to use github action as trusted publisher (catdad)0566ad2β Merge pull request #258 from Gavin-Hofer/gavin/fix-offscreen-canvas-error (catdad)51e7932β Merge branch 'master' into gavin/fix-offscreen-canvas-error (catdad)c4385c8β Merge pull request #259 from catdad/actions-update (catdad)4bf60a5β updating linting to later versions that work in node 24 (catdad)0d755bcβ using latest version of node (catdad)664a8bbβ updating actions to the latest versions (catdad)c1748feβ Fixed error in canDrawBitmap if OffscreenCanvas exists but is not supported (Gavin-Hofer)
Security observations
The canvas-confetti repository has significant security concerns primarily related to severely outdated dependencies. Multiple devDependencies are 3-8 years old and likely contain known vulnerabilities, particularly jimp (v0.2.28 from 2016), terser (v3.14.1), and send (v0.16.1). The outdated babel-eslint increases the risk of missing security-related linting issues. While this is primarily a frontend animation library with minimal attack surface, the build toolchain and testing infrastructure should be modernized to reduce supply chain risks. No hardcoded secrets or injection
- High Β· Outdated Puppeteer Dependency β
package.json - devDependencies. puppeteer v19.11.1 is outdated and may contain known security vulnerabilities. Current versions are significantly newer (v20+), which include important security patches and bug fixes. Fix: Update puppeteer to the latest stable version (v21 or later) to ensure security patches are applied. Run 'npm update puppeteer' and test thoroughly. - High Β· Outdated Terser Dependency β
package.json - devDependencies. terser v3.14.1 is significantly outdated (released 2018). Current versions are v5.x+. This may contain known vulnerabilities and lacks modern security improvements. Fix: Update terser to the latest stable version (v5.x). Review breaking changes and update build configuration accordingly. - High Β· Outdated jimp Dependency β
package.json - devDependencies. jimp v0.2.28 is extremely outdated (2016 release). Current versions are v0.16.x+. Old image processing libraries may have unpatched security vulnerabilities. Fix: Update jimp to the latest stable version (v0.16.x or later). Test image processing functionality thoroughly after upgrade. - Medium Β· Outdated Send Dependency β
package.json - devDependencies. send v0.16.1 is outdated (2017). Current versions are v0.18.x+. HTTP serving libraries should be kept current for security fixes. Fix: Update send to the latest stable version (v0.18.x). Verify compatibility with build/serve.js. - Medium Β· Outdated Browserify Dependency β
package.json - devDependencies. browserify v15.2.0 is outdated. Current versions are v17+. Module bundlers should be kept current for security and compatibility. Fix: Update browserify to the latest stable version. Test bundled output thoroughly. - Medium Β· Outdated ESLint Configuration β
package.json - devDependencies, .eslintrc.yml. babel-eslint v8.2.1 is outdated and deprecated. ESLint now recommends @babel/eslint-parser. This may cause parsing issues and miss security-related linting rules. Fix: Replace babel-eslint with @babel/eslint-parser and update .eslintrc.yml parser configuration. - Low Β· Outdated AVA Test Runner β
package.json - devDependencies. ava v2.4.0 is significantly outdated (2019). Current versions are v5.x+. Outdated test runners may lack security improvements and new features. Fix: Update ava to the latest stable version (v5.x). Review migration guide and update test configuration if needed. - Low Β· No SBOM or Dependency Pinning β
package.json. package.json uses flexible version ranges (^, ~) for many devDependencies. This allows automatic updates that could introduce breaking changes or vulnerabilities without explicit review. Fix: Consider using npm shrinkwrap or package-lock.json lock file for reproducible builds. Review critical dependencies regularly. - Low Β· No Security Policy Document β
Repository root. No SECURITY.md file found. Users and security researchers have no clear channel for reporting vulnerabilities. Fix: Create a SECURITY.md file with vulnerability disclosure policy and responsible disclosure guidelines.
LLM-derived; treat as a starting point, not a security audit.
Where to read next
- Open issues β current backlog
- Recent PRs β what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals β see the live page for receipts. Re-run on a new commit to refresh.