VibeCoderzVibeCoderz
Telegram
All Prompts
Animated Watercolor Botanical Background with Quote preview
animatedcanvastailwindvisualfull-screen

Animated Watercolor Botanical Background with Quote

Анимированный фон с ботаническими элементами в стиле акварели. Показывает цитату после отрисовки цветов. Реализован на Tailwind CSS и Canvas.

Prompt

<div class="relative w-full h-screen overflow-hidden select-none"
  style="background-color: #faf8f3; font-family: 'Cormorant Garamond', serif;">
  <script src="https://cdn.tailwindcss.com/3.4.17"></script>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600&family=Cormorant+Garamond:ital,wght@0,300;0,400;0,600;1,400&display=swap');

    .watercolor-canvas {
      filter: url(#watercolor);
    }

    .paper-texture {
      pointer-events: none;
      mix-blend-mode: multiply;
      opacity: 0.5;
    }

    .fade-in {
      animation: fadeIn 3s forwards;
    }

    @keyframes fadeIn {
      from {
        opacity: 0;
        transform: translateY(10px);
      }

      to {
        opacity: 1;
        transform: translateY(0);
      }
    }
  </style>

  <!-- SVG Filters for Watercolor Effect -->
  <svg class="absolute w-0 h-0">
    <filter id="paper-noise">
      <feTurbulence type="fractalNoise" baseFrequency="0.6" numOctaves="3" result="noise" />
      <feColorMatrix type="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0.4 0" />
    </filter>
    <filter id="watercolor">
      <feTurbulence type="fractalNoise" baseFrequency="0.04" numOctaves="4" result="noise" />
      <feDisplacementMap in="SourceGraphic" in2="noise" scale="14" />
      <feGaussianBlur stdDeviation="0.6" />
    </filter>
  </svg>

  <!-- Background Texture -->
  <div class="paper-texture absolute inset-0 z-10">
    <svg width="100%" height="100%">
      <rect width="100%" height="100%" filter="url(#paper-noise)" />
    </svg>
  </div>
  <div class="absolute inset-0 z-15 pointer-events-none"
    style="background: radial-gradient(circle, transparent 60%, rgba(139, 119, 101, 0.15) 100%);"></div>

  <!-- Canvas Layer -->
  <canvas id="artCanvas" class="watercolor-canvas block absolute inset-0 z-0"></canvas>

  <!-- UI Overlay -->
  <div class="relative z-20 flex flex-col items-center pt-[8vh] text-[#2c3e50] pointer-events-none">
    <h1 class="fade-in font-['Cinzel'] text-sm tracking-[0.4em] uppercase border-b border-black/20 pb-2 mb-4">Botanical
      Study • Series IV</h1>
    <div id="quoteText" class="fade-in opacity-0 italic text-2xl max-w-xl text-center leading-relaxed"
      style="animation-delay: 2s;">
      "The earth laughs in flowers."
      <div class="text-sm not-italic tracking-wider opacity-60 mt-4">— Ralph Waldo Emerson</div>
    </div>
  </div>

  <script>
    (function() {
      const canvas = document.getElementById('artCanvas');
      const ctx = canvas.getContext('2d');
      let w, h, animationId;
      let stems = [], flowers = [];
      const colors = {
        stems: [{h:85,s:35,l:45}, {h:120,s:25,l:38}, {h:65,s:40,l:55}],
        petals: [{h:355,s:75,l:65}, {h:45,s:85,l:65}, {h:215,s:65,l:70}, {h:280,s:50,l:65}, {h:15,s:80,l:75}]
      };

      function resize() {
        w = canvas.width = window.innerWidth;
        h = canvas.height = window.innerHeight;
      }

      class Stem {
        constructor(x) {
          this.x = x;
          this.y = h + 10;
          this.segments = [];
          this.len = h * (0.2 + Math.random() * 0.4);
          this.curr = 0;
          this.angle = -Math.PI/2 + (Math.random()-0.5)*0.3;
          this.color = colors.stems[Math.floor(Math.random()*colors.stems.length)];
          this.done = false;
          this.flowerType = Math.floor(Math.random() * 4);
          let cx = this.x, cy = this.y, ca = this.angle;
          for(let i=0; i<this.len/5; i++) {
            ca += (Math.random()-0.5)*0.1;
            cx += Math.cos(ca)*5; cy += Math.sin(ca)*5;
            this.segments.push({x:cx, y:cy, a:ca});
          }
        }
        draw() {
          if (this.curr < this.segments.length-1) {
            const p = this.segments[Math.floor(this.curr)];
            const n = this.segments[Math.floor(this.curr)+1];
            ctx.beginPath();
            ctx.moveTo(p.x, p.y); ctx.lineTo(n.x, n.y);
            ctx.strokeStyle = `hsla(${this.color.h},${this.color.s}%,${this.color.l}%, 0.2)`;
            ctx.lineWidth = 2 * (1 - this.curr/this.segments.length) + 1;
            ctx.stroke();
            this.curr += 1.5;
          } else if (!this.done) {
            this.done = true;
            flowers.push(new Flower(this.segments[this.segments.length-1], this.flowerType));
          }
        }
      }

      class Flower {
        constructor(pos, type) {
          this.x = pos.x; this.y = pos.y; this.type = type;
          this.age = 0; this.max = 80 + Math.random()*40;
          this.clr = colors.petals[Math.floor(Math.random()*colors.petals.length)];
          this.petals = Array.from({length: type === 0 ? 12 : 6}, (_, i) => ({
            a: (i / (type === 0 ? 12 : 6)) * Math.PI * 2,
            s: 0.8 + Math.random() * 0.5
          }));
        }
        draw() {
          if (this.age < this.max) {
            this.age++;
            const grow = Math.min(1, this.age/60);
            this.petals.forEach(p => {
              if (Math.random() > 0.5) return;
              const r = (this.type === 0 ? 15 : 25) * grow;
              const px = this.x + Math.cos(p.a) * r * 0.5;
              const py = this.y + Math.sin(p.a) * r * 0.5;
              ctx.beginPath();
              ctx.ellipse(px, py, r * p.s, r * 0.6, p.a, 0, Math.PI*2);
              ctx.fillStyle = `hsla(${this.clr.h},${this.clr.s}%,${this.clr.l}%, 0.04)`;
              ctx.fill();
            });
            if (this.age > 30 && Math.random() > 0.8) {
              ctx.beginPath();
              ctx.arc(this.x, this.y, 3 * grow, 0, Math.PI*2);
              ctx.fillStyle = `rgba(0,0,0,0.1)`; ctx.fill();
            }
          }
        }
      }

      function init() {
        resize();
        stems = Array.from({length: Math.floor(w/30)}, () => new Stem(Math.random()*w));
        flowers = [];
        ctx.clearRect(0,0,w,h);
        if (animationId) cancelAnimationFrame(animationId);
        loop();
      }

      function loop() {
        let active = false;
        stems.forEach(s => { s.draw(); if(!s.done) active = true; });
        flowers.forEach(f => { f.draw(); if(f.age < f.max) active = true; });
        if (active) animationId = requestAnimationFrame(loop);
        else document.getElementById('quoteText').classList.add('opacity-100');
      }

      window.addEventListener('resize', init);
      init();
    })();
  </script>
</div>
All Prompts