css-3d-carousel

ui

src

tailwind.css

css
@import "tailwindcss";

@theme {
    @keyframes animate-rotate {
        from { transform: perspective(1200px) rotateY(0deg) }
        to   { transform: perspective(1200px) rotateY(-360deg) }
    }
    --animate-rotate: animate-rotate 15s infinite linear;
}

@utility animate-paused {
    animation-play-state: paused;
}

page.tsx

tsx
export default function Page() {

    const images = [
        "https://cdn.pixabay.com/photo/2023/05/08/08/41/ai-7977960_1280.jpg",
        "https://cdn.pixabay.com/photo/2020/05/25/17/03/merry-christmas-5219496_1280.jpg",
        "https://cdn.pixabay.com/photo/2020/07/08/04/12/work-5382501_1280.jpg",
        "https://cdn.pixabay.com/photo/2014/07/06/13/55/calculator-385506_1280.jpg",
        "https://cdn.pixabay.com/photo/2020/04/20/18/10/cinema-5069314_1280.jpg",
        "https://cdn.pixabay.com/photo/2016/03/11/02/08/speedometer-1249610_1280.jpg",
        "https://cdn.pixabay.com/photo/2016/11/21/16/27/laptop-1846277_1280.jpg",
        "https://cdn.pixabay.com/photo/2015/10/21/08/22/media-998990_1280.jpg",
        "https://cdn.pixabay.com/photo/2018/05/08/08/44/artificial-intelligence-3382507_1280.jpg",
    ];

    return (
        <div className="group">
            <div className="flex justify-center items-center bg-black py-32 cursor-pointer">
                <section
                    className="relative w-60 aspect-video
                               transform-[perspective(1200px)] transform-3d animate-rotate
                               group-hover:animate-paused">
                    {
                        images.map((url, i) => (
                            <img className="absolute inset-0 object-cover"
                                 style={ {
                                     transform: `rotateY(${ 360 / images.length * i }deg) translateZ(480px)`,
                                 } }
                                 src={ url }
                                 alt=""
                                 key={ i }/>
                        ))
                    }
                </section>
            </div>
        </div>
    )
}

video