VibeCoderzVibeCoderz
Telegram
All Prompts
Animated Testimonial Section with Word Reveal preview
testimonialquotetailwindscroll-animationintersectionobserverresponsivelanding-page

Animated Testimonial Section with Word Reveal

Анимированный блок отзывов с эффектом появления слов по скроллу. Идеально для лендингов, выводя цитату, аватар и бейдж.

Prompt

<section class="relative z-10 sm:px-6 lg:px-8 quoteRevealSection max-w-7xl mt-8 mr-auto ml-auto pt-8 pr-4 pb-16 pl-4"
  style="--reveal: 100%;">
  <div class="relative overflow-hidden sm:p-10 ring-white/10 ring-1 bg-neutral-900 rounded-3xl p-6">
    <div class="flex justify-center">
      <span class="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/5 px-3 py-1.5 text-[11px] text-neutral-200">
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="star" class="lucide lucide-star w-3.5 h-3.5" style="stroke-width:1.5"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" class=""></path></svg>
          PLAYERS LOVE ARCADE
        </span>
    </div>

    <div class="relative sm:mt-10 quoteReveal mt-8">
      <p class="max-w-5xl sm:text-4xl md:text-5xl lg:text-6xl leading-[1.1] tracking-tight text-center mr-auto ml-auto">
        <span class="quote-word transition-colors duration-300" data-word-index="0" style="color: rgb(255, 255, 255);">"Instant</span>
        <span class="quote-word transition-colors duration-300" data-word-index="1" style="color: rgb(255, 255, 255);">delivery,</span>
        <span class="quote-word transition-colors duration-300" data-word-index="2" style="color: rgb(255, 255, 255);">great</span>
        <span class="quote-word transition-colors duration-300" data-word-index="3" style="color: rgb(255, 255, 255);">deals,</span>
        <span class="quote-word transition-colors duration-300 font-instrument-serif italic" data-word-index="4" style="color: rgb(255, 255, 255);">zero</span>
        <span class="quote-word transition-colors duration-300" data-word-index="5" style="color: rgb(255, 255, 255);">hassle.</span>
        <span class="quote-word transition-colors duration-300" data-word-index="6" style="color: rgb(255, 255, 255);">Arcade</span>
        <span class="quote-word transition-colors duration-300" data-word-index="7" style="color: rgb(255, 255, 255);">is</span>
        <span class="quote-word transition-colors duration-300" data-word-index="8" style="color: rgb(255, 255, 255);">my</span>
        <span class="quote-word transition-colors duration-300" data-word-index="9" style="color: rgb(255, 255, 255);">go‑to</span>
        <span class="quote-word transition-colors duration-300" data-word-index="10" style="color: rgb(255, 255, 255);">for</span>
        <span class="quote-word transition-colors duration-300" data-word-index="11" style="color: rgb(255, 255, 255);">finding</span>
        <span class="quote-word transition-colors duration-300" data-word-index="12" style="color: rgb(255, 255, 255);">the</span>
        <span class="quote-word transition-colors duration-300" data-word-index="13" style="color: rgb(255, 255, 255);">best</span>
        <span class="quote-word transition-colors duration-300" data-word-index="14" style="color: rgb(255, 255, 255);">games</span>
        <span class="quote-word transition-colors duration-300" data-word-index="15" style="color: rgb(255, 255, 255);">fast,</span>
        <span class="quote-word transition-colors duration-300" data-word-index="16" style="color: rgb(255, 255, 255);">across</span>
        <span class="quote-word transition-colors duration-300" data-word-index="17" style="color: rgb(255, 255, 255);">all</span>
        <span class="quote-word transition-colors duration-300" data-word-index="18" style="color: rgb(255, 255, 255);">my</span>
        <span class="quote-word transition-colors duration-300" data-word-index="19" style="color: rgb(115, 115, 115);">platforms.</span>
        <span class="quote-word transition-colors duration-300" data-word-index="20" style="color: rgb(115, 115, 115);">Highly</span>
        <span class="quote-word transition-colors duration-300" data-word-index="21" style="color: rgb(115, 115, 115);">recommend!"</span>
      </p>
    </div>

    <div class="sm:mt-10 flex gap-3 mt-8 items-center justify-center">
      <img alt="Player avatar" class="h-10 w-10 ring-1 ring-white/10 object-cover rounded-full" src="https://hoirqrkdgbmvpwutwuwj-all.supabase.co/storage/v1/object/public/assets/assets/8d3cb9d4-adbe-41e5-a351-a4a6c22d6037_320w.jpg">
      <span class="text-sm sm:text-base text-neutral-300 font-medium">Pro Gamer &amp; Streamer</span>
    </div>
  </div>

  <script>
    (function () {
        const section = document.querySelector('.quoteRevealSection');
        const target = section ? section.querySelector('.quoteReveal') : null;
        const words = section ? section.querySelectorAll('.quote-word') : [];
        if (!section || !target || words.length === 0) return;

        words.forEach(word => { word.style.color = 'rgb(115 115 115)'; });
        function updateWordReveal() {
          const rect = target.getBoundingClientRect();
          const vh = window.innerHeight || document.documentElement.clientHeight;
          const viewportCenter = vh / 2;
          const elementCenter = rect.top + rect.height / 2;
          const distanceFromCenter = Math.abs(elementCenter - viewportCenter);
          const maxDistance = vh / 2;
          const centerRatio = Math.max(0, Math.min(1, 1 - (distanceFromCenter / maxDistance)));
          const totalWords = words.length;
          const wordsToReveal = Math.floor(centerRatio * totalWords);
          words.forEach((word, index) => {
            word.style.color = index < wordsToReveal ? 'rgb(255 255 255)' : 'rgb(115 115 115)';
          });
        }
        if (typeof IntersectionObserver !== 'undefined') {
          const io = new IntersectionObserver(updateWordReveal, { threshold: Array.from({ length: 101 }, (_, i) => i / 100) });
          io.observe(target);
        }
        window.addEventListener('scroll', updateWordReveal, { passive: true });
        window.addEventListener('resize', updateWordReveal);
        updateWordReveal();
      })();
  </script>
</section>
All Prompts