Performance Optimization Guide
tsParticles Ribbons is designed to be fast out of the box. However, understanding how the animation pipeline works and following a few best practices can help you maintain smooth 60fps rendering even on lower-end devices. This guide covers everything you need to know about ribbon animation performance.
How Ribbon Rendering Works
Under the hood, tsParticles Ribbons uses the HTML5 Canvas 2D API. Each ribbon is a series of connected bezier curves that follow a physics simulation. The rendering pipeline involves three main stages:
- Physics update: Each ribbon's position, velocity, rotation, and opacity are calculated based on gravity, drag, and decay parameters. This happens on the main thread.
- Canvas drawing: Updated ribbon paths are drawn to a Canvas element using bezier curves and gradient fills. Modern browsers hardware-accelerate this step.
- Composition: The canvas is composited over your page content using CSS positioning and opacity.
The most expensive operation is typically the canvas drawing step, especially when ribbons are long and have many segments. Understanding this helps you make informed decisions about configuration.
Limit Simultaneous Animations
Each call to ribbons() creates a burst of ribbons. Multiple simultaneous bursts
multiply the rendering workload. Here's a practical guideline:
// Good: Stagger bursts to avoid peak load
ribbons();
setTimeout(() => ribbons(), 300);
setTimeout(() => ribbons(), 600);
// Better: Use fewer, larger bursts instead
ribbons({
count: 50, // spawn more ribbons per burst
});
On desktop browsers, 2-3 simultaneous bursts typically maintain 60fps without issues. On
mobile devices, limit yourself to 1-2 concurrent animations. If you need more ribbons,
increase the count option rather than calling ribbons() multiple
times.
Use Custom Canvas for Section Animations
Full-screen canvas overlays are convenient but wasteful when you only need ribbons in a specific area. Using a custom canvas reduces the drawing area significantly:
// Instead of full-screen ribbons
const canvas = document.getElementById('hero-canvas');
const shoot = await ribbons.create(canvas, {
zIndex: 0,
});
// Only the hero section needs animation
shoot();
A custom canvas that covers 20% of the viewport uses roughly 80% less GPU memory than a full-screen canvas. This is especially important on mobile devices where GPU memory is limited.
Control Ribbon Count
The number of individual ribbons in a burst directly affects rendering performance. Each ribbon is an independent path that must be drawn every frame. The default count is tuned for visual appeal, but you can reduce it for better performance:
ribbons({
count: 15, // fewer ribbons, less GPU work
});
Reducing from 30 to 15 ribbons typically improves frame rates by 20-30% on lower-end devices while still providing a visually satisfying effect.
Animation Duration
Longer animations mean more frames to render. Keep animation durations reasonable:
- Click effects: 3-5 seconds is ideal for button-triggered bursts
- Page load animations: 5-8 seconds provides a nice entrance without overstaying its welcome
- Background effects: Use shorter intervals (200-300ms) with moderate duration (8-12 seconds)
For continuous background animations, consider using
requestAnimationFrame instead of setInterval to stay in sync with
the browser's render cycle:
const duration = 8000;
const animationEnd = Date.now() + duration;
function spawn() {
if (Date.now() >= animationEnd) return;
ribbons();
requestAnimationFrame(() => {
setTimeout(spawn, 260);
});
}
spawn();
Mobile Optimization
Mobile devices have less powerful GPUs and tighter memory constraints. Follow these guidelines for mobile-friendly ribbons:
- Use fewer ribbons per burst (10-15 instead of 20-30)
- Limit to one burst at a time on mobile
- Use custom canvases instead of full-screen overlays
- Set shorter animation durations (3-5 seconds)
- Avoid continuous animations on mobile — prefer user-triggered effects
You can detect mobile devices and adjust settings accordingly:
const isMobile = window.matchMedia('(max-width: 768px)').matches;
ribbons({
count: isMobile ? 12 : 25,
});
Avoiding Layout Thrashing
Ribbon canvases are positioned using CSS. Avoid forcing layout recalculations during animations by:
-
Using
position: fixedorposition: absolutefor ribbon canvases (avoids affecting document flow) -
Setting
pointer-events: noneon the canvas so it doesn't interfere with click handling -
Using
will-change: transformortransform: translateZ(0)to promote the canvas to its own compositor layer
tsParticles handles most of these optimizations automatically, but if you're using custom canvases, ensure these CSS properties are set.
Measuring Performance
Use your browser's DevTools to monitor animation performance:
- Chrome DevTools Performance panel: Record a session while ribbons are running and look for dropped frames in the frame rate chart
- Layers panel: Check how many compositor layers are being created — each ribbon canvas should be a single layer
- Lighthouse: Run a performance audit to identify any JavaScript execution bottlenecks
A well-optimized ribbon animation should use less than 5ms of CPU time per frame, leaving plenty of budget for your page content and interactions.
Summary
Performance optimization for ribbon animations comes down to three principles: minimize the rendering area, limit concurrent animations, and keep ribbon counts reasonable. Following the guidelines in this guide will ensure smooth, jank-free ribbon animations across all devices.
For more tips, check out the customization guide or explore the interactive playground to experiment with different configurations.