skip to Main Content

I need help to apply the water effect which is fading like the below image. In the image the white particles are fading to blue blurry effect. This is what I am trying to achieve.

I believe with fast blur or simplex-noise we should be able to achieve this, but not sure how to proceed.

(click to enlarge)

Water fall

Achieved the water fall with splinters in HTML5 canvas.

CodePen Source

const canvas = document.getElementById('fountainCanvas');
const ctx = canvas.getContext('2d');

// Set canvas size
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const particles = [];
const splinters = [];
const gravity = 0.1; // Gravity constant
const fountainX = canvas.width / 2;
const fountainY = canvas.height / 2;

// Mouse position
let mouseX = fountainX;
let mouseY = fountainY;

// Particle class
class Particle {
  constructor(x, y, angle, isSplinter = false) {
    this.x = x;
    this.y = y;
    const speed = Math.random() * 3 + 2; // Random speed
    const spread = Math.random() * 0.4 - 0.2; // Randomize direction slightly
    this.vx = isSplinter ?
      (Math.random() * 2 - 1) * 3 :
      Math.cos(angle + spread) * speed;
    this.vy = isSplinter ?
      Math.random() * -3 :
      Math.sin(angle + spread) * speed;
    this.alpha = isSplinter ? 1 : 1; // Opacity
    this.radius = isSplinter ? Math.random() : Math.random() + 1; // Size
    this.isSplinter = isSplinter;
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;
    this.vy += gravity; // Apply gravity
    this.alpha -= this.isSplinter ? 0.02 : 0.005; // Fade out

    // Check if main particles reach the bottom of the canvas
    if (!this.isSplinter && this.y >= canvas.height) {
      this.createSplinters(); // Create splinters on impact
      this.alpha = 0; // Make particle invisible
    }
  }

  createSplinters() {
    for (let i = 0; i < 10; i++) {
      splinters.push(new Particle(this.x, canvas.height, 0, true));
    }
  }

  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
    ctx.fillStyle = `hsla(199, 100%, 67%, ${this.alpha})`; // Blue shade with opacity
    ctx.fill();
  }

  isAlive() {
    return this.alpha > 0; // Check if particle is still visible
  }
}

// Create particles over time
function emitParticles() {
  const angle = Math.atan2(mouseY - fountainY, mouseX - fountainX);
  for (let i = 0; i < 5; i++) { // Emit a few particles per frame
    particles.push(new Particle(fountainX, fountainY, angle));
  }
}

// Animation loop
function animate() {
  ctx.fillStyle = 'rgba(0, 0, 0, 0.2)'; // Trail effect
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  emitParticles(); // Emit new particles continuously

  // Update and draw particles
  particles.forEach((particle, index) => {
    particle.update();
    if (!particle.isAlive()) {
      particles.splice(index, 1); // Remove dead particles
    } else {
      particle.draw();
    }
  });

  // Update and draw splinters
  splinters.forEach((splinter, index) => {
    splinter.update();
    if (!splinter.isAlive()) {
      splinters.splice(index, 1); // Remove dead splinters
    } else {
      splinter.draw();
    }
  });

  requestAnimationFrame(animate);
}

// Update mouse position on move
canvas.addEventListener('mousemove', (event) => {
  mouseX = event.clientX;
  mouseY = event.clientY;
});

// Initialize animation
animate();
canvas {
  display: block;
  margin: 0 auto;
  background: #000;
  /* Black background */
}
<canvas id="fountainCanvas"></canvas>

2

Answers


  1. // script.js
    
    const container = document.getElementById("waterfall-container");
    
    function createFallingElement() {
        // Create a new div element
        const waterfallItem = document.createElement("div");
        waterfallItem.classList.add("waterfall-item");
    
        // Set a random horizontal position
        const randomX = Math.random() * window.innerWidth;
        waterfallItem.style.left = `${randomX}px`;
    
        // Append the element to the container
        container.appendChild(waterfallItem);
    
        // Remove the element after animation ends to avoid clutter
        waterfallItem.addEventListener("animationend", () => {
            container.removeChild(waterfallItem);
        });
    }
    
    // Create new falling elements every 200ms
    setInterval(createFallingElement, 200);
    Login or Signup to reply.
  2. In your code you fade the particles with the alpha:

    ctx.fillStyle = `hsla(199, 100%, 67%, ${this.alpha})`;
    

    But your background is black so the fade is from blue to black

    If you want to create the illusion of fading from one color to another, you can draw two arc on the exact same location but the first one do it with a different color while that will be on the background, and should create the experience you are looking for…

    const canvas = document.getElementById('fountainCanvas');
    const ctx = canvas.getContext('2d');
    var particles = []
    
    class Particle {
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.alpha = 1;
      }
    
      draw() {
        this.alpha -= 0.005;
        ctx.beginPath();
        ctx.arc(this.x, this.y, 15, 0, Math.PI * 2);
        ctx.fillStyle = `red`;
        ctx.fill();
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = `hsla(199, 100%, 67%, ${this.alpha})`;
        ctx.fill();
      }
    }
    
    function emitParticles() {
      particles= []
      for (let i = 2; i < 7; i++) { 
        particles.push(new Particle(35*i, 20+10*i));
      }
    }
    
    function animate() {
      ctx.reset();
      particles.forEach(p => p.draw());
      requestAnimationFrame(animate);
    }
    
    setInterval(emitParticles, 4000)
    emitParticles()
    animate();
    canvas {
      display: block;
      margin: 0 auto;
      background: #000;
      /* Black background */
    }
    <canvas id="fountainCanvas"></canvas>

    You can also transition to other colors:
    https://www.w3schools.com/colors/colors_hsl.asp

    const canvas = document.getElementById('fountainCanvas');
    const ctx = canvas.getContext('2d');
    var particles = []
    
    class Particle {
      constructor(x, y) {
        this.x = x;
        this.y = y;
        this.alpha = 1;
        this.color = 199
      }
    
      draw() {
        this.alpha -= 0.005;
        this.color -= 1;
        ctx.beginPath();
        ctx.arc(this.x, this.y, 15, 0, Math.PI * 2);
        ctx.fillStyle = `hsla(${this.color}, 100%, 67%, ${this.alpha})`;
        ctx.fill();
      }
    }
    
    function emitParticles() {
      particles= []
      for (let i = 2; i < 7; i++) { 
        particles.push(new Particle(35*i, 20+10*i));
      }
    }
    
    function animate() {
      ctx.reset();
      particles.forEach(p => p.draw());
      requestAnimationFrame(animate);
    }
    
    setInterval(emitParticles, 4000)
    emitParticles()
    animate();
    canvas {
      display: block;
      margin: 0 auto;
      background: #000;
      /* Black background */
    }
    <canvas id="fountainCanvas"></canvas>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search