Cursor Tracking Comparison
The trackCursorOnlyInsideCanvas setting fundamentally changes how particles respond to cursor movement. This guide compares both modes to help you choose the right approach for your project.
Quick Comparison
Section titled “Quick Comparison”| Feature | Unrestricted (Default) | Restricted |
|---|---|---|
| Configuration | trackCursorOnlyInsideCanvas: false | trackCursorOnlyInsideCanvas: true |
| Tracking Scope | Entire page | Canvas boundaries only |
| Cursor Outside Canvas | Particles still react | Particles return to rest |
| Transition | Smooth approach | Sharp on/off |
| Performance | Constant calculations | Reduced when cursor outside |
| Best For | Single canvas, fluid UX | Multiple canvases, clear boundaries |
| User Experience | Anticipatory, fluid | Explicit, bounded |
Side-by-Side Demonstration
Section titled “Side-by-Side Demonstration”Unrestricted Tracking (Default)
Section titled “Unrestricted Tracking (Default)”Unrestricted - Tracks Everywhere
const instance = initParticleJS('#canvas', {text: 'ANYWHERE',colors: ['#4facfe', '#00f2fe'],trackCursorOnlyInsideCanvas: false // Default});
// Behavior:// - Particles react to cursor anywhere on page// - Smooth transitions as cursor approaches// - Creates anticipation effect// - Constant tracking and calculationsTry it: Move your cursor around the page - particles react even when you’re far from the canvas.
Restricted Tracking
Section titled “Restricted Tracking”Restricted - Inside Only
const instance = initParticleJS('#canvas', {text: 'INSIDE',colors: ['#f093fb', '#f5576c'],trackCursorOnlyInsideCanvas: true});
// Behavior:// - Particles only react when cursor is inside canvas// - Immediate return to rest when cursor leaves// - Clear interaction boundary// - Reduced calculations when cursor outsideTry it: Move your cursor into and out of the canvas - notice the sharp transition.
Technical Differences
Section titled “Technical Differences”Mouse Position Handling
Section titled “Mouse Position Handling”// UNRESTRICTED (default)function onMouseMove(e) {const rect = element.getBoundingClientRect();const relativeX = e.clientX - rect.left;const relativeY = e.clientY - rect.top;
// Always update mouse positionmouse.x = relativeX * (canvas.width / rect.width);mouse.y = relativeY * (canvas.height / rect.height);
// Particles calculate distance to this position// Even if it's outside canvas bounds}
// RESTRICTEDfunction onMouseMove(e) {const rect = element.getBoundingClientRect();const relativeX = e.clientX - rect.left;const relativeY = e.clientY - rect.top;
// Check if cursor is outside canvasif (relativeX < 0 || relativeX > rect.width || relativeY < 0 || relativeY > rect.height) {
// Reset to far-away position mouse.x = -9999; mouse.y = -9999; return; // Don't process further}
// Only update if insidemouse.x = relativeX * (canvas.width / rect.width);mouse.y = relativeY * (canvas.height / rect.height);}Particle Behavior
Section titled “Particle Behavior”// In both modes, particles check distance to mousefunction particleUpdate() {const dx = particle.x - mouse.x;const dy = particle.y - mouse.y;const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < explosionRadius) { // Push particle away from mouse particle.vx += (particle.x - mouse.x) / 10; particle.vy += (particle.y - mouse.y) / 10;}}
// UNRESTRICTED:// mouse.x, mouse.y = actual cursor position (even if outside canvas)// distance = real distance from cursor to particle// Particles may be pushed even when cursor is far away
// RESTRICTED:// mouse.x, mouse.y = (-9999, -9999) when cursor outside// distance = very large number// distance > explosionRadius, so no explosion effect// Particles naturally return to rest positionWhen to Use Each Mode
Section titled “When to Use Each Mode”Use Unrestricted (Default) When:
Section titled “Use Unrestricted (Default) When:”// 1. Single canvas taking up most of viewportconst heroInstance = initParticleJS('#hero-canvas', {text: 'WELCOME',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: false // Smooth experience});
// 2. Full-page background effectconst bgInstance = initParticleJS('#bg-canvas', {text: 'BACKGROUND',colors: ['#E0E0E0'],trackCursorOnlyInsideCanvas: false // Seamless integration});
// 3. Creating anticipation before interactionconst calloutInstance = initParticleJS('#callout', {text: 'CLICK ME',colors: ['#FF6B6B'],trackCursorOnlyInsideCanvas: false // Particles react as you approach});
// 4. Smooth, fluid user experience is priorityconst fluidInstance = initParticleJS('#canvas', {text: 'FLUID',colors: ['#4ECDC4'],trackCursorOnlyInsideCanvas: false // No jarring transitions});Advantages:
- Smooth, fluid transitions
- Creates anticipation and visual interest
- Natural feel as particles respond to approaching cursor
- Good for immersive experiences
- Works well for single, prominent canvas
Disadvantages:
- Can interfere with multiple canvases
- Particles react even when user isn’t focused on canvas
- Slightly higher CPU usage (constant calculations)
- Less clear interaction boundaries
Use Restricted When:
Section titled “Use Restricted When:”// 1. Multiple canvas instances on same pagedocument.querySelectorAll('.gallery-item canvas').forEach(canvas => {initParticleJS(canvas, { text: canvas.dataset.text, colors: ['#695aa6'], trackCursorOnlyInsideCanvas: true // Each independent});});
// 2. Canvas near interactive elementsconst headerInstance = initParticleJS('#header-canvas', {text: 'HEADER',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true // Don't interfere with buttons});
// 3. Explicit interaction zones neededconst zoneInstance = initParticleJS('#zone-canvas', {text: 'ZONE',colors: ['#4ECDC4'],trackCursorOnlyInsideCanvas: true // Clear boundary});
// 4. Performance optimizationconst largeInstance = initParticleJS('#large-canvas', {text: 'LARGE',colors: ['#FF6B6B'],trackCursorOnlyInsideCanvas: true, // Reduce calculationsmaxParticles: 5000});Advantages:
- Clear, explicit interaction boundaries
- No interference between multiple canvases
- Reduced calculations when cursor outside
- Better for galleries, grids, lists
- Explicit user intent required
Disadvantages:
- Abrupt on/off transition
- No anticipatory effect
- Requires cursor to be inside canvas
- Less fluid user experience
Common Scenarios
Section titled “Common Scenarios”Scenario 1: Full-Screen Hero Section
Section titled “Scenario 1: Full-Screen Hero Section”// Recommendation: UNRESTRICTED// Reasoning: Single prominent canvas, fluid experience desired
<section class="hero" style="height: 100vh;"><canvas id="hero-canvas"></canvas><h1>Welcome to Our Site</h1></section>
<script>const instance = initParticleJS('#hero-canvas', {text: 'HERO',colors: ['#667eea', '#764ba2'],trackCursorOnlyInsideCanvas: false, // Smooth, immersive
explosionRadius: { xs: 100, lg: 200 // Large radius for dramatic effect}});</script>
// Why unrestricted:// - Canvas takes up entire viewport// - Smooth interaction is key// - No other canvases to interfere with// - Creates immersive experienceScenario 2: Portfolio Grid
Section titled “Scenario 2: Portfolio Grid”// Recommendation: RESTRICTED// Reasoning: Multiple canvases, clear boundaries needed
<div class="portfolio-grid"><div class="project"><canvas data-text="PROJECT 1"></canvas></div><div class="project"><canvas data-text="PROJECT 2"></canvas></div><div class="project"><canvas data-text="PROJECT 3"></canvas></div><div class="project"><canvas data-text="PROJECT 4"></canvas></div></div>
<script>document.querySelectorAll('.project canvas').forEach(canvas => {initParticleJS(canvas, { text: canvas.dataset.text, colors: ['#695aa6'], trackCursorOnlyInsideCanvas: true, // Independent items
explosionRadius: { xs: 60, lg: 100 }});});</script>
// Why restricted:// - Multiple canvases in proximity// - User needs to know which project they're interacting with// - Clear visual feedback// - Prevents cross-contaminationScenario 3: Fixed Header
Section titled “Scenario 3: Fixed Header”// Recommendation: RESTRICTED// Reasoning: Fixed positioning, other page elements present
<header style="position: fixed; top: 0; width: 100%;"><canvas id="header-canvas"></canvas><nav> <a href="#">Home</a> <a href="#">About</a> <a href="#">Contact</a></nav></header>
<script>const instance = initParticleJS('#header-canvas', {text: 'HEADER',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true // Don't interfere with nav});</script>
// Why restricted:// - Navigation links present// - Don't want particles reacting while scrolling// - Clear separation of canvas vs nav interaction// - Better accessibilityScenario 4: Background Wallpaper
Section titled “Scenario 4: Background Wallpaper”// Recommendation: UNRESTRICTED// Reasoning: Background effect, subtle interaction
<div class="page-background"><canvas id="bg-canvas" style="position: fixed; z-index: -1;"></canvas></div>
<script>const instance = initParticleJS('#bg-canvas', {text: 'BACKGROUND',colors: ['#E0E0E0'],trackCursorOnlyInsideCanvas: false, // Seamless background
explosionRadius: { xs: 150, lg: 250 // Wide radius for subtle effect},
friction: { base: 0.95, rand: 0.03 } // Slow, gentle movement});</script>
// Why unrestricted:// - Background spans entire page// - Subtle, ambient effect// - Should respond throughout page// - No other canvases to conflict withHybrid Approach
Section titled “Hybrid Approach”You can mix both modes on the same page:
// Hero section: Unrestricted (immersive)const hero = initParticleJS('#hero-canvas', {text: 'HERO',colors: ['#667eea'],trackCursorOnlyInsideCanvas: false});
// Gallery items: Restricted (clear boundaries)document.querySelectorAll('.gallery canvas').forEach(canvas => {initParticleJS(canvas, { text: canvas.dataset.text, colors: ['#4ECDC4'], trackCursorOnlyInsideCanvas: true});});
// Footer: Unrestricted (subtle effect)const footer = initParticleJS('#footer-canvas', {text: 'FOOTER',colors: ['#95a5a6'],trackCursorOnlyInsideCanvas: false});
// This gives you:// - Immersive hero// - Clear gallery interaction// - Subtle footer effect// Each canvas optimized for its contextPerformance Comparison
Section titled “Performance Comparison”Unrestricted Mode
Section titled “Unrestricted Mode”// CPU Usage Pattern (Unrestricted)// Cursor anywhere on page: HIGH (constant calculations)// Cursor over canvas: HIGH (explosion calculations)// Cursor off-page: MEDIUM (tracking, no explosions)
// Frame time: ~12-18ms (60 FPS achievable)// Recommended for: Single canvas, fluid UXRestricted Mode
Section titled “Restricted Mode”// CPU Usage Pattern (Restricted)// Cursor outside canvas: LOW (particles at rest)// Cursor inside canvas: HIGH (explosion calculations)// Cursor off-page: LOW (no tracking)
// Frame time: ~8-12ms outside, ~15-20ms inside// Recommended for: Multiple canvases, performance-criticalPerformance Test
Section titled “Performance Test”// Measure performance differencelet frameCount = 0;let lastTime = performance.now();
const unrestrictedInstance = initParticleJS('#canvas1', {text: 'UNRESTRICTED',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: false});
const restrictedInstance = initParticleJS('#canvas2', {text: 'RESTRICTED',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
setInterval(() => {const now = performance.now();const elapsed = now - lastTime;const fps = Math.round((frameCount * 1000) / elapsed);
console.log(`FPS: ${fps}`);console.log(`Cursor outside restricted canvas: likely higher FPS`);
frameCount = 0;lastTime = now;}, 1000);User Experience Considerations
Section titled “User Experience Considerations”Unrestricted: Fluid & Anticipatory
Section titled “Unrestricted: Fluid & Anticipatory”// User Experience Flow:
// 1. User scrolls page// → Particles begin to react as cursor approaches
// 2. Cursor gets closer to canvas// → Particles react more strongly
// 3. Cursor directly over canvas// → Full explosion effect
// 4. Cursor moves away// → Gradual decrease in effect
// Result: Smooth, natural, fluid experience// Feels: Organic, responsive, immersive// Good for: Artistic sites, portfolios, hero sectionsRestricted: Explicit & Bounded
Section titled “Restricted: Explicit & Bounded”// User Experience Flow:
// 1. User scrolls page// → No particle reaction
// 2. Cursor enters canvas boundary// → IMMEDIATE full effect
// 3. Cursor inside canvas// → Full explosion effect
// 4. Cursor exits canvas boundary// → IMMEDIATE return to rest
// Result: Clear on/off behavior// Feels: Explicit, intentional, controlled// Good for: Galleries, grids, interactive elementsMigration Between Modes
Section titled “Migration Between Modes”Switching from Unrestricted to Restricted
Section titled “Switching from Unrestricted to Restricted”// Before (unrestricted)const instance = initParticleJS('#canvas', {text: 'TEXT',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: false});
// After (restricted)const instance = initParticleJS('#canvas', {text: 'TEXT',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true, // Changed
// Consider adding visual boundary});
// Add border to show interaction zonedocument.getElementById('canvas').style.border = '2px solid #695aa6';
// Might want to increase explosion radius// Since particles only react inside, make the effect strongerexplosionRadius: {xs: 100, // Larger than beforelg: 150}Switching from Restricted to Unrestricted
Section titled “Switching from Restricted to Unrestricted”// Before (restricted)const instance = initParticleJS('#canvas', {text: 'TEXT',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: true});
// After (unrestricted)const instance = initParticleJS('#canvas', {text: 'TEXT',colors: ['#695aa6'],trackCursorOnlyInsideCanvas: false, // Changed
// Might want to reduce explosion radius// Since effect is always active, make it more subtleexplosionRadius: { xs: 60, // Smaller than before lg: 100},
// Consider gentler friction for smoother transitionsfriction: { base: 0.92, rand: 0.03 }});
// Remove border if presentdocument.getElementById('canvas').style.border = 'none';Decision Flowchart
Section titled “Decision Flowchart”// Choose the right mode with this decision tree:
START → Do you have multiple canvases on the page? ├─ YES → Use RESTRICTED (trackCursorOnlyInsideCanvas: true) └─ NO → Continue...
Is your canvas near interactive elements (buttons, links)? ├─ YES → Use RESTRICTED └─ NO → Continue...
Do you want explicit, clear interaction boundaries? ├─ YES → Use RESTRICTED └─ NO → Continue...
Is smooth, fluid UX more important than performance? ├─ YES → Use UNRESTRICTED (trackCursorOnlyInsideCanvas: false) └─ NO → Use RESTRICTED
// Summary:// - RESTRICTED: Multiple canvases, clear boundaries, performance// - UNRESTRICTED: Single canvas, smooth UX, immersiveTesting Both Modes
Section titled “Testing Both Modes”// Quick test to compare both modesfunction testBothModes() {const config = { text: 'TEST', colors: ['#695aa6'], explosionRadius: { xs: 100, lg: 150 }};
// Test unrestrictedconsole.log('Testing UNRESTRICTED mode...');const unrestricted = initParticleJS('#canvas1', { ...config, trackCursorOnlyInsideCanvas: false});
// Test restrictedconsole.log('Testing RESTRICTED mode...');const restricted = initParticleJS('#canvas2', { ...config, trackCursorOnlyInsideCanvas: true});
// Move cursor around both canvases// Observe differences in behavior}
testBothModes();Related Documentation
Section titled “Related Documentation”- Restricted Tracking - Detailed restricted mode guide
- trackCursorOnlyInsideCanvas (API Reference) - Configuration option
- Explosion Radius - Control interaction distance
- Performance Optimization - Optimize animation performance
- Multiple Canvases - Managing multiple instances