VibeCoderzVibeCoderz
Telegram
All Prompts
Interactive Pricing Cards with Draggable Tiers preview
pricingsectioninteractiveanimatedtailwindwebglcards

Interactive Pricing Cards with Draggable Tiers

Интерактивные карточки с ценами и анимированными уровнями. Драг-н-дроп, тайпрайтер-заголовки, WebGL-фон. Идеально для SaaS.

Prompt

<div
  class="antialiased bg-gray-50 text-gray-900 min-h-screen flex flex-col items-center justify-center overflow-x-hidden relative font-['Inter',sans-serif] font-light selection:bg-cyan-500/20 py-20 md:py-0">
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://code.iconify.design/iconify-icon/1.0.7/iconify-icon.min.js"></script>
  <style>
    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400&display=swap');

    .perspective-1200 {
      perspective: 1200px;
    }
  </style>

  <!-- Background Layers -->
  <div class="fixed inset-0 z-0 flex items-center justify-center pointer-events-none overflow-hidden">
    <div
      class="absolute w-[70vw] h-[70vw] max-w-[900px] max-h-[900px] rounded-full blur-[120px] opacity-30 animate-[pulse_6s_ease-in-out_infinite]"
      style="background: radial-gradient(circle, rgba(34,211,238,0.2) 0%, transparent 70%); left: 5%; top: 10%;"></div>
    <div
      class="absolute w-[70vw] h-[70vw] max-w-[900px] max-h-[900px] rounded-full blur-[120px] opacity-30 animate-[pulse_8s_ease-in-out_infinite]"
      style="background: radial-gradient(circle, rgba(251,146,60,0.2) 0%, transparent 70%); right: 5%; bottom: 10%;">
    </div>
  </div>
  <canvas id="noiseCanvas"
    class="fixed inset-0 pointer-events-none z-50 opacity-[0.03] w-full h-full mix-blend-multiply"></canvas>

  <!-- Header Section -->
  <div class="relative z-10 text-center mb-10 md:mb-16 px-6 flex flex-col items-center w-full max-w-3xl mx-auto">
    <div
      class="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-white/80 border border-gray-200/50 mb-6 backdrop-blur-md"
      style="box-shadow: 0 4px 12px rgba(0,0,0,0.03), 0 1px 3px rgba(0,0,0,0.02), inset 0 1px 0 rgba(255,255,255,1);">
      <div class="w-1.5 h-1.5 rounded-full bg-cyan-500 animate-pulse"></div>
      <span class="text-xs text-gray-500 tracking-widest uppercase font-medium">Service Levels</span>
    </div>
    <h1 class="text-4xl md:text-5xl tracking-tight text-gray-900 mb-4 font-normal">Choose Your Configuration</h1>
    <p class="text-sm text-gray-500 max-w-md typewriter-text h-10 md:h-auto"
      data-text="Select the bandwidth and security parameters for your environment."></p>
  </div>

  <!-- Main Container -->
  <div
    class="relative w-full max-w-5xl mx-auto px-6 flex flex-col md:flex-row items-center justify-center gap-10 md:gap-8 z-10 perspective-1200">

    <!-- Tier 1: Standard Node -->
    <div class="draggable-card cursor-grab select-none relative w-full max-w-sm md:w-[22rem] h-[32rem] z-10">
      <div
        class="relative w-full h-full rounded-3xl p-8 flex flex-col group transition-all duration-700 ease-out hover:-translate-y-4 hover:rotate-0 md:-rotate-6 md:translate-x-12"
        style="background: linear-gradient(145deg, #ffffff 0%, #f0f9ff 100%); box-shadow: 2px 4px 8px rgba(0,0,0,0.02), 8px 16px 24px rgba(0,0,0,0.03), 64px 96px 128px rgba(0,0,0,0.12), 80px 120px 160px rgba(6, 182, 212, 0.15), inset 0 1px 1px rgba(255,255,255,1), 0 0 0 1px rgba(0,0,0,0.04);">
        <div class="flex justify-between items-start relative z-10 mb-8">
          <div class="w-16 h-16 rounded-xl p-2.5 flex items-end justify-between gap-0.5 bg-white shadow-sm">
            <div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
              style="height: 40%; animation-duration: 0.7s;"></div>
            <div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
              style="height: 85%; animation-duration: 1.2s; animation-delay: 0.2s;"></div>
            <div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
              style="height: 100%; animation-duration: 1.5s; animation-delay: 0.1s;"></div>
            <div class="w-full bg-cyan-500/90 rounded-t-sm animate-pulse"
              style="height: 30%; animation-duration: 0.8s; animation-delay: 0.7s;"></div>
          </div>
          <div class="flex flex-col items-end">
            <div class="flex items-center gap-1.5 text-cyan-600 font-normal">
              <iconify-icon icon="solar:box-linear" class="text-lg"></iconify-icon>
              <span class="tracking-tight">INIT</span>
            </div>
            <div class="text-[10px] text-cyan-600/70 mt-1 uppercase tracking-widest">Base Node</div>
          </div>
        </div>
        <div class="relative z-10 mb-6">
          <div class="flex items-end gap-2 mb-2">
            <span class="text-5xl tracking-tight text-cyan-500 font-normal">0</span>
            <span class="text-sm text-cyan-600/70 mb-1 tracking-widest uppercase">/ Mo</span>
          </div>
          <h2 class="text-xl tracking-tight text-gray-900 mb-2 font-normal">Standard Node</h2>
          <p class="text-xs text-gray-500 leading-relaxed typewriter-text min-h-[2.5rem]"
            data-text="Essential telemetry and foundational security layers."></p>
        </div>
        <div class="relative z-10 flex flex-col gap-3 mb-8 flex-grow">
          <div class="w-full h-px mb-1 bg-black/5"></div>
          <div class="flex items-center gap-3 text-xs text-gray-600">
            <iconify-icon icon="solar:shield-check-linear" class="text-cyan-500 text-base"></iconify-icon>
            <span>Standard Encryption</span>
          </div>
          <div class="flex items-center gap-3 text-xs text-gray-600">
            <iconify-icon icon="solar:database-linear" class="text-cyan-500 text-base"></iconify-icon>
            <span>Metered Bandwidth</span>
          </div>
        </div>
        <button class="relative z-10 w-full py-3.5 px-5 rounded-xl flex items-center justify-between group/btn transition-all duration-300 hover:bg-gray-50 bg-white border border-black/5 shadow-sm">
                    <span class="text-xs text-cyan-600 tracking-widest uppercase font-medium">Deploy</span>
                    <iconify-icon icon="solar:alt-arrow-right-linear" class="text-cyan-500 text-lg group-hover/btn:translate-x-1 transition-transform"></iconify-icon>
                </button>
      </div>
    </div>

    <!-- Tier 2: Premium Relay -->
    <div class="draggable-card cursor-grab select-none relative w-full max-w-sm md:w-[22rem] h-[32rem] z-0">
      <div
        class="relative w-full h-full rounded-3xl p-8 flex flex-col group transition-all duration-700 ease-out hover:-translate-y-4 hover:rotate-0 md:rotate-6 md:-translate-x-12"
        style="background: linear-gradient(145deg, #ffffff 0%, #fff7ed 100%); box-shadow: 2px 4px 8px rgba(0,0,0,0.02), 8px 16px 24px rgba(0,0,0,0.03), 64px 96px 128px rgba(0,0,0,0.12), 80px 120px 160px rgba(249, 115, 22, 0.15), inset 0 1px 1px rgba(255,255,255,1), 0 0 0 1px rgba(0,0,0,0.04);">
        <div class="flex justify-between items-start relative z-10 mb-8">
          <div class="w-16 h-16 rounded-xl p-2.5 flex items-end justify-between gap-0.5 bg-white shadow-sm">
            <div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
              style="height: 60%; animation-duration: 0.9s;"></div>
            <div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
              style="height: 90%; animation-duration: 1.1s; animation-delay: 0.1s;"></div>
            <div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
              style="height: 50%; animation-duration: 0.8s; animation-delay: 0.6s;"></div>
            <div class="w-full bg-orange-500/90 rounded-t-sm animate-pulse"
              style="height: 75%; animation-duration: 1.3s; animation-delay: 0.3s;"></div>
          </div>
          <div class="flex flex-col items-end">
            <div class="flex items-center gap-1.5 text-orange-600 font-normal">
              <iconify-icon icon="solar:layers-linear" class="text-lg"></iconify-icon>
              <span class="tracking-tight">PLUS</span>
            </div>
            <div class="text-[10px] text-orange-600/70 mt-1 uppercase tracking-widest">Ultra Relay</div>
          </div>
        </div>
        <div class="relative z-10 mb-6">
          <div class="flex items-end gap-2 mb-2">
            <span class="text-5xl tracking-tight text-orange-500 font-normal">50</span>
            <span class="text-sm text-orange-600/70 mb-1 tracking-widest uppercase">/ Mo</span>
          </div>
          <h2 class="text-xl tracking-tight text-gray-900 mb-2 font-normal">Premium Relay</h2>
          <p class="text-xs text-gray-500 leading-relaxed typewriter-text min-h-[2.5rem]"
            data-text="High-speed pathways featuring intelligent failover."></p>
        </div>
        <div class="relative z-10 flex flex-col gap-3 mb-8 flex-grow">
          <div class="w-full h-px mb-1 bg-black/5"></div>
          <div class="flex items-center gap-3 text-xs text-gray-600">
            <iconify-icon icon="solar:shield-keyhole-linear" class="text-orange-500 text-base"></iconify-icon>
            <span>Advanced Cryptography</span>
          </div>
          <div class="flex items-center gap-3 text-xs text-gray-600">
            <iconify-icon icon="solar:infinity-linear" class="text-orange-500 text-base"></iconify-icon>
            <span>Unlimited Transfer</span>
          </div>
        </div>
        <button class="relative z-10 w-full py-3.5 px-5 rounded-xl flex items-center justify-between group/btn transition-all duration-300 hover:bg-[#fffcf9] bg-white border border-black/5 shadow-sm">
                    <span class="text-xs text-orange-600 tracking-widest uppercase font-medium">Deploy</span>
                    <iconify-icon icon="solar:alt-arrow-right-linear" class="text-orange-500 text-lg group-hover/btn:translate-x-1 transition-transform"></iconify-icon>
                </button>
      </div>
    </div>
  </div>

  <!-- Logic Layer -->
  <script>
    // WebGL Noise Background Logic
        (function() {
            const c = document.getElementById('noiseCanvas');
            const gl = c.getContext('webgl', { alpha: true });
            if (!gl) return;
            const pid = gl.createProgram();
            const shader = (type, src) => {
                const s = gl.createShader(type);
                gl.shaderSource(s, src);
                gl.compileShader(s);
                gl.attachShader(pid, s);
            };
            shader(gl.VERTEX_SHADER, 'attribute vec2 p;void main(){gl_Position=vec4(p,0,1);}');
            shader(gl.FRAGMENT_SHADER, 'precision lowp float;uniform float t;float rand(vec2 n){return fract(sin(dot(n,vec2(12.9898,4.1414)))*43758.5453);}void main(){vec2 uv=gl_FragCoord.xy;float n=rand(uv+vec2(t,-t));gl_FragColor=vec4(vec3(n),1.0);}');
            gl.linkProgram(pid); gl.useProgram(pid);
            gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer());
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1, 1,-1, -1,1, 1,1]), gl.STATIC_DRAW);
            const p = gl.getAttribLocation(pid, 'p');
            gl.enableVertexAttribArray(p); gl.vertexAttribPointer(p, 2, gl.FLOAT, false, 0, 0);
            const tLoc = gl.getUniformLocation(pid, 't');
            const resize = () => { c.width = window.innerWidth; c.height = window.innerHeight; gl.viewport(0,0,c.width,c.height); };
            window.addEventListener('resize', resize); resize();
            let time = 0;
            const draw = () => { time += 0.05; gl.uniform1f(tLoc, time); gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); requestAnimationFrame(draw); };
            draw();
        })();

        // Typewriter Effect Logic
        document.querySelectorAll('.typewriter-text').forEach(el => {
            const text = el.getAttribute('data-text');
            let i = 0;
            const type = () => {
                if (i < text.length) { el.innerHTML += text.charAt(i); i++; setTimeout(type, 35); }
            };
            setTimeout(type, 800 + Math.random() * 500);
        });

        // Draggable Cards Logic
        document.querySelectorAll('.draggable-card').forEach(wrapper => {
            let isDragging = false, startX, startY, currentX = 0, currentY = 0;
            const originalZ = window.getComputedStyle(wrapper).zIndex;
            const start = (e) => {
                if (e.target.closest('button')) return;
                isDragging = true; wrapper.style.transition = 'none'; wrapper.style.zIndex = '50';
                const clientX = e.touches ? e.touches[0].clientX : e.clientX;
                const clientY = e.touches ? e.touches[0].clientY : e.clientY;
                startX = clientX - currentX; startY = clientY - currentY;
                wrapper.classList.replace('cursor-grab', 'cursor-grabbing');
            };
            const move = (e) => {
                if (!isDragging) return;
                const clientX = e.touches ? e.touches[0].clientX : e.clientX;
                const clientY = e.touches ? e.touches[0].clientY : e.clientY;
                currentX = clientX - startX; currentY = clientY - startY;
                wrapper.style.transform = `translate(${currentX}px, ${currentY}px)`;
            };
            const end = () => {
                if (!isDragging) return;
                isDragging = false; wrapper.style.zIndex = originalZ;
                wrapper.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
                currentX = 0; currentY = 0; wrapper.style.transform = `translate(0px, 0px)`;
                wrapper.classList.replace('cursor-grabbing', 'cursor-grab');
            };
            wrapper.addEventListener('mousedown', start);
            window.addEventListener('mousemove', move);
            window.addEventListener('mouseup', end);
            wrapper.addEventListener('touchstart', start, {passive: true});
            window.addEventListener('touchmove', (e) => { if(isDragging) e.preventDefault(); move(e); }, {passive: false});
            window.addEventListener('touchend', end);
        });
  </script>
</div>
All Prompts