Canvas Particles JS

A smooth yet efficient particle renderer. All in an HTML canvas.

Installation

  • npm

    View the package on npm: canvasparticles-js.

    NPM downloads
    Console
    npm install canvasparticles-js

    ES Module import

    ESM
    import CanvasParticles from 'canvasparticles-js'

    If you don't have a bundler:

    ESM
    import CanvasParticles from './node_modules/canvasparticles-js/canvasParticles.js'

    Global import

    HTML
    <script src="./node_modules/canvasparticles-js/canvasParticles.js" defer></script>

    No import required in each JavaScript file!

Start animating

Documentation: README.md

Options documentation: README.md#options

JavaScript
const selector = '#my-canvas'
const options = {}
new CanvasParticles(selector, options).start()

Showcase

Default

Instantiation of the CanvasParticles class with the default options.

JavaScript
const showcaseDefault = new CanvasParticles('#showcase-default').start()

Start and stop the animation.

Stop
showcaseDefault.stop()
Stop (no clear)
showcaseDefault.stop({clear: false})
Start
showcaseDefault.start()

Coloring

Setting the canvas and the particle colors.

JavaScript
new CanvasParticles('#showcase-coloring', {
  // Any CSS Supported value for the 'background' property
  background: 'rgb(21, 16, 25)',
  particles: {
    // Any CSS Supported color
    color: 'hsl(206, 100%, 77%)',
  },
}).start()

Interaction

Choose how the mouse can interact.

Info Setting mouse.distRatio below 1 allows particles to stick.

Important When using Stick, set particles.maxWork below 30 to prevent performance drops when collecting all particles in one place.

JavaScript
new CanvasParticles('#showcase-interact', {
  mouse: {
    interactionType: 2,
    connectDistMult: 0.8,
    distRatio: 0.7,
  },
  particles: {
      maxWork: 20,
  },
}).start()

Quantity

Define the amount of particles by setting particles.ppm.

Info ppm = Particles Per Million pixels the canvas covers.

JavaScript
new CanvasParticles('#showcase-quantity', {
  mouse: {
    connectDistMult: 1,
  },
  particles: {
    ppm: 250,
    max: 300,
  },
}).start()

Connect distance

Define the maximum length of a connection.

JavaScript
new CanvasParticles('#showcase-connect-distance', {
  background: 'linear-gradient(100deg, #f80, #0f8 150%)',
  mouse: {
    interactionType: 2,
    connectDistMult: 0.3,
    distRatio: 1,
  },
  particles: {
    connectDistance: 400,
  },
}).start()

Movement

Customize the movement of the particles.

JavaScript
new CanvasParticles('#showcase-movement', {
  particles: {
    relSpeed: 3,
    relSize: 2,
    rotationSpeed: 40,
  },
}).start()

Pushing Gravity

Important Gravity requires heavy calculations.

JavaScript
new CanvasParticles('#showcase-pushing-gravity', {
  particles: {
    connectDistance: 175,
  },
  gravity: {
    repulsive: 3,
    fricion: 0.995,
  },
}).start()

Pulling Gravity

Also requires repulsive gravity to avoid forming a singularity.

JavaScript
const showcasePullingGravity =
new CanvasParticles('#showcase-pulling-gravity', {
  mouse: {
    interactionType: 2,
    distRatio: 1,
  },
  particles: {
    maxWork: Infinity
    relSpeed: 0,
  },
  gravity: {
    repulsive: 8.25,
    pulling: 3,
  },
})
Reset
showcasePullingGravity.newParticles()
Prevent heavy load
showcasePullingGravity.options.particles.maxWork = 12

Hue Rotation Effect

Use JavaScript to edit options on the fly.

JavaScript
const showcaseHueRotation =
new CanvasParticles('#showcase-hue-rotation', {
  background: 'var(--bg)',
  particles: {
    color: 'hsl(0, 100%, 50%)'
  },
}).start()
Rotate hue
setInterval(() => {
  const color = `hsl(${hue++}, 100%, 50%)`
  hue %= 360
  showcaseHueRotation.setParticleColor(color)
}, 20)

Multiple Colors

Overlap multiple <canvas> elements using CSS and initialize each one seperately.

JavaScript
new CanvasParticles('#showcase-multiple-colors-1', {
  background: 'black',
  particles: {
    color: 'yellow',
  },
}).start()

new CanvasParticles('#showcase-multiple-colors-2', {
  background: 'transparent',
  particles: {
    color: 'aqua',
  },
}).start()

Sandbox

Presets

JavaScript (editable)
options = {}

Options documentation: README.md#options

JavaScript
new CanvasParticles('#cp-sandbox', options).start()

Information

Handling particles beyond canvas bounds

Particles are only drawn if they are within the visible area of the canvas, accounting for their size. Particles are considered to still be visible if their edges are within the canvas bounds, preventing large particles from disappearing when their center crosses the edge.

When particles move beyond the floating area bounds, they will teleport to the opposite side.

Handling particle connections beyond canvas bounds

The floating area for the particles is larger than the canvas bounds to ensure no lines between particles will suddenly dissapear near the edges. The floating space added to all 4 sides is exactly equal to the maximum length of a line, defined with options.particles.connectDist.

By default, a line is not drawn between particles if both are outside the visible canvas area.

Each particle's grid position is calculated based on its location relative to the visible canvas area. This allows for determining whether two particles, even when outside the canvas, should have a connecting line drawn between them because part of it can still be seen.

Performance optimizations

Canvas Particles JS is a highly optimized particle renderer (ignoring the fact that it's coded in JS). A lot of time has gone into profiling the code and improving efficiency on expensive tasks.

An IntersectionObserver is used to pause and resume the animation based on if the canvas is within the viewbox

Particles smaller than one pixel are drawn as squares instead of circles which is ±183% faster.

Dynamically generating the fillStyle combinations for each connection in every frame is the most expensive task. It's about 5x faster to precomputing all 256 particle colors, accounting only for varying opacity levels, and storing them in a lookup table.

Contact me

Do you think something is missing or did you spot a (small) mistake?
Don't hesitate to reach out and send me an email at:

kyle.hoeckman@gmail.com
document icon document icon