Troubleshooting & FAQ
Particles not showing up
Particles fail to render even though you followed the quick-start example.
Check the following:
Engine not initialized — You must call a
load*function (e.g.loadFull,loadSlim,loadBasic) beforetsParticles.load(). Without it the engine has no shapes, moves, or interactions registered.typescriptimport { tsParticles } from "@tsparticles/engine"; import { loadBasic } from "@tsparticles/basic"; await loadBasic(tsParticles); await tsParticles.load({ id: "tsparticles", options: { /* ... */ }, });Container element missing — The element with the
idyou pass must exist in the DOM before you callload.Zero particle count — Check
particles.number.valuein your options. The default is0in some configs.Canvas fully transparent — If particles use
opacity: 0or a color that matches the background, they become invisible.Errors in browser console — Open DevTools and look for error messages. Most issues log a clear description.
SSR (Server-Side Rendering) errors
Next.js, Nuxt, or other SSR frameworks throw window is not defined or document is not defined.
tsParticles depends on browser APIs (window, document, canvas). You must:
- Next.js: Use
dynamic(() => import(...), { ssr: false })to load the particles component. - Nuxt: Register the tsParticles plugin in a client-only context (
plugins/withmode: 'client'). - Astro: Use the
client:onlydirective on the component. - VitePress / Vitepress: tsParticles components should be used in
.vuefiles with<ClientOnly>wrapper.
See the Next.js guide, Nuxt guide, or Astro guide for framework-specific solutions.
Slow performance or low FPS
Particles animation is GPU-heavy. Here is how to keep it smooth:
- Lower particle count —
particles.number.value. Start with50and increase gradually. - Reduce size — Smaller particles use less fill work. Set
particles.size.valuebetween2and5. - Disable move or use slow speed —
particles.move.speed: 0.5instead of2. - Reduce link distance —
particles.links.distanceandparticles.links.opacityaffect link rendering cost. - Use the
@tsparticles/plugin-motionplugin — themotion.reduce.valueoption serves a lighter config when the user prefers reduced motion. The plugin is included in@tsparticles/allonly; for other bundles load it separately. - Set FPS limit via options — use
fpsLimitin the root options object (default120).
TypeScript type errors
Cannot find @tsparticles/react types or similar.
Install the engine types as a dev dependency:
npm install @tsparticles/engine --save-devThen import types from the engine:
import type { ISourceOptions, Engine } from "@tsparticles/engine";How do I access the container instance?
The load method returns a Promise<Container>. Save the reference:
const container = await tsParticles.load({ id: "myParticles", options });
// Later
container.pause();
container.play();
container.refresh();In framework wrappers, use the callback or ref:
- React:
<Particles id="tsparticles" options={...} particlesLoaded={async (container) => { /* ... */ }} /> - Vue 3: The component emits
@particles-loaded. - Angular: The
(particlesLoaded)output event.
How do I handle click / hover events?
Use the interactivity options in the config:
interactivity: {
events: {
onClick: { enable: true, mode: "push" },
onHover: { enable: true, mode: "repulse" },
},
modes: {
push: { quantity: 4 },
repulse: { distance: 100 },
},
},If you need a custom callback, listen on the engine:
tsParticles.addEventListener("click", () => {
// your logic
});The engine emits these event types: configAdded, containerInit, particlesSetup, containerStarted, containerStopped, containerDestroyed, containerPaused, containerPlay, containerBuilt, particleAdded, particleDestroyed, particleRemoved.
Images not appearing as particles
Load the image shape plugin — The
preloadoption and theimageshape require the@tsparticles/shape-imageplugin. It is included in@tsparticles/slimand above.Set the shape to
image:typescriptparticles: { shape: { type: "image" }, },Preload images so they are ready before rendering:
typescriptpreload: [ { src: "path/to/image.png", width: 32, height: 32 }, ],Images must be accessible — check for CORS errors in the console if the image is on a different origin.
How do I make particles responsive?
Use the responsive array in the options. This requires loading the @tsparticles/plugin-responsive plugin (included in @tsparticles/all only):
responsive: [
{
maxWidth: 768,
options: {
particles: { number: { value: 30 } },
},
},
],You can also use the @tsparticles/plugin-motion plugin to serve a reduced config when the user's device prefers reduced motion:
motion: {
disable: false,
reduce: {
value: true, // use reduced config when prefers-reduced-motion is set
factor: 0.5, // multiplies number.value by this factor
},
},How do I update options after initialization?
Call tsParticles.load() again with the new options. The engine will replace the existing container configuration:
await tsParticles.load({ id: "tsparticles", options: newOptions });In React, simply pass new options via props — the component handles it automatically.
Why does loadFull make the bundle so large?
loadFull loads every shape, updater, interaction, and plugin. If you only need a subset, use loadSlim or loadBasic and import only what you need:
import { loadSlim } from "@tsparticles/slim"; // common features
import { loadBasic } from "@tsparticles/basic"; // minimal
// Then add specific plugins
import { loadPolygonMaskPlugin } from "@tsparticles/plugin-polygon-mask";See the Bundles overview for a detailed comparison.
How do I install a specific version?
npm install tsparticles@4.2.0
npm install @tsparticles/react@4.2.0Check the Releases page for version history and changelogs.
