ROB'S GARAGE DESIGN STUDIO

CSS3 NEON RAINBOW MOUSE TRAIL

Web Page Code Highlights

•  CSS and Javascript for Neon Rainbow Bubbles Mouse Trail. No Dependencies.
•  FX Effects: Rainbow Color Changing Mouse Trail Bubbles with Explosive on-Click Particles.

This web page Validates at:

Neon Rainbow Mouse Trail Javascript

Creating a mouse trail effect primarily involves JavaScript to track mouse movement and dynamically add/remove image elements, with CSS used for styling and animation of these images.

Explanation:
• HTML:
A container div is used to hold the dynamically created trail images.

CSS:
• mouse-trail-container: Fixed positioning ensures the container overlays the viewport and pointer-events: none prevents the trail images from blocking clicks or scrolling.

trail-image: Images are absolutely positioned and initially hidden (opacity: 0, transform: scale(0)). A transition property provides smooth fading and scaling effects.

trail-image.active: This class is added by JavaScript to trigger the fade-in and scale-up animation.

JavaScript:
• An event listener on mousemove triggers creation of a new img element (throttled). The image's position is calculated relative to the overlay container using getBoundingClientRect + clientX/clientY. A small requestAnimationFrame-based throttle reduces DOM churn. Images are removed after their transition completes.

Customization:
• Particle Size: Adjust the random size range in the createParticle() function.
• Color Cycling: Modify the global hue incrementation to speed up or slow down rainbow shifting.
• Trail Density: Change spawnDistance to increase or reduce how many particles follow the mouse.
• Explosion Intensity: Adjust the amount, range, and duration of particles inside the click handler.
• Comet Effect: Enable/disable or modify the chained mini-particles created when comet: true is used.

	
document.addEventListener("DOMContentLoaded", () => {
    const container = document.querySelector(".mouse-trail-container");
    
    let hue = 0;
    let lastX = 0, lastY = 0;
    const spawnDistance = 12; // smaller distance for ultra dense trail
    
    function createParticle(x, y, options = {}) {
    const p = document.createElement("div");
    p.className = "particle";
    
    const size = options.size || Math.random() * 8 + 4;
    p.style.width = `${size}px`;
    p.style.height = `${size}px`;
    
    p.style.left = `${x}px`;
    p.style.top = `${y}px`;
    
    const pHue = (hue + (options.offsetHue || 0)) % 360;
    p.style.color = `hsl(${pHue}, 100%, 60%)`;
    
    container.appendChild(p);
    
    // Physics-like drift
    const velocityX = ((Math.random() - 0.5) * (options.range || 100));
    const velocityY = ((Math.random() - 0.5) * (options.range || 100));
    const rotate = (Math.random() - 0.5) * 720;
    const scale = 0.3 + Math.random();
    
    const anim = p.animate([
      { transform: `translate(0,0) rotate(0deg) scale(1)`, opacity: 1 },
      { transform: `translate(${velocityX}px, ${velocityY}px) rotate(${rotate}deg) scale(${scale})`, opacity: 0 }
    ], {
      duration: (options.duration || 1200) + Math.random() * 800,
      easing: 'cubic-bezier(0.22, 1, 0.36, 1)'
    });
    
    anim.onfinish = () => p.remove();
    
    // Optional comet chain
    if(options.comet){
      const chainCount = 2 + Math.floor(Math.random()*3);
      for(let i=0; i<chainCount; i++){
    	setTimeout(() => {
    	  createParticle(x + velocityX*0.3, y + velocityY*0.3, {
    		size: size*0.6,
    		range: options.range*0.6,
    		duration: options.duration*0.6,
    		offsetHue: Math.random()*30
    	  });
    	}, i*50);
      }
    }
    }
    
    window.addEventListener("mousemove", e => {
    const dx = e.clientX - lastX;
    const dy = e.clientY - lastY;
    const dist = Math.sqrt(dx*dx + dy*dy);
    
    if(dist > spawnDistance){
      hue = (hue + 1) % 360;
    
      // Main particle with comet
      createParticle(e.clientX, e.clientY, { comet: true });
    
      lastX = e.clientX;
      lastY = e.clientY;
    }
    });
    
    window.addEventListener("click", e => {
    const x = e.clientX;
    const y = e.clientY;
    const explosionParticles = 60 + Math.floor(Math.random()*40);
    
    for(let i=0; i<explosionParticles; i++){
      createParticle(x, y, {
    	range: 150 + Math.random()*150,
    	duration: 1500 + Math.random()*1200,
    	offsetHue: Math.random()*360
      });
    }
    });

});