VibeCoderzVibeCoderz
Telegram
All Prompts
Animated Beams Background Canvas preview
backgroundcanvasanimationbeamsinteractiveresponsivedark-themeperformancehero-sectionvisual-effects

Animated Beams Background Canvas

Интерактивный анимированный фон с лучами на HTML5 Canvas. Настраиваемая интенсивность, высокая производительность, адаптивный дизайн. Идеально для hero-секций.

Prompt

<div class="absolute inset-0 bg-neutral-950">
  <div class="relative w-full h-full">
    <canvas id="beamsCanvas" class="absolute inset-0"></canvas>
    <div class="absolute inset-0 bg-neutral-950/5 backdrop-blur-3xl animate-pulse [animation-duration:8s]"></div>
    <div class="pointer-events-none absolute inset-0">
      <div class="absolute inset-x-0 top-0 h-40 bg-gradient-to-b from-neutral-950 to-transparent"></div>
      <div class="absolute inset-x-0 bottom-0 h-40 bg-gradient-to-t from-neutral-950 to-transparent"></div>
      <div class="absolute -inset-[25%] bg-[radial-gradient(60%_60%_at_50%_40%,rgba(80,120,255,0.10),transparent)]"></div>
    </div>
  </div>
  <script>
    // Beams Canvas
    (() => {
      const canvas = document.getElementById('beamsCanvas');
      if (!canvas) return;
      
      const ctx = canvas.getContext('2d', { alpha: true });
      if (!ctx) return;
      
      const MINIMUM_BEAMS = 20;
      let beams = [];
      let rafId = 0;
      
      const opacityMap = {
        subtle: 0.7,
        medium: 0.85,
        strong: 1.0,
      };
      
      let intensity = 'strong';
      
      function random(min, max) {
        return Math.random() * (max - min) + min;
      }
      
      function createBeam(w, h) {
        const angle = -35 + Math.random() * 10;
        return {
          x: Math.random() * w * 1.5 - w * 0.25,
          y: Math.random() * h * 1.5 - h * 0.25,
          width: 30 + Math.random() * 60,
          length: h * 2.5,
          angle,
          speed: 0.6 + Math.random() * 1.2,
          opacity: 0.12 + Math.random() * 0.16,
          hue: 190 + Math.random() * 70,
          pulse: Math.random() * Math.PI * 2,
          pulseSpeed: 0.02 + Math.random() * 0.03,
        };
      }
      
      function resetBeam(beam, index, totalBeams, w, h) {
        const column = index % 3;
        const spacing = w / 3;
        beam.y = h + 100;
        beam.x = column * spacing + spacing / 2 + (Math.random() - 0.5) * spacing * 0.5;
        beam.width = 100 + Math.random() * 100;
        beam.speed = 0.5 + Math.random() * 0.4;
        beam.hue = 190 + (index * 70) / totalBeams;
        beam.opacity = 0.2 + Math.random() * 0.1;
        return beam;
      }
      
      function updateCanvasSize() {
        const dpr = Math.max(1, window.devicePixelRatio || 1);
        const w = Math.floor(canvas.clientWidth || window.innerWidth);
        const h = Math.floor(canvas.clientHeight || window.innerHeight);
        
        canvas.width = Math.floor(w * dpr);
        canvas.height = Math.floor(h * dpr);
        canvas.style.width = w + 'px';
        canvas.style.height = h + 'px';
        
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        ctx.scale(dpr, dpr);
        
        const density = Math.min(1.5, Math.max(1, (w * h) / (1280 * 800)));
        const total = Math.floor(MINIMUM_BEAMS * density * 1.5);
        
        beams = Array.from({ length: total }, () => createBeam(w, h));
      }
      
      function drawBeam(c, beam, w, h) {
        c.save();
        c.translate(beam.x, beam.y);
        c.rotate((beam.angle * Math.PI) / 180);
        
        const pulsingOpacity = beam.opacity * (0.8 + Math.sin(beam.pulse) * 0.2) * opacityMap[intensity];
        
        const gradient = c.createLinearGradient(0, 0, 0, beam.length);
        gradient.addColorStop(0, `hsla(${beam.hue},85%,65%,0)`);
        gradient.addColorStop(0.1, `hsla(${beam.hue},85%,65%,${pulsingOpacity * 0.5})`);
        gradient.addColorStop(0.4, `hsla(${beam.hue},85%,65%,${pulsingOpacity})`);
        gradient.addColorStop(0.6, `hsla(${beam.hue},85%,65%,${pulsingOpacity})`);
        gradient.addColorStop(0.9, `hsla(${beam.hue},85%,65%,${pulsingOpacity * 0.5})`);
        gradient.addColorStop(1, `hsla(${beam.hue},85%,65%,0)`);
        
        c.fillStyle = gradient;
        c.fillRect(-beam.width / 2, 0, beam.width, beam.length);
        c.restore();
      }
      
      function animate() {
        const w = canvas.clientWidth || window.innerWidth;
        const h = canvas.clientHeight || window.innerHeight;
        
        ctx.clearRect(0, 0, w, h);
        ctx.filter = 'blur(35px)';
        
        const total = beams.length;
        for (let i = 0; i < total; i++) {
          const b = beams[i];
          b.y -= b.speed;
          b.pulse += b.pulseSpeed;
          
          if (b.y + b.length < -100) {
            resetBeam(b, i, total, w, h);
          }
          drawBeam(ctx, b, w, h);
        }
        
        rafId = requestAnimationFrame(animate);
      }
      
      function init() {
        const parent = canvas.parentElement;
        if (parent) {
          const rect = parent.getBoundingClientRect();
          canvas.style.width = rect.width + 'px';
          canvas.style.height = rect.height + 'px';
        }
        updateCanvasSize();
        cancelAnimationFrame(rafId);
        animate();
      }
      
      window.addEventListener('resize', () => {
        updateCanvasSize();
      }, { passive: true });
      
      init();
      
      // External intensity control
      window.setBeamIntensity = function(newIntensity) {
        if (opacityMap[newIntensity]) {
          intensity = newIntensity;
        }
      };
    })();
  </script>
</div>
All Prompts