DEV Community

0 seconds of 0 secondsVolume 90%
Press shift question mark to access a list of keyboard shortcuts
00:00
00:00
00:00
 
Prince
Prince

Posted on

1 1

Purpose your love with the coding of the html css and javascript illusionistic heart with particles

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Particle Heart Illusion</title>
  <style>
    body {
      margin: 0;
      overflow: hidden;
      background-color: #000;
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
    }
    canvas {
      display: block;
    }
  </style>
</head>
<body>
  <canvas id="heartCanvas"></canvas>

  <script>
    document.addEventListener('DOMContentLoaded', function() {
      const canvas = document.getElementById('heartCanvas');
      const ctx = canvas.getContext('2d');

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

      // Responsive sizing
      const size = Math.min(canvas.width, canvas.height) * 0.8;

      // Particle class
      class Particle {
        constructor(x, y) {
          this.originalX = x;
          this.originalY = y;
          this.x = Math.random() * canvas.width;
          this.y = Math.random() * canvas.height;
          this.size = Math.random() * 3 + 1;
          this.velocityX = Math.random() * 2 - 1;
          this.velocityY = Math.random() * 2 - 1;
          this.color = `hsl(${340 + Math.random() * 40}, 100%, ${50 + Math.random() * 30}%)`;
          this.targetX = x;
          this.targetY = y;
        }

        update() {
          const dx = this.targetX - this.x;
          const dy = this.targetY - this.y;
          const distance = Math.sqrt(dx * dx + dy * dy);

          if (distance > 1) {
            this.velocityX = dx * 0.03;
            this.velocityY = dy * 0.03;
          } else {
            // Add some random movement when close to target
            this.velocityX = (Math.random() * 2 - 1) * 0.3;
            this.velocityY = (Math.random() * 2 - 1) * 0.3;
          }

          this.x += this.velocityX;
          this.y += this.velocityY;
        }

        draw() {
          ctx.beginPath();
          ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
          ctx.fillStyle = this.color;
          ctx.fill();
        }

        scatter() {
          this.targetX = Math.random() * canvas.width;
          this.targetY = Math.random() * canvas.height;
        }

        returnToHeart() {
          this.targetX = this.originalX;
          this.targetY = this.originalY;
        }
      }

      // Generate particles in a heart shape
      const particles = [];
      const heartPoints = [];
      const particleCount = 1000;

      // Create heart shape points
      function createHeartPoints() {
        heartPoints.length = 0;

        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;
        const scale = size / 20;

        for (let t = 0; t < Math.PI * 2; t += 0.01) {
          const x = 16 * Math.pow(Math.sin(t), 3);
          const y = 13 * Math.cos(t) - 5 * Math.cos(2*t) - 2 * Math.cos(3*t) - Math.cos(4*t);

          heartPoints.push({
            x: centerX + x * scale,
            y: centerY - y * scale
          });
        }

        // Fill in the heart
        for (let i = 0; i < 200; i++) {
          const randomAngle = Math.random() * Math.PI * 2;
          const randomRadius = Math.random() * size / 3;

          const x = centerX + Math.cos(randomAngle) * randomRadius;
          const y = centerY - Math.sin(randomAngle) * randomRadius;

          if (isPointInHeart(x, y, centerX, centerY, scale)) {
            heartPoints.push({x, y});
          }
        }
      }

      // Check if a point is inside the heart shape
      function isPointInHeart(x, y, centerX, centerY, scale) {
        const rx = (x - centerX) / scale;
        const ry = (centerY - y) / scale;

        // Heart equation: (x^2 + y^2 - 1)^3 - x^2*y^3 < 0
        const v1 = Math.pow(rx*rx + ry*ry - 1, 3);
        const v2 = rx*rx * Math.pow(ry, 3);

        return v1 - v2 < 0;
      }

      // Initialize particles
      function initParticles() {
        createHeartPoints();
        particles.length = 0;

        for (let i = 0; i < particleCount; i++) {
          const randomIndex = Math.floor(Math.random() * heartPoints.length);
          const point = heartPoints[randomIndex];
          particles.push(new Particle(point.x, point.y));
        }
      }

      // Animation loop
      function animate() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        for (const particle of particles) {
          particle.update();
          particle.draw();
        }

        requestAnimationFrame(animate);
      }

      // Event listeners for interactions
      canvas.addEventListener('click', function() {
        const isScattered = particles[0].targetX !== particles[0].originalX;

        if (isScattered) {
          for (const particle of particles) {
            particle.returnToHeart();
          }
        } else {
          for (const particle of particles) {
            particle.scatter();
          }
        }
      });

      // Handle window resize
      window.addEventListener('resize', function() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        initParticles();
      });

      // Start animation
      initParticles();
      animate();
    });
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)