Nazmul Hub | Enterprise Header

3D Product Card Slider with Perspective Effect

Full Code :

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Arcane Vapor β€” 3D Perspective Experience</title>
    <style>
        :root {
            --primary: #00f2ff;
            --accent: #7000ff;
            --bg: #050505;
            --card-w: 340px;
            --card-h: 480px;
            --transition: cubic-bezier(0.23, 1, 0.32, 1);
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            user-select: none;
        }

        body {
            background-color: var(--bg);
            color: white;
            font-family: 'Inter', system-ui, -apple-system, sans-serif;
            overflow: hidden;
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        /* Ambient Background */
        .ambient-light {
            position: fixed;
            top: 50%;
            left: 50%;
            width: 60vw;
            height: 60vh;
            background: radial-gradient(circle, rgba(112, 0, 255, 0.15) 0%, rgba(0, 0, 0, 0) 70%);
            transform: translate(-50%, -50%);
            filter: blur(80px);
            z-index: 0;
            pointer-events: none;
        }

        /* Perspective Container */
        .stage {
            perspective: 1200px;
            width: 100%;
            height: 600px;
            display: flex;
            align-items: center;
            justify-content: center;
            position: relative;
            z-index: 1;
        }

        .slider-track {
            display: flex;
            gap: 40px;
            transform-style: preserve-3d;
            will-change: transform;
            cursor: grab;
            padding: 0 20%;
        }

        .slider-track:active {
            cursor: grabbing;
        }

        /* Product Card */
        .card {
            position: relative;
            min-width: var(--card-w);
            height: var(--card-h);
            background: rgba(255, 255, 255, 0.03);
            border-radius: 24px;
            border: 1px solid rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(10px);
            transform-style: preserve-3d;
            transition: border-color 0.4s ease;
            display: flex;
            flex-direction: column;
            padding: 30px;
            overflow: hidden;
        }

        .card::before {
            content: '';
            position: absolute;
            inset: 0;
            background: radial-gradient(circle at var(--px) var(--py), rgba(255,255,255,0.15) 0%, transparent 80%);
            opacity: 0;
            transition: opacity 0.3s;
        }

        .card:hover::before {
            opacity: 1;
        }

        /* Product Visuals */
        .product-image-container {
            position: relative;
            width: 100%;
            height: 220px;
            transform-style: preserve-3d;
            pointer-events: none;
        }

        .product-image {
            width: 120%;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%) translateZ(50px);
            filter: drop-shadow(0 20px 30px rgba(0,0,0,0.5));
            transition: transform 0.2s ease-out;
        }

        /* Card Content */
        .card-info {
            margin-top: auto;
            transform: translateZ(30px);
        }

        .tag {
            font-size: 10px;
            text-transform: uppercase;
            letter-spacing: 2px;
            color: var(--primary);
            margin-bottom: 8px;
            display: block;
        }

        .title {
            font-size: 24px;
            font-weight: 800;
            margin-bottom: 12px;
            line-height: 1.1;
        }

        .price-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-top: 20px;
        }

        .price {
            font-size: 18px;
            font-weight: 300;
            opacity: 0.8;
        }

        .buy-btn {
            background: white;
            color: black;
            border: none;
            padding: 10px 20px;
            border-radius: 30px;
            font-weight: 700;
            font-size: 12px;
            cursor: pointer;
            transition: transform 0.2s, background 0.2s;
        }

        .buy-btn:hover {
            transform: scale(1.05);
            background: var(--primary);
        }

        /* Navigation UI */
        .controls {
            position: absolute;
            bottom: 50px;
            display: flex;
            gap: 20px;
            align-items: center;
            z-index: 10;
        }

        .nav-dot {
            width: 40px;
            height: 2px;
            background: rgba(255,255,255,0.2);
            transition: 0.4s;
        }

        .nav-dot.active {
            background: var(--primary);
            width: 80px;
        }

        .ui-overlay {
            position: fixed;
            top: 40px;
            left: 40px;
            z-index: 100;
        }

        .logo {
            font-weight: 900;
            letter-spacing: -1px;
            font-size: 20px;
            display: flex;
            align-items: center;
            gap: 10px;
        }

        .logo-box {
            width: 12px;
            height: 12px;
            background: var(--primary);
            rotate: 45deg;
        }
    </style>
</head>
<body>

    <div class="ambient-light" id="ambient"></div>


    </div>

    <div class="stage" id="stage">
        <div class="slider-track" id="track">
            <!-- Card 1 -->
            <div class="card" data-index="0">
                <div class="product-image-container">
                    <img src="https://travel.nazmulhub.com/wp-content/uploads/2026/01/AIRJORDAN9RETRO.avif" alt="Sneaker" class="product-image">
                </div>
                <div class="card-info">
                    <h2 class="title">Air Jordan 9 Retro<br>French Blue</h2>
                    <div class="price-row">
                        <span class="price">$240.00</span>
                        <button class="buy-btn">Add to Bag</button>
                    </div>
                </div>
            </div>

            <!-- Card 2 -->
            <div class="card" data-index="1">
                <div class="product-image-container">
                    <img src="https://travel.nazmulhub.com/wp-content/uploads/2026/01/26230-6-nike-shoes-clipart.png" alt="Sneaker" class="product-image">
                </div>
                <div class="card-info">
                    <h2 class="title">GLITCH ASPECT<br>GHOST</h2>
                    <div class="price-row">
                        <span class="price">$185.00</span>
                        <button class="buy-btn">Add to Bag</button>
                    </div>
                </div>
            </div>

            <!-- Card 3 -->
            <div class="card" data-index="2">
                <div class="product-image-container">
                    <img src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?auto=format&fit=crop&w=800&q=80" alt="Sneaker" class="product-image">
                </div>
                <div class="card-info">
                    <h2 class="title">CRIMSON<br>ECLIPSE</h2>
                    <div class="price-row">
                        <span class="price">$210.00</span>
                        <button class="buy-btn">Add to Bag</button>
                    </div>
                </div>
            </div>

            <!-- Card 4 -->
            <div class="card" data-index="3">
                <div class="product-image-container">
                    <img src="https://images.unsplash.com/photo-1600185365483-26d7a4cc7519?auto=format&fit=crop&w=800&q=80" alt="Sneaker" class="product-image">
                </div>
                <div class="card-info">
    
                    <h2 class="title">ZENITH<br>SPECTRUM</h2>
                    <div class="price-row">
                        <span class="price">$320.00</span>
                        <button class="buy-btn">Add to Bag</button>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <div class="controls" id="controls"></div>

    <script>
        const track = document.getElementById('track');
        const cards = document.querySelectorAll('.card');
        const controls = document.getElementById('controls');
        const ambient = document.getElementById('ambient');

        let isDragging = false;
        let startX = 0;
        let currentTranslate = 0;
        let prevTranslate = 0;
        let animationID = 0;
        let currentIndex = 0;

        // Initialize Nav Dots
        cards.forEach((_, i) => {
            const dot = document.createElement('div');
            dot.classList.add('nav-dot');
            if (i === 0) dot.classList.add('active');
            controls.appendChild(dot);
        });

        // Mouse & Touch Events
        track.addEventListener('mousedown', dragStart);
        track.addEventListener('touchstart', dragStart);
        track.addEventListener('mouseup', dragEnd);
        track.addEventListener('touchend', dragEnd);
        track.addEventListener('mousemove', dragAction);
        track.addEventListener('touchmove', dragAction);
        window.addEventListener('mousemove', handleHoverEffect);

        function dragStart(e) {
            isDragging = true;
            startX = getPositionX(e);
            animationID = requestAnimationFrame(animation);
            track.style.transition = 'none';
        }

        function dragEnd() {
            isDragging = false;
            cancelAnimationFrame(animationID);
            
            const movedBy = currentTranslate - prevTranslate;
            if (movedBy < -100 && currentIndex < cards.length - 1) currentIndex += 1;
            if (movedBy > 100 && currentIndex > 0) currentIndex -= 1;

            setPositionByIndex();
        }

        function dragAction(e) {
            if (isDragging) {
                const currentPosition = getPositionX(e);
                currentTranslate = prevTranslate + currentPosition - startX;
            }
        }

        function getPositionX(e) {
            return e.type.includes('mouse') ? e.pageX : e.touches[0].clientX;
        }

        function animation() {
            setSliderPosition();
            if (isDragging) requestAnimationFrame(animation);
        }

        function setSliderPosition() {
            track.style.transform = `translateX(${currentTranslate}px)`;
            updateCardParallax();
        }

        function setPositionByIndex() {
            currentTranslate = currentIndex * -(340 + 40); // card width + gap
            prevTranslate = currentTranslate;
            track.style.transition = 'transform 0.6s cubic-bezier(0.23, 1, 0.32, 1)';
            setSliderPosition();
            updateDots();
        }

        function updateDots() {
            document.querySelectorAll('.nav-dot').forEach((dot, i) => {
                dot.classList.toggle('active', i === currentIndex);
            });
        }

        // The "Secret Sauce": 3D Proximity Calculation
        function updateCardParallax() {
            const centerX = window.innerWidth / 2;
            
            cards.forEach(card => {
                const rect = card.getBoundingClientRect();
                const cardCenter = rect.left + rect.width / 2;
                const distanceFromCenter = cardCenter - centerX;
                
                // Dynamic Rotation based on distance from viewport center
                const rotateY = distanceFromCenter / 15;
                const scale = Math.max(0.8, 1 - Math.abs(distanceFromCenter) / 2000);
                const opacity = Math.max(0.4, 1 - Math.abs(distanceFromCenter) / 1000);
                
                card.style.transform = `rotateY(${rotateY}deg) scale(${scale})`;
                card.style.opacity = opacity;

                // Move internal image slightly for extra depth
                const img = card.querySelector('.product-image');
                img.style.transform = `translate(-50%, -50%) translateZ(100px) translateX(${distanceFromCenter / 10}px)`;
            });
        }

        // Lighting and Tilt Reactive behavior
        function handleHoverEffect(e) {
            const x = e.clientX;
            const y = e.clientY;

            // Ambient background follows mouse
            ambient.style.left = `${x}px`;
            ambient.style.top = `${y}px`;

            cards.forEach(card => {
                const rect = card.getBoundingClientRect();
                const px = ((e.clientX - rect.left) / rect.width) * 100;
                const py = ((e.clientY - rect.top) / rect.height) * 100;
                
                // Set CSS variables for the spotlight effect
                card.style.setProperty('--px', `${px}%`);
                card.style.setProperty('--py', `${py}%`);
                
                // Subtle local tilt on hover
                if (e.target.closest('.card') === card) {
                    const tiltX = (y - (rect.top + rect.height/2)) / 15;
                    const tiltY = (x - (rect.left + rect.width/2)) / 15;
                    card.style.transform += ` rotateX(${-tiltX}deg) rotateY(${tiltY}deg)`;
                }
            });
        }

        // Initial Position
        setPositionByIndex();

    </script>
</body>
</html>

My Services

II offer complete digital solutions that help brands grow online β€”
from designing modern websites to creating powerful marketing campaigns. Every project is built with passion, creativity, and precision.