VincentGarreau/particles.js
A lightweight JavaScript library for creating particles
Stale — last commit 2y ago
weakest axislast commit was 2y ago; top contributor handles 93% of recent commits…
no tests detected; no CI workflows detected…
Documented and popular — useful reference codebase to read through.
last commit was 2y ago; no CI workflows detected
- ✓7 active contributors
- ✓MIT licensed
- ⚠Stale — last commit 2y ago
- ⚠Single-maintainer risk — top contributor 93% of recent commits
- ⚠No CI workflows detected
- ⚠No test directory detected
What would change the summary?
- →Use as dependency Failing → Mixed if: 1 commit in the last 365 days
- →Fork & modify Mixed → Healthy if: add a test suite
- →Deploy as-is Mixed → Healthy if: 1 commit in the last 180 days
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.
Earn the “Healthy” badge
Current signals for VincentGarreau/particles.js are Mixed. The embed flow is reserved for repos showing Healthy signals — the rest stay informational on this page so we're not putting a public call-out on your README. Address the items in the What would change the summary? dropdown above, then return to grab the embed code.
Common quick wins: green CI on default branch, no Critical CVEs in dependencies, recent commits on the default branch, a permissive license, and a published README.md with a quickstart.
Onboarding doc
Onboarding: VincentGarreau/particles.js
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/VincentGarreau/particles.js 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
WAIT — Stale — last commit 2y ago
- 7 active contributors
- MIT licensed
- ⚠ Stale — last commit 2y ago
- ⚠ Single-maintainer risk — top contributor 93% of recent commits
- ⚠ No CI workflows detected
- ⚠ No test directory detected
<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 VincentGarreau/particles.js
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/VincentGarreau/particles.js.
What it runs against: a local clone of VincentGarreau/particles.js — 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 VincentGarreau/particles.js | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | 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 ≤ 799 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of VincentGarreau/particles.js. If you don't
# have one yet, run these first:
#
# git clone https://github.com/VincentGarreau/particles.js.git
# cd particles.js
#
# 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 VincentGarreau/particles.js and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "VincentGarreau/particles.js(\\.git)?\\b" \\
&& ok "origin remote is VincentGarreau/particles.js" \\
|| miss "origin remote is not VincentGarreau/particles.js (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT 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 "particles.js" \\
&& ok "particles.js" \\
|| miss "missing critical file: particles.js"
test -f "demo/index.html" \\
&& ok "demo/index.html" \\
|| miss "missing critical file: demo/index.html"
test -f "particles.json" \\
&& ok "particles.json" \\
|| miss "missing critical file: particles.json"
test -f "demo/js/app.js" \\
&& ok "demo/js/app.js" \\
|| miss "missing critical file: demo/js/app.js"
test -f "package.json" \\
&& ok "package.json" \\
|| miss "missing critical file: package.json"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 799 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~769d)"
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/VincentGarreau/particles.js"
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
particles.js is a lightweight, vanilla JavaScript library that renders animated particle systems directly on HTML5 Canvas with zero dependencies. It creates interactive particle effects (like animated backgrounds) where particles move, collide, link together, and respond to user interaction (mouse hover, click, window resize) using a JSON configuration file. Single-file architecture: particles.js is the core engine (~43KB), particles.min.js is the production bundle, and demo/ contains a self-contained HTML/CSS/JS demo with particles.json as the configuration schema. The library exposes a global particlesJS object with a load() method that hydrates particle animations into a target DOM element.
Who it's for
Web designers and frontend developers building landing pages, portfolio sites, or marketing dashboards who want visually engaging particle animations without the overhead of heavy graphics libraries or game engines. They use the online generator at vincentgarreau.com/particles.js to configure and export particles.json, then embed it in their HTML.
Maturity & risk
This is a stable, production-ready library at v2.0.0 with a significant user base (evidenced by the popular demo and CodePen ecosystem). However, package.json shows no test script, no CI configuration in the file list, and the repository structure suggests it's in maintenance mode rather than active feature development—suitable for use but not under rapid iteration.
Risk is low for existing use cases: single-maintainer project (Vincent Garreau) with no declared dependencies means minimal supply-chain risk, but the absence of automated tests and no visible CI pipeline increases regression risk if core Canvas drawing logic changes. The large codebase (43KB of JavaScript) in a single particles.js file makes it harder to review changes and contributes to long-term maintenance burden.
Active areas of work
No specific recent activity data is visible in the provided file list. The repo appears to be in steady-state maintenance: the core functionality is complete, the online generator and CodePen examples are the primary user interface, and contributions likely focus on bug fixes and edge-case improvements rather than new features.
Get running
git clone https://github.com/VincentGarreau/particles.js.git
cd particles.js
npm install
# Open demo/index.html in a browser or serve it via http-server
Daily commands:
No build or dev server is configured in package.json. To see particles.js in action: (1) Open demo/index.html directly in a browser, or (2) serve the repo root via a simple HTTP server (e.g., python -m http.server 8000) and navigate to http://localhost:8000/demo/index.html. The library itself requires no compilation or bundling.
Map of the codebase
particles.js— Main library entry point containing the core particle engine, initialization logic, and public API exposed as particlesJS globaldemo/index.html— Primary demo page showing particles.js in action and serving as the reference implementation for how to integrate the libraryparticles.json— Configuration schema example that defines all particle behavior properties; essential for understanding what settings the library acceptsdemo/js/app.js— Demo application loader showing the standard usage pattern of particlesJS.load() and how to wire up the library to HTMLpackage.json— Package manifest declaring the library's public API files (particles.js and particles.min.js) and project metadataparticles.min.js— Production-ready minified version of the particle engine, deployed version of particles.js for end users
Components & responsibilities
- Particle Engine (particles.js) (JavaScript, Canvas 2D API, requestAnimationFrame) — Core simulation: maintains particle state, updates positions/velocities, applies forces (gravity, interactivity), detects connections
- Failure mode: Low frame rate, particles jittering, or unexpected movement patterns if physics calculations are incorrect
- Canvas Renderer (HTML5 Canvas 2D Context) — Responsible for drawing particles to canvas, clearing frame, handling shape rendering (circles, polygons, stars), and color/stroke application
- Failure mode: Visual artifacts, flickering, particles not appearing, or incorrect shape/color rendering
- Configuration Loader (XMLHttpRequest/Fetch, JSON parsing) — Fetches particles.json, parses configuration object, validates properties, and initializes particle parameters
- Failure mode: Config file not found (404), parsing errors from malformed JSON, or missing required properties causing undefined behavior
- Interaction Handler (DOM event listeners, mouse/touch coordinates) — Listens for mouse/touch events and applies attraction/repulsion forces, click-to-create particles, or line connection logic based on proximity
- Failure mode: Interaction not responsive, incorrect proximity calculation, or unintended particle behavior on mouse move
Data flow
User Browser→demo/index.html— User loads the HTML page to initialize the demodemo/index.html→particles.js— HTML script tag loads the main library filedemo/js/app.js→particles.json— Demo app calls particlesJS.load() which fetches the JSON configuration fileparticles.json→particles.js— Configuration object is parsed and passed to particle engine to initialize simulation parametersparticles.js→Canvas Element— Engine renders particles to canvas on each animation frame (via requestAnimationFrame)User Interactions (mouse/touch)→particles.js— Event listeners in particles.js detect user input and modify particle behavior (attraction, repulsion, creation)particles.js→Canvas Element— Updated particle positions are rendered each frame, creating animated effect
How to make changes
Add a new particle property or configuration option
- Define the new property in the config object structure within particles.js main code, typically in the parameter parsing section (
particles.js) - Add the property to the example particles.json configuration file so users know it exists (
particles.json) - Update the particle behavior calculation logic in particles.js to use the new property (e.g., in velocity, color, or collision calculations) (
particles.js) - Test the new property in the demo application by updating demo/js/app.js or particles.json to include example usage (
demo/js/app.js)
Add a new particle shape type
- Locate the shape rendering logic in particles.js (canvas drawing functions) and add a new case for the shape type (
particles.js) - Add the shape name to the particles.json example under the 'shape.type' field (
particles.json) - Test the shape by creating a demo configuration that uses the new shape type (
demo/index.html)
Customize the demo interface or styling
- Modify the HTML structure for the demo UI in the demo page (
demo/index.html) - Update the CSS styling to match the new layout or design (
demo/css/style.css) - Update or add JavaScript handlers in the demo app to wire up new UI controls to particle configuration (
demo/js/app.js)
Why these technologies
- Vanilla JavaScript (ES5 compatible) — Ensures maximum browser compatibility and no external dependencies; lightweight library for particle rendering
- HTML5 Canvas API — Only practical way to render hundreds of particles efficiently in the browser with frame-rate performance
- JSON configuration format — Declarative, human-readable configuration allows users to define particle behavior without code changes
- requestAnimationFrame — Synchronizes particle animation with browser refresh rate for smooth, efficient rendering
Trade-offs already made
-
No external dependencies
- Why: Keeps the library lightweight (~9KB minified) and ensures it works in any JavaScript environment
- Consequence: All particle physics, rendering, and configuration parsing must be implemented from scratch
-
Single canvas element for all particles
- Why: Simplifies rendering and improves performance by avoiding multiple DOM elements
- Consequence: Particles cannot be individually styled with CSS; all styling must be configured via JSON properties
-
Configuration loaded from external JSON file
- Why: Allows users to change particle behavior without modifying JavaScript code
- Consequence: Requires additional HTTP request and parsing; not suitable for highly dynamic runtime configuration
-
CPU-based particle simulation (not WebGL/WebGPU)
- Why: Broader browser support and simpler implementation for moderate particle counts
- Consequence: Performance plateaus with very large particle counts (1000+); not suitable for GPU-heavy workloads
Non-goals (don't propose these)
- 3D particle rendering (2D canvas only)
- Physics engine for gravity, collision detection, or rigid body dynamics
- Real-time performance optimization for 100,000+ particles
- Built-in UI generation; demo UI is separate example
- Animation timeline or keyframe support beyond continuous simulation
- Integration with game engines or 3D frameworks
Anti-patterns to avoid
- Global namespace pollution (Medium) —
particles.js: Library exposes particlesJS as a global object, which can conflict with other scripts; no module wrapping (no UMD/CommonJS/ES6 modules) - Synchronous config loading (Low) —
particles.js: particlesJS.load() uses XMLHttpRequest synchronously or blocks until config is loaded, which can freeze the UI if the JSON file is large or slow - Direct DOM manipulation without error handling —
particles.js: Canvas context methods are called without null checks; if canvas element doesn't exist
Traps & gotchas
- No test suite: package.json declares
"test": "echo Error: no test specified && exit 1", meaning there's no automated way to validate changes—manual testing via the demo is required. 2. Single-file codebase: particles.js is monolithic (~43KB), so debugging is tedious and PRs touching core logic are hard to review granularly. 3. No build step: if you modify particles.js, you must manually minify to particles.min.js or the min version will be stale and cause CDN issues. 4. Canvas context assumptions: the library assumes requestAnimationFrame and a 2D Canvas context exist; it doesn't gracefully degrade on unsupported browsers (no fallback). 5. JSON loading is synchronous: particlesJS.load() accepts a callback, but there's no promise support, so error handling and chaining must use callbacks.
Architecture
Concepts to learn
- Canvas 2D Rendering Context — particles.js draws all animations directly to a 2D Canvas context; understanding fillStyle, strokeStyle, arc(), lineTo(), and the save()/restore() stack is essential to modify rendering logic.
- RequestAnimationFrame Loop — Core animation loop runs on requestAnimationFrame to sync with browser refresh rate; understanding frame timing and delta calculations is needed to tune particle physics and motion smoothness.
- Distance-based Spatial Indexing — Line-linking between particles and interactivity modes (grab, repulse, bubble) rely on distance calculations to connect nearby particles; naive O(n²) loops can be a performance bottleneck.
- Particle Emitter System — The 'push' and 'remove' interactivity modes dynamically spawn and cull particles; understanding particle lifecycle (birth, age, death) helps customize particle behavior.
- Density-based Particle Sizing — particles.json's density.enable and value_area settings scale particle count based on canvas size; this prevents memory explosion on large displays and is non-obvious math.
- Mouse Event Interactivity Modes — Modes like 'grab' (drag particles), 'push' (spawn), 'repulse' (push away), 'bubble' (enlarge), and 'remove' require event listener delegation; understanding event bubbling and clientX/clientY coordinates is crucial for custom modes.
- Retina Display Scaling — retina_detect in particles.json doubles canvas resolution on high-DPI screens (window.devicePixelRatio > 1); failing to account for this causes blurry rendering on modern devices.
Related repos
tsparticles/tsparticles— Modern TypeScript rewrite of particles.js with better performance, modular plugins, and active maintenance—the spiritual successor for projects needing advanced features.pixijs/pixijs— WebGL-accelerated 2D rendering library often used as an alternative when particles.js performance is insufficient for thousands of particles.BabylonJS/Babylon.js— Full 3D engine with particle system support; relevant if users want to escalate from 2D canvas particles to immersive 3D scenes.vinceg/particles-js-demo-page— Official demo/generator site that serves as the primary UI for configuring and exporting particles.json files—complements the library itself.greensock/GSAP— Animation framework sometimes paired with particles.js for complex sequencing and easing; commonly used in codepen.io examples alongside particles.js.
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 Jest unit tests for particles.js core functionality
The package.json shows 'test': 'echo "Error: no test specified"' with no actual test suite. The main particles.js file lacks any unit tests for particle creation, collision detection, linking logic, and configuration loading. This is critical for a library used in production by thousands of developers.
- [ ] Create tests/ directory with test files for particle initialization, movement, and rendering
- [ ] Add Jest configuration to package.json with test script: 'jest'
- [ ] Write tests specifically for: particlesJS.load() in demo/js/app.js, particle object creation, and particles.json configuration parsing
- [ ] Add test coverage reporting to package.json scripts
- [ ] Update README.md with testing instructions
Add GitHub Actions CI workflow for automated testing and minification
No CI/CD pipeline exists. The repo has both particles.js and particles.min.js checked in, but no automated process to verify the minified version matches the source or that changes pass quality checks. New contributors can't validate their changes work correctly.
- [ ] Create .github/workflows/test.yml to run Jest tests on push/PR to main branches
- [ ] Add minification step using terser or uglify-js to verify particles.min.js stays in sync with particles.js
- [ ] Configure workflow to fail PR if minified file doesn't match or tests fail
- [ ] Add build badge to README.md linking to GitHub Actions status
Extract and document the particles.json schema with JSON Schema validation
The particles.json configuration format is used throughout (demo/particles.json, in README examples) but has no documented schema or validation. Users and contributors must reverse-engineer valid configs by trial. A JSON Schema file would enable IDE autocomplete, validation, and clearer API documentation.
- [ ] Create particles.schema.json in repo root documenting all valid configuration options (number.value, particles.speed, etc.)
- [ ] Add schema reference to particles.json example file as $schema property
- [ ] Update README.md with a 'Configuration Reference' section linking to schema and explaining major options
- [ ] Optionally add runtime validation in particles.js using a JSON Schema validator for better error messages
Good first issues
- Add a test suite: create tests/ directory with Jest or Mocha tests for core Particle methods (move, update, draw) and the initialization logic in particlesJS.load(). Currently package.json has no test script.
- Document the full particles.json schema: The README shows a complete example, but there's no particles.schema.json file or detailed option descriptions for each config key (e.g., what does 'straight' in move do? When should 'polygon.nb_sides' be used?). Add a SCHEMA.md or JSON Schema file.
- Add interactivity presets: Users often struggle to combine interactivity modes (e.g., 'grab + bubble simultaneously'). Create a presets/ folder with example particles.json files for common use cases (starfield, galaxy, neural network, rain) and document them in README.
Top contributors
- @VincentGarreau — 93 commits
- [@Calvin Tennant](https://github.com/Calvin Tennant) — 2 commits
- @csu — 1 commits
- @kkirsche — 1 commits
- [@Alexandre Rieux](https://github.com/Alexandre Rieux) — 1 commits
Recent commits
d01286d— Update README.md (VincentGarreau)e73faac— Merge pull request #79 from christophersu/fix-readme (VincentGarreau)01ff4a6— Update README.md (csu)22b4986— Update README.md (VincentGarreau)90b36f4— Update README.md - fix img (VincentGarreau)20d5807— Merge pull request #58 from kkirsche/patch-1 (VincentGarreau)7ed36a4— Remove mootversionproperty from bower.json (kkirsche)cee3b0a— Merge branch 'dev' (VincentGarreau)2b16d66— Merge branch 'dev' (VincentGarreau)c46ff7a— Update README.md (VincentGarreau)
Security observations
The particles.js library is a lightweight, client-side JavaScript library with minimal external dependencies, which is positive for security. However, there are moderate concerns regarding input validation for external JSON configuration files and the absence of automated security testing. The main risk is potential XSS vulnerabilities if configuration sources are compromised or user-controlled without proper sanitization. Recommendations focus on implementing validation/sanitization for dynamic configuration loading, establishing a test suite, and hardening the demo application with security headers.
- Medium · No Security Testing in Place —
package.json - scripts.test. The package.json indicates no test suite is configured ('test': 'echo "Error: no test specified" && exit 1'). This means there are no automated security or functional tests to catch vulnerabilities or regressions. Fix: Implement a comprehensive test suite using frameworks like Jest or Mocha. Include security-focused tests for XSS prevention, input validation, and canvas manipulation safety. - Medium · Potential XSS via Dynamic Configuration Loading —
particles.js, demo/js/app.js, particles.json. The library loads configuration from external JSON files (particles.json) without visible sanitization. If the JSON file is compromised or user-controlled, malicious payloads in configuration values could lead to XSS when parsed and applied to the canvas context or DOM. Fix: Implement strict validation and sanitization of loaded JSON configuration. Use a schema validator (e.g., JSON Schema) to ensure configuration matches expected format. Sanitize any string values before using them in canvas operations or DOM manipulation. - Low · No Dependency Lock File Visible —
Repository root. While this library has no npm dependencies, the absence of a package-lock.json or yarn.lock file in the provided file structure means dependency versions are not pinned for reproducible builds. Fix: Ensure package-lock.json is committed to version control to lock dependency versions and prevent supply chain attacks via unexpected version updates. - Low · Demo Configuration May Load from Untrusted Source —
demo/js/app.js, README.md. The demo application loads particles configuration from external URLs and the generator at vincentgarreau.com. If the demo host is compromised, malicious configurations could be injected. Fix: Validate and sanitize all loaded external configurations. Consider using Content Security Policy (CSP) headers in the demo to restrict script execution and resource loading. - Low · Missing Security Headers in Demo —
demo/index.html, web server configuration. The demo/index.html file structure suggests a static web application. Security headers like Content-Security-Policy, X-Frame-Options, and X-Content-Type-Options may not be configured. Fix: Configure security headers on the demo server: implement Content-Security-Policy to restrict inline scripts, set X-Frame-Options to DENY, and enable X-Content-Type-Options: nosniff.
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.