Back to tips

10 CSS Spinner Examples

Discover 10 great CSS spinner examples to enhance your web design. Easy to implement and visually appealing for any project.

Spinners are essential UI elements that enhance user experience by indicating loading processes. They keep users engaged and informed, ensuring a seamless interaction.

In this article, we explore 10 spinner examples that can elevate your web design. Each example showcases unique styles and functionalities to inspire your next project.

10 Spinner Examples

1) Social Media Loader

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Social Media Loader</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Inter', 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        }

        body {
            width: 100%;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #f9f9fb;
            overflow: hidden;
        }

        .loader-container {
            position: relative;
            width: 100%;
            max-width: 500px;
            height: 450px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            background-color: white;
            border-radius: 24px;
            box-shadow: 0 12px 32px rgba(0, 0, 0, 0.05);
            padding: 2rem;
            overflow: hidden;
            transition: all 0.4s ease;
        }

        .loader-container:hover {
            transform: translateY(-5px);
            box-shadow: 0 18px 42px rgba(0, 0, 0, 0.08);
        }

        .loader-heading {
            font-size: 1.8rem;
            font-weight: 700;
            color: #333;
            margin-bottom: 1rem;
            text-align: center;
        }

        .loader-subheading {
            font-size: 1rem;
            font-weight: 400;
            color: #666;
            text-align: center;
            margin-bottom: 2.5rem;
            max-width: 320px;
            line-height: 1.5;
        }

        .loader-wrapper {
            position: relative;
            width: 120px;
            height: 120px;
            margin-bottom: 2.5rem;
        }

        .spinner {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            border: 4px solid transparent;
            border-top-color: #6366F1;
            animation: spin 1.8s cubic-bezier(0.39, 0.575, 0.565, 1) infinite;
        }

        .spinner:nth-child(1) {
            border-top-color: #6366F1;
        }

        .spinner:nth-child(2) {
            border-top-color: #8B5CF6;
            width: 85%;
            height: 85%;
            top: 7.5%;
            left: 7.5%;
            animation-delay: -0.2s;
            animation-duration: 1.6s;
        }

        .spinner:nth-child(3) {
            border-top-color: #EC4899;
            width: 70%;
            height: 70%;
            top: 15%;
            left: 15%;
            animation-delay: -0.4s;
            animation-duration: 1.4s;
        }

        .spinner-center {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 50%;
            height: 50%;
            background: linear-gradient(135deg, #6366F1, #EC4899);
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-size: 0.75rem;
            font-weight: 600;
            box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
            animation: pulse 2s cubic-bezier(0.4, 0, 0.2, 1) infinite;
        }

        .status-container {
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .status-text {
            font-size: 1rem;
            font-weight: 600;
            color: #333;
            margin-bottom: 0.5rem;
        }

        .progress-text {
            font-size: 0.85rem;
            color: #666;
            margin-bottom: 1rem;
            min-height: 20px;
        }

        .activity-indicator {
            display: flex;
            gap: 8px;
            margin-bottom: 1.5rem;
        }

        .activity-dot {
            width: 8px;
            height: 8px;
            border-radius: 50%;
            background-color: #d1d5db;
        }

        .activity-dot.active {
            animation: fadeInOut 1.5s infinite;
        }

        .activity-dot:nth-child(1).active {
            animation-delay: 0s;
            background-color: #6366F1;
        }

        .activity-dot:nth-child(2).active {
            animation-delay: 0.3s;
            background-color: #8B5CF6;
        }

        .activity-dot:nth-child(3).active {
            animation-delay: 0.6s;
            background-color: #EC4899;
        }

        .cancel-button {
            background: none;
            border: none;
            color: #6366F1;
            font-size: 0.9rem;
            font-weight: 600;
            cursor: pointer;
            padding: 8px 16px;
            border-radius: 8px;
            transition: all 0.2s ease;
        }

        .cancel-button:hover {
            background-color: rgba(99, 102, 241, 0.1);
        }

        .pulse-ring {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 150%;
            height: 150%;
            border-radius: 50%;
            border: 2px solid rgba(99, 102, 241, 0.5);
            opacity: 0;
            animation: pulse-ring 3s cubic-bezier(0.39, 0.575, 0.565, 1) infinite;
        }

        .pulse-ring:nth-child(2) {
            animation-delay: 1s;
        }

        .network-icon {
            position: absolute;
            width: 28px;
            height: 28px;
            border-radius: 50%;
            background: white;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
            display: flex;
            justify-content: center;
            align-items: center;
            animation: float 3s infinite ease-in-out;
        }

        .network-icon:nth-child(1) {
            top: 10%;
            left: 15%;
            animation-delay: 0.2s;
        }

        .network-icon:nth-child(2) {
            top: 20%;
            right: 15%;
            animation-delay: 0.5s;
        }

        .network-icon:nth-child(3) {
            bottom: 15%;
            left: 20%;
            animation-delay: 0.8s;
        }

        .network-icon:nth-child(4) {
            bottom: 10%;
            right: 20%;
            animation-delay: 1.1s;
        }

        .network-icon i {
            font-size: 1rem;
            color: #6366F1;
        }

        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            80%, 100% {
                transform: rotate(360deg);
            }
        }

        @keyframes pulse {
            0% {
                transform: scale(1);
            }
            50% {
                transform: scale(1.1);
            }
            100% {
                transform: scale(1);
            }
        }

        @keyframes fadeInOut {
            0%, 100% {
                opacity: 0.4;
            }
            50% {
                opacity: 1;
            }
        }

        @keyframes pulse-ring {
            0% {
                opacity: 0.5;
                transform: translate(-50%, -50%) scale(0.8);
            }
            100% {
                opacity: 0;
                transform: translate(-50%, -50%) scale(1.2);
            }
        }

        @keyframes float {
            0%, 100% {
                transform: translateY(0);
            }
            50% {
                transform: translateY(-8px);
            }
        }

        @media (max-width: 600px) {
            .loader-container {
                max-width: 90%;
                height: auto;
                padding: 1.5rem;
            }

            .loader-heading {
                font-size: 1.5rem;
            }

            .loader-wrapper {
                width: 100px;
                height: 100px;
            }
        }
    </style>
</head>
<body>
    <div class="loader-container">
        <div class="network-icon"><i>📸</i></div>
        <div class="network-icon"><i>📱</i></div>
        <div class="network-icon"><i>💬</i></div>
        <div class="network-icon"><i>❤️</i></div>

        <h1 class="loader-heading">Syncing your social world</h1>
        <p class="loader-subheading">We're connecting to your friends and updating your feeds with the latest content</p>

        <div class="loader-wrapper">
            <div class="pulse-ring"></div>
            <div class="pulse-ring"></div>
            <div class="spinner"></div>
            <div class="spinner"></div>
            <div class="spinner"></div>
            <div class="spinner-center">
                <span id="percentage">0%</span>
            </div>
        </div>

        <div class="status-container">
            <div class="status-text" id="status-text">Establishing connection</div>
            <div class="progress-text" id="progress-text"></div>
            <div class="activity-indicator">
                <div class="activity-dot active"></div>
                <div class="activity-dot active"></div>
                <div class="activity-dot active"></div>
            </div>
            <button class="cancel-button" id="cancel-button">Cancel sync</button>
        </div>
    </div>

    <script>
        const statusMessages = [
            "Establishing connection",
            "Retrieving friend updates",
            "Syncing message history",
            "Downloading media items",
            "Updating story feed",
            "Syncing profile changes",
            "Finishing up"
        ];

        const progressMessages = [
            "Connecting to remote servers...",
            "Scanning for new content...",
            "Backing up your messages...",
            "Processing new photos and videos...",
            "Refreshing your timeline...",
            "Applying latest settings...",
            "Almost there!"
        ];

        const statusText = document.getElementById('status-text');
        const progressText = document.getElementById('progress-text');
        const percentageText = document.getElementById('percentage');
        const cancelButton = document.getElementById('cancel-button');

        let currentStep = 0;
        let percentage = 0;
        let progressInterval;
        let messageInterval;

        function startSync() {
            updateStatusMessage();
            
            progressInterval = setInterval(() => {
                percentage += 1;
                
                if (percentage > 100) {
                    percentage = 100;
                    clearInterval(progressInterval);
                    completeSync();
                    return;
                }
                
                percentageText.textContent = `${percentage}%`;
                
                // Change status message at certain percentage milestones
                if (percentage === 15) changeStatusMessage(1);
                if (percentage === 35) changeStatusMessage(2);
                if (percentage === 50) changeStatusMessage(3);
                if (percentage === 65) changeStatusMessage(4);
                if (percentage === 80) changeStatusMessage(5);
                if (percentage === 95) changeStatusMessage(6);
                
            }, 120);

            // Cycle through different progress messages
            messageInterval = setInterval(() => {
                progressText.textContent = getRandomSubProgressMessage();
            }, 2500);
        }

        function changeStatusMessage(step) {
            currentStep = step;
            updateStatusMessage();
        }

        function updateStatusMessage() {
            statusText.textContent = statusMessages[currentStep];
            progressText.textContent = progressMessages[currentStep];
        }

        function getRandomSubProgressMessage() {
            const subMessages = [
                "Processing data packet " + Math.floor(Math.random() * 100) + " of 100",
                "Checking for " + Math.floor(Math.random() * 30) + " new notifications",
                "Authenticating with secure servers",
                "Optimizing your experience",
                "Applying privacy settings",
                "Buffering media content",
                "Checking for updates"
            ];
            return subMessages[Math.floor(Math.random() * subMessages.length)];
        }

        function completeSync() {
            clearInterval(messageInterval);
            statusText.textContent = "Sync completed successfully!";
            progressText.textContent = "Your social media is now up to date";
            cancelButton.textContent = "Done";
            
            // Reset the animation after 3 seconds
            setTimeout(() => {
                percentage = 0;
                currentStep = 0;
                percentageText.textContent = `${percentage}%`;
                cancelButton.textContent = "Cancel sync";
                startSync();
            }, 3000);
        }

        cancelButton.addEventListener('click', function() {
            if (cancelButton.textContent === "Done") {
                percentage = 0;
                currentStep = 0;
                percentageText.textContent = `${percentage}%`;
                cancelButton.textContent = "Cancel sync";
                startSync();
                return;
            }
            
            // Cancel the sync
            clearInterval(progressInterval);
            clearInterval(messageInterval);
            statusText.textContent = "Sync cancelled";
            progressText.textContent = "You can restart the sync anytime";
            cancelButton.textContent = "Restart";
            
            // Animate percentage back to zero
            const decreaseInterval = setInterval(() => {
                percentage -= 2;
                if (percentage <= 0) {
                    percentage = 0;
                    clearInterval(decreaseInterval);
                }
                percentageText.textContent = `${percentage}%`;
            }, 20);
        });

        // Start the animation when the page loads
        window.addEventListener('load', startSync);
    </script>
</body>
</html>

2) Corporate Minimalist Loader

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Corporate Minimalist Spinner</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Arial', sans-serif;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 700px;
            width: 100%;
            background-color: #f9f9f9;
            overflow: hidden;
        }

        .dashboard-container {
            width: 650px;
            height: 650px;
            background-color: #ffffff;
            border-radius: 10px;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.05);
            padding: 2rem;
            display: flex;
            flex-direction: column;
            position: relative;
            overflow: hidden;
        }

        .dashboard-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 2rem;
        }

        .dashboard-title {
            font-size: 1.5rem;
            font-weight: 600;
            color: #333;
        }

        .dashboard-subtitle {
            font-size: 0.9rem;
            color: #888;
            margin-top: 0.25rem;
        }

        .loading-container {
            position: relative;
            flex-grow: 1;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
        }

        .spinner-container {
            position: relative;
            width: 180px;
            height: 180px;
            margin-bottom: 2rem;
        }

        .spinner {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            border: 4px solid transparent;
            border-top-color: #333;
            animation: spin 1.5s linear infinite;
        }

        .spinner-inner {
            position: absolute;
            top: 15px;
            left: 15px;
            right: 15px;
            bottom: 15px;
            border-radius: 50%;
            border: 4px solid transparent;
            border-top-color: #888;
            animation: spin 2s linear infinite reverse;
        }

        .spinner-center {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 30px;
            height: 30px;
            background-color: #333;
            border-radius: 50%;
            z-index: 2;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
        }

        .spinner-pulse {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 180px;
            height: 180px;
            border-radius: 50%;
            background-color: rgba(51, 51, 51, 0.05);
            animation: pulse 2s ease-out infinite;
        }

        .progress-text {
            font-size: 1.2rem;
            font-weight: 500;
            color: #333;
            margin-top: 1rem;
            letter-spacing: 0.05em;
        }

        .status-message {
            font-size: 0.9rem;
            color: #888;
            margin-top: 0.5rem;
            max-width: 300px;
            text-align: center;
            line-height: 1.5;
        }

        .dashboard-footer {
            margin-top: auto;
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding-top: 1.5rem;
            border-top: 1px solid #f0f0f0;
        }

        .cancel-btn {
            background: none;
            border: none;
            color: #888;
            font-size: 0.9rem;
            cursor: pointer;
            transition: color 0.3s;
        }

        .cancel-btn:hover {
            color: #333;
        }

        .progress-bar {
            position: absolute;
            bottom: 0;
            left: 0;
            height: 4px;
            background-color: #333;
            width: 0%;
            transition: width 0.3s ease;
        }

        .timestamp {
            font-size: 0.8rem;
            color: #aaa;
        }

        .speed-control {
            display: flex;
            gap: 0.5rem;
            align-items: center;
            margin-top: 0.5rem;
        }

        .speed-btn {
            background: none;
            border: 1px solid #eee;
            padding: 0.2rem 0.5rem;
            font-size: 0.8rem;
            border-radius: 3px;
            cursor: pointer;
            transition: all 0.3s;
        }

        .speed-btn:hover, .speed-btn.active {
            background-color: #f0f0f0;
            color: #333;
        }

        .speed-btn.active {
            border-color: #ddd;
            font-weight: 600;
        }

        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }

        @keyframes pulse {
            0% {
                transform: translate(-50%, -50%) scale(0.8);
                opacity: 0.7;
            }
            100% {
                transform: translate(-50%, -50%) scale(1.2);
                opacity: 0;
            }
        }

        @media (max-width: 700px) {
            .dashboard-container {
                width: 95%;
                height: auto;
                min-height: 500px;
            }

            .spinner-container {
                width: 120px;
                height: 120px;
            }

            .spinner-pulse {
                width: 120px;
                height: 120px;
            }

            .dashboard-header {
                flex-direction: column;
                align-items: flex-start;
            }
        }

        /* Dark mode toggle */
        .mode-switch {
            position: absolute;
            top: 1rem;
            right: 1rem;
            width: 40px;
            height: 20px;
            background-color: #eee;
            border-radius: 10px;
            cursor: pointer;
            transition: background-color 0.3s;
        }

        .mode-switch::after {
            content: "";
            position: absolute;
            top: 2px;
            left: 2px;
            width: 16px;
            height: 16px;
            background-color: #fff;
            border-radius: 50%;
            transition: transform 0.3s;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
        }

        body.dark-mode {
            background-color: #1a1a1a;
        }

        body.dark-mode .dashboard-container {
            background-color: #222;
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
        }

        body.dark-mode .dashboard-title,
        body.dark-mode .progress-text {
            color: #f0f0f0;
        }

        body.dark-mode .dashboard-subtitle,
        body.dark-mode .status-message,
        body.dark-mode .cancel-btn {
            color: #aaa;
        }

        body.dark-mode .spinner {
            border-top-color: #f0f0f0;
        }

        body.dark-mode .spinner-inner {
            border-top-color: #aaa;
        }

        body.dark-mode .spinner-center {
            background-color: #f0f0f0;
        }

        body.dark-mode .dashboard-footer {
            border-top-color: #333;
        }

        body.dark-mode .progress-bar {
            background-color: #f0f0f0;
        }

        body.dark-mode .speed-btn {
            border-color: #333;
            color: #aaa;
        }

        body.dark-mode .speed-btn:hover,
        body.dark-mode .speed-btn.active {
            background-color: #333;
            color: #f0f0f0;
        }

        body.dark-mode .mode-switch {
            background-color: #666;
        }

        body.dark-mode .mode-switch::after {
            transform: translateX(20px);
            background-color: #222;
        }
    </style>
</head>
<body>
    <div class="dashboard-container">
        <div class="dashboard-header">
            <div>
                <h1 class="dashboard-title">Data Processing</h1>
                <p class="dashboard-subtitle">Enterprise Analytics Pipeline</p>
            </div>
        </div>
        
        <div class="mode-switch" id="modeSwitch"></div>
        
        <div class="loading-container">
            <div class="spinner-pulse"></div>
            <div class="spinner-container">
                <div class="spinner"></div>
                <div class="spinner-inner"></div>
                <div class="spinner-center"></div>
            </div>
            <p class="progress-text" id="progressText">Processing 45%</p>
            <p class="status-message" id="statusMessage">Aggregating quarterly performance metrics across departments</p>
            
            <div class="speed-control">
                <button class="speed-btn" data-speed="slow">Slow</button>
                <button class="speed-btn active" data-speed="normal">Normal</button>
                <button class="speed-btn" data-speed="fast">Fast</button>
            </div>
        </div>
        
        <div class="dashboard-footer">
            <button class="cancel-btn">Cancel Process</button>
            <span class="timestamp" id="timestamp">Last update: Just now</span>
        </div>
        
        <div class="progress-bar" id="progressBar"></div>
    </div>
    
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // Initial progress values
            let progress = 45;
            let speed = 1;
            
            // Status messages for different progress stages
            const statusMessages = [
                "Initializing secure data connection...",
                "Collecting interdepartmental metrics...",
                "Analyzing year-over-year performance trends...",
                "Aggregating quarterly performance metrics across departments...",
                "Generating executive dashboard visualizations...",
                "Applying predictive analytics models...",
                "Cross-referencing financial indicators...",
                "Finalizing data integrity verification...",
                "Preparing comprehensive quarterly reports...",
                "Process complete. Optimizing dashboard view..."
            ];
            
            // Elements
            const progressBar = document.getElementById('progressBar');
            const progressText = document.getElementById('progressText');
            const statusMessage = document.getElementById('statusMessage');
            const timestamp = document.getElementById('timestamp');
            const cancelBtn = document.querySelector('.cancel-btn');
            const speedBtns = document.querySelectorAll('.speed-btn');
            const modeSwitch = document.getElementById('modeSwitch');
            
            // Update progress bar and text
            function updateProgress() {
                if (progress < 100) {
                    progress += (0.2 * speed);
                    if (progress > 100) progress = 100;
                    
                    progressBar.style.width = `${progress}%`;
                    progressText.textContent = `Processing ${Math.floor(progress)}%`;
                    
                    // Update status message based on progress
                    const messageIndex = Math.min(Math.floor(progress / 11), statusMessages.length - 1);
                    statusMessage.textContent = statusMessages[messageIndex];
                    
                    // Update timestamp periodically
                    if (Math.random() > 0.9) {
                        const now = new Date();
                        const timeString = now.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
                        timestamp.textContent = `Last update: ${timeString}`;
                    }
                    
                    setTimeout(updateProgress, 100);
                } else {
                    progressText.textContent = 'Process Complete';
                    statusMessage.textContent = statusMessages[statusMessages.length - 1];
                    cancelBtn.textContent = 'View Results';
                }
            }
            
            // Initialize the progress
            setTimeout(updateProgress, 500);
            
            // Speed control
            speedBtns.forEach(btn => {
                btn.addEventListener('click', function() {
                    speedBtns.forEach(b => b.classList.remove('active'));
                    this.classList.add('active');
                    
                    const selectedSpeed = this.getAttribute('data-speed');
                    switch(selectedSpeed) {
                        case 'slow':
                            speed = 0.5;
                            break;
                        case 'normal':
                            speed = 1;
                            break;
                        case 'fast':
                            speed = 2;
                            break;
                    }
                });
            });
            
            // Dark mode toggle
            modeSwitch.addEventListener('click', function() {
                document.body.classList.toggle('dark-mode');
            });
            
            // Cancel button hover animation
            cancelBtn.addEventListener('mouseenter', function() {
                this.style.transition = 'transform 0.3s';
                this.style.transform = 'translateY(-2px)';
            });
            
            cancelBtn.addEventListener('mouseleave', function() {
                this.style.transform = 'translateY(0)';
            });
            
            // Reset button
            cancelBtn.addEventListener('click', function() {
                if (progress < 100) {
                    progress = 0;
                    progressBar.style.width = '0%';
                    progressText.textContent = 'Process Cancelled';
                    statusMessage.textContent = 'Operation has been cancelled. Click to restart.';
                    setTimeout(() => {
                        progress = 0;
                        updateProgress();
                    }, 2000);
                } else {
                    // Reset after completion
                    progress = 0;
                    progressBar.style.width = '0%';
                    cancelBtn.textContent = 'Cancel Process';
                    setTimeout(updateProgress, 500);
                }
            });
        });
    </script>
</body>
</html>

3) Dynamic Finance Loader

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Finance App Loader</title>
    <style>
        :root {
            --primary: #476C9B;
            --secondary: #984447;
            --accent: #ADD9F4;
            --neutral-dark: #2B2D42;
            --neutral-light: #EDF2F4;
            --gold: #D5A021;
            --silver: #C0C0C0;
            --platinum: #E5E4E2;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background: linear-gradient(135deg, var(--neutral-dark) 0%, #1A1B29 100%);
            overflow: hidden;
        }

        .app-container {
            width: 100%;
            max-width: 700px;
            height: 700px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            position: relative;
            padding: 2rem;
        }

        .demo-screen {
            width: 100%;
            max-width: 400px;
            background: var(--neutral-dark);
            border-radius: 16px;
            box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
            padding: 2rem;
            color: var(--neutral-light);
            position: relative;
            overflow: hidden;
            z-index: 1;
        }

        .demo-screen::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(135deg, rgba(0, 0, 0, 0.05) 0%, rgba(0, 0, 0, 0.2) 100%);
            z-index: -1;
        }

        .demo-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 1.5rem;
        }

        .demo-logo {
            display: flex;
            align-items: center;
        }

        .demo-logo-icon {
            width: 24px;
            height: 24px;
            background: var(--gold);
            border-radius: 6px;
            margin-right: 8px;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .demo-logo-icon::before {
            content: '$';
            font-weight: bold;
            color: var(--neutral-dark);
            font-size: 16px;
        }

        .demo-logo-text {
            font-weight: 600;
            font-size: 18px;
            color: var(--neutral-light);
        }

        .demo-user {
            width: 32px;
            height: 32px;
            background: var(--primary);
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            color: var(--neutral-light);
            font-weight: bold;
            font-size: 14px;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .demo-user:hover {
            transform: scale(1.1);
            box-shadow: 0 0 15px rgba(71, 108, 155, 0.5);
        }

        .loader-container {
            width: 100%;
            height: 280px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            position: relative;
            margin-bottom: 1.5rem;
        }

        .loader-spinner {
            width: 100px;
            height: 100px;
            position: relative;
            margin-bottom: 2rem;
        }

        .spinner-segment {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            border: 4px solid transparent;
            box-sizing: border-box;
        }

        .segment-1 {
            border-top-color: var(--platinum);
            animation: spin1 1.5s ease-in-out infinite;
        }

        .segment-2 {
            border-right-color: var(--silver);
            animation: spin2 1.5s ease-in-out infinite;
        }

        .segment-3 {
            border-bottom-color: var(--gold);
            animation: spin3 1.5s ease-in-out infinite;
        }

        @keyframes spin1 {
            0% { transform: rotate(0deg); border-width: 4px; }
            50% { transform: rotate(180deg); border-width: 6px; }
            100% { transform: rotate(360deg); border-width: 4px; }
        }

        @keyframes spin2 {
            0% { transform: rotate(90deg); border-width: 4px; }
            50% { transform: rotate(270deg); border-width: 6px; }
            100% { transform: rotate(450deg); border-width: 4px; }
        }

        @keyframes spin3 {
            0% { transform: rotate(180deg); border-width: 4px; }
            50% { transform: rotate(360deg); border-width: 6px; }
            100% { transform: rotate(540deg); border-width: 4px; }
        }

        .loader-inner {
            position: absolute;
            width: 70px;
            height: 70px;
            background: linear-gradient(135deg, var(--silver) 0%, var(--platinum) 100%);
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            color: var(--neutral-dark);
            font-weight: bold;
            font-size: 12px;
            box-shadow: inset 0 0 15px rgba(0, 0, 0, 0.2);
            animation: pulse 1.5s ease-in-out infinite;
        }

        @keyframes pulse {
            0% { transform: scale(1); opacity: 0.8; }
            50% { transform: scale(1.05); opacity: 1; }
            100% { transform: scale(1); opacity: 0.8; }
        }

        .loader-text {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            text-align: center;
            font-size: 16px;
            font-weight: 500;
            color: var(--neutral-light);
            opacity: 0.9;
        }

        .status-text {
            display: inline-block;
            min-width: 200px;
            position: relative;
            text-align: center;
            margin-top: 10px;
            font-size: 14px;
            color: var(--accent);
            opacity: 0;
            animation: fadeInOut 3s ease-in-out infinite;
        }

        @keyframes fadeInOut {
            0%, 100% { opacity: 0; }
            50% { opacity: 1; }
        }

        .transaction-info {
            background: rgba(255, 255, 255, 0.05);
            border-radius: 12px;
            padding: 1.2rem;
            margin-bottom: 1.5rem;
            border: 1px solid rgba(255, 255, 255, 0.1);
        }

        .transaction-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 0.8rem;
        }

        .transaction-title {
            font-size: 14px;
            font-weight: 600;
            color: var(--neutral-light);
        }

        .transaction-amount {
            font-size: 14px;
            font-weight: 700;
            color: var(--gold);
        }

        .transaction-details {
            display: flex;
            flex-direction: column;
            gap: 0.5rem;
        }

        .detail-row {
            display: flex;
            justify-content: space-between;
            font-size: 12px;
        }

        .detail-label {
            color: rgba(255, 255, 255, 0.5);
        }

        .detail-value {
            color: var(--neutral-light);
            font-weight: 500;
        }

        .cancel-button {
            width: 100%;
            padding: 0.9rem;
            background: transparent;
            border: 1px solid rgba(255, 255, 255, 0.2);
            border-radius: 8px;
            color: var(--neutral-light);
            font-size: 14px;
            font-weight: 500;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .cancel-button:hover {
            background: rgba(255, 255, 255, 0.1);
            border-color: rgba(255, 255, 255, 0.3);
        }

        .geometric-bg {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
        }

        .geometric-shape {
            position: absolute;
            background: linear-gradient(135deg, var(--primary) 0%, rgba(71, 108, 155, 0.3) 100%);
            opacity: 0.1;
            border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
        }

        .shape-1 {
            width: 400px;
            height: 400px;
            top: -150px;
            left: -150px;
            animation: float1 20s ease-in-out infinite;
        }

        .shape-2 {
            width: 300px;
            height: 300px;
            bottom: -100px;
            right: -100px;
            animation: float2 15s ease-in-out infinite;
        }

        @keyframes float1 {
            0%, 100% { transform: translate(0, 0) rotate(0deg); }
            50% { transform: translate(30px, 30px) rotate(5deg); }
        }

        @keyframes float2 {
            0%, 100% { transform: translate(0, 0) rotate(0deg); }
            50% { transform: translate(-30px, -20px) rotate(-5deg); }
        }

        /* Responsive adjustments */
        @media (max-width: 500px) {
            .demo-screen {
                max-width: 320px;
                padding: 1.5rem;
            }

            .loader-spinner {
                width: 80px;
                height: 80px;
            }

            .loader-inner {
                width: 56px;
                height: 56px;
                font-size: 10px;
            }
        }

        @media (max-width: 400px) {
            .demo-screen {
                max-width: 280px;
                padding: 1rem;
            }

            .transaction-info {
                padding: 1rem;
            }
        }
    </style>
</head>
<body>
    <div class="app-container">
        <div class="demo-screen">
            <div class="demo-header">
                <div class="demo-logo">
                    <div class="demo-logo-icon"></div>
                    <div class="demo-logo-text">FinancePro</div>
                </div>
                <div class="demo-user">JP</div>
            </div>

            <div class="loader-container">
                <div class="loader-spinner">
                    <div class="spinner-segment segment-1"></div>
                    <div class="spinner-segment segment-2"></div>
                    <div class="spinner-segment segment-3"></div>
                    <div class="loader-inner">
                        <span id="progress-percentage">67%</span>
                    </div>
                </div>
                <div class="loader-text">Processing Transaction</div>
                <div class="status-text" id="status-message">Verifying account details...</div>
            </div>

            <div class="transaction-info">
                <div class="transaction-header">
                    <div class="transaction-title">International Wire Transfer</div>
                    <div class="transaction-amount">$12,450.00</div>
                </div>
                <div class="transaction-details">
                    <div class="detail-row">
                        <div class="detail-label">From Account</div>
                        <div class="detail-value">••••8742</div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-label">Recipient</div>
                        <div class="detail-value">Globex Corp Ltd.</div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-label">Reference</div>
                        <div class="detail-value">INV-20231105</div>
                    </div>
                    <div class="detail-row">
                        <div class="detail-label">Fee</div>
                        <div class="detail-value">$25.00</div>
                    </div>
                </div>
            </div>

            <button class="cancel-button" id="cancel-btn">Cancel Transaction</button>
        </div>

        <div class="geometric-bg">
            <div class="geometric-shape shape-1"></div>
            <div class="geometric-shape shape-2"></div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const statusMessages = [
                "Verifying account details...",
                "Processing currency conversion...",
                "Calculating exchange rates...",
                "Applying regulatory checks...",
                "Confirming recipient details...",
                "Finalizing transaction..."
            ];

            const progressNumbers = [34, 48, 67, 72, 85, 93, 97];
            
            let currentStatusIndex = 0;
            let currentProgressIndex = 0;
            
            const statusMessageElement = document.getElementById('status-message');
            const progressPercentageElement = document.getElementById('progress-percentage');
            const cancelBtn = document.getElementById('cancel-btn');
            
            // Update status message
            function updateStatusMessage() {
                statusMessageElement.textContent = statusMessages[currentStatusIndex];
                currentStatusIndex = (currentStatusIndex + 1) % statusMessages.length;
            }
            
            // Update progress percentage
            function updateProgressPercentage() {
                if (currentProgressIndex < progressNumbers.length) {
                    progressPercentageElement.textContent = progressNumbers[currentProgressIndex] + '%';
                    currentProgressIndex++;
                }
            }
            
            // Initialize intervals
            const statusInterval = setInterval(updateStatusMessage, 3000);
            const progressInterval = setInterval(updateProgressPercentage, 2500);
            
            // Cancel button with visual feedback
            cancelBtn.addEventListener('click', function() {
                this.textContent = "Cancelling...";
                this.style.background = "rgba(152, 68, 71, 0.2)";
                this.style.borderColor = "var(--secondary)";
                this.style.color = "var(--secondary)";
                
                setTimeout(() => {
                    clearInterval(statusInterval);
                    clearInterval(progressInterval);
                    
                    statusMessageElement.textContent = "Transaction cancelled";
                    statusMessageElement.style.color = "var(--secondary)";
                    statusMessageElement.style.opacity = "1";
                    statusMessageElement.style.animation = "none";
                    
                    progressPercentageElement.textContent = "0%";
                    
                    // Reset the spinner animation
                    document.querySelector('.segment-1').style.animationPlayState = 'paused';
                    document.querySelector('.segment-2').style.animationPlayState = 'paused';
                    document.querySelector('.segment-3').style.animationPlayState = 'paused';
                    document.querySelector('.loader-inner').style.animationPlayState = 'paused';
                    
                    // Update loader text
                    document.querySelector('.loader-text').textContent = "Transaction Cancelled";
                    document.querySelector('.loader-text').style.color = "var(--secondary)";
                }, 1000);
            });

            // Add subtle hover effect to transaction info
            const transactionInfo = document.querySelector('.transaction-info');
            transactionInfo.addEventListener('mouseenter', function() {
                this.style.transform = 'translateY(-2px)';
                this.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.2)';
                this.style.transition = 'all 0.3s ease';
            });
            
            transactionInfo.addEventListener('mouseleave', function() {
                this.style.transform = 'translateY(0)';
                this.style.boxShadow = 'none';
            });
        });
    </script>
</body>
</html>

4) Animated Cart Spinner

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CartSpin - E-Commerce Loading Spinner</title>
    <style>
        :root {
            --primary: #FF4E50;
            --secondary: #FC913A;
            --tertiary: #F9D423;
            --accent: #5CDBBD;
            --accent-dark: #1F8A70;
            --bg: #FAFAFA;
            --text: #212121;
        }

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

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: var(--bg);
            color: var(--text);
            overflow: hidden;
            width: 700px;
            height: 700px;
            margin: 0 auto;
        }

        .spinner-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 100%;
            padding: 2rem;
            position: relative;
        }

        .logo-container {
            position: relative;
            width: 100px;
            height: 100px;
            background-color: white;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
            z-index: 10;
            animation: pulse 2s infinite ease-in-out;
        }

        .logo {
            width: 60px;
            height: 60px;
            position: relative;
        }

        .cart-icon {
            font-size: 2.5rem;
            color: var(--accent-dark);
        }

        .spinner {
            position: absolute;
            width: 160px;
            height: 160px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1;
        }

        .spinner-ring {
            border-radius: 50%;
            position: absolute;
            border: 5px solid transparent;
            animation: spin 1.5s linear infinite;
        }

        .spinner-ring-1 {
            width: 160px;
            height: 160px;
            border-top-color: var(--primary);
            animation-delay: 0s;
        }

        .spinner-ring-2 {
            width: 140px;
            height: 140px;
            border-right-color: var(--secondary);
            animation-delay: 0.2s;
            animation-direction: reverse;
        }

        .spinner-ring-3 {
            width: 120px;
            height: 120px;
            border-bottom-color: var(--tertiary);
            animation-delay: 0.4s;
        }

        .spinner-ring-4 {
            width: 180px;
            height: 180px;
            border-left-color: var(--accent);
            animation-delay: 0.6s;
            animation-direction: reverse;
        }

        .loading-text {
            position: absolute;
            bottom: 1.5rem;
            font-size: 1.2rem;
            color: var(--text);
            text-align: center;
            max-width: 80%;
            animation: fadeInOut 2s infinite ease-in-out;
        }

        .particles {
            position: absolute;
            width: 100%;
            height: 100%;
            z-index: 0;
        }

        .particle {
            position: absolute;
            width: 8px;
            height: 8px;
            background-color: var(--tertiary);
            border-radius: 50%;
            opacity: 0;
            animation: particleAnimation 4s ease-in-out infinite;
        }

        @keyframes spin {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }

        @keyframes pulse {
            0%, 100% {
                transform: scale(1);
                box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
            }
            50% {
                transform: scale(1.1);
                box-shadow: 0 0 25px rgba(0, 0, 0, 0.2);
            }
        }

        @keyframes fadeInOut {
            0%, 100% {
                opacity: 0.5;
            }
            50% {
                opacity: 1;
            }
        }

        @keyframes particleAnimation {
            0% {
                transform: translate(0, 0) scale(0);
                opacity: 0;
            }
            50% {
                opacity: 0.8;
            }
            100% {
                transform: translate(var(--endX), var(--endY)) scale(1);
                opacity: 0;
            }
        }

        .item-preview {
            position: absolute;
            width: 350px;
            height: 80px;
            background-color: white;
            border-radius: 10px;
            bottom: 6rem;
            display: flex;
            align-items: center;
            padding: 0.5rem;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            transform: translateY(20px);
            opacity: 0;
            animation: slideUp 5s infinite cubic-bezier(0.23, 1, 0.32, 1);
            animation-delay: 1s;
        }

        .item-preview img {
            width: 60px;
            height: 60px;
            border-radius: 8px;
            object-fit: cover;
            margin-right: 1rem;
        }

        .item-info {
            flex: 1;
        }

        .item-title {
            font-weight: 600;
            margin-bottom: 0.2rem;
            color: var(--text);
            font-size: 0.9rem;
        }

        .item-price {
            color: var(--primary);
            font-weight: 700;
            font-size: 1rem;
        }

        .item-progress {
            width: 60px;
            height: 60px;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            background: conic-gradient(var(--primary) var(--progress), #eee var(--progress));
            position: relative;
            margin-left: 0.5rem;
        }

        .item-progress::before {
            content: '';
            position: absolute;
            width: 50px;
            height: 50px;
            border-radius: 50%;
            background-color: white;
        }

        .progress-text {
            position: relative;
            z-index: 1;
            font-weight: 700;
            font-size: 0.9rem;
            color: var(--accent-dark);
        }

        @keyframes slideUp {
            0%, 20% {
                transform: translateY(20px);
                opacity: 0;
            }
            25%, 75% {
                transform: translateY(0);
                opacity: 1;
            }
            80%, 100% {
                transform: translateY(-20px);
                opacity: 0;
            }
        }

        /* Product previews */
        .product-category {
            position: absolute;
            width: 160px;
            height: 160px;
            border-radius: 10px;
            background-color: white;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
            opacity: 0;
            transform: scale(0.8);
            transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }

        .product-category.visible {
            opacity: 1;
            transform: scale(1);
        }

        .product-category:nth-child(1) {
            top: 10%;
            left: 10%;
        }

        .product-category:nth-child(2) {
            top: 10%;
            right: 10%;
        }

        .product-category:nth-child(3) {
            bottom: 10%;
            left: 10%;
        }

        .product-category:nth-child(4) {
            bottom: 10%;
            right: 10%;
        }

        .category-icon {
            width: 60px;
            height: 60px;
            background-color: var(--bg);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            margin-bottom: 0.5rem;
            color: var(--accent-dark);
            font-size: 1.5rem;
        }

        .category-name {
            font-weight: 600;
            font-size: 0.9rem;
        }

        @media (max-width: 600px) {
            .product-category {
                width: 120px;
                height: 120px;
            }

            .category-icon {
                width: 50px;
                height: 50px;
                font-size: 1.2rem;
            }

            .category-name {
                font-size: 0.8rem;
            }

            .item-preview {
                width: 300px;
            }
        }

        /* State when spinner is "done" loading */
        .done .spinner-ring {
            animation: none;
            border-color: transparent;
        }

        .done .logo-container {
            animation: doneAnimation 0.5s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275);
        }

        @keyframes doneAnimation {
            0% {
                transform: scale(1);
            }
            50% {
                transform: scale(1.2);
            }
            100% {
                transform: scale(1);
            }
        }

        /* Cart badge */
        .cart-badge {
            position: absolute;
            top: -5px;
            right: -5px;
            width: 22px;
            height: 22px;
            background-color: var(--primary);
            color: white;
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 0.8rem;
            font-weight: bold;
            opacity: 0;
            transform: scale(0);
            transition: all 0.3s ease;
        }

        .cart-badge.show {
            opacity: 1;
            transform: scale(1);
        }
    </style>
</head>
<body>
    <div class="spinner-container" id="spinnerContainer">
        <!-- Particles animation -->
        <div class="particles" id="particles"></div>
        
        <!-- Product categories that appear after loading -->
        <div class="product-category">
            <div class="category-icon">👕</div>
            <div class="category-name">Fashion</div>
        </div>
        <div class="product-category">
            <div class="category-icon">🖥️</div>
            <div class="category-name">Tech</div>
        </div>
        <div class="product-category">
            <div class="category-icon">🏠</div>
            <div class="category-name">Home</div>
        </div>
        <div class="product-category">
            <div class="category-icon">🎮</div>
            <div class="category-name">Gaming</div>
        </div>

        <!-- Main spinner -->
        <div class="spinner">
            <div class="spinner-ring spinner-ring-1"></div>
            <div class="spinner-ring spinner-ring-2"></div>
            <div class="spinner-ring spinner-ring-3"></div>
            <div class="spinner-ring spinner-ring-4"></div>
        </div>
        
        <!-- Center logo -->
        <div class="logo-container">
            <div class="logo">
                <i class="cart-icon">🛒</i>
                <div class="cart-badge" id="cartBadge">0</div>
            </div>
        </div>

        <!-- Product preview that appears during loading -->
        <div class="item-preview">
            <img src="data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='60' height='60' viewBox='0 0 60 60' fill='none'%3E%3Crect width='60' height='60' fill='%23F9D423'/%3E%3Cpath d='M30 25L40 35H20L30 25Z' fill='%235CDBBD'/%3E%3Ccircle cx='30' cy='45' r='5' fill='%23FF4E50'/%3E%3C/svg%3E" alt="Product">
            <div class="item-info">
                <div class="item-title">Limited Edition Bluetooth Earbuds</div>
                <div class="item-price">$129.99</div>
            </div>
            <div class="item-progress" style="--progress: 75%">
                <span class="progress-text">75%</span>
            </div>
        </div>

        <!-- Loading text -->
        <div class="loading-text" id="loadingText">Preparing your personalized shopping experience...</div>
    </div>

    <script>
        // Create particle elements
        function createParticles() {
            const particlesContainer = document.getElementById('particles');
            const numberOfParticles = 30;
            
            for (let i = 0; i < numberOfParticles; i++) {
                const particle = document.createElement('div');
                particle.classList.add('particle');
                
                // Set random positions
                const angle = Math.random() * Math.PI * 2;
                const distance = 100 + Math.random() * 150;
                const endX = Math.cos(angle) * distance;
                const endY = Math.sin(angle) * distance;
                
                particle.style.setProperty('--endX', `${endX}px`);
                particle.style.setProperty('--endY', `${endY}px`);
                
                // Random colors
                const colors = ['#FF4E50', '#FC913A', '#F9D423', '#5CDBBD', '#1F8A70'];
                particle.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
                
                // Random sizes
                const size = 4 + Math.random() * 8;
                particle.style.width = `${size}px`;
                particle.style.height = `${size}px`;
                
                // Random positions
                particle.style.left = '50%';
                particle.style.top = '50%';
                
                // Random animation duration
                const duration = 2 + Math.random() * 3;
                particle.style.animationDuration = `${duration}s`;
                
                // Random animation delay
                const delay = Math.random() * 2;
                particle.style.animationDelay = `${delay}s`;
                
                particlesContainer.appendChild(particle);
            }
        }

        // Loading messages
        const loadingMessages = [
            "Preparing your personalized shopping experience...",
            "Finding the best deals just for you...",
            "Curating your personalized product recommendations...",
            "Almost there! Finalizing your shopping dashboard...",
            "Setting up secure payment options...",
        ];

        let messageIndex = 0;
        let cartCount = 0;
        const cartBadge = document.getElementById('cartBadge');
        const loadingText = document.getElementById('loadingText');
        const spinnerContainer = document.getElementById('spinnerContainer');

        // Change loading message every 2 seconds
        function changeLoadingMessage() {
            messageIndex = (messageIndex + 1) % loadingMessages.length;
            loadingText.textContent = loadingMessages[messageIndex];
        }

        // Simulate adding items to cart during loading
        function simulateCartAddition() {
            cartCount++;
            cartBadge.textContent = cartCount;
            cartBadge.classList.add('show');
            
            // Create a "pop" effect
            cartBadge.animate([
                { transform: 'scale(1.3)' },
                { transform: 'scale(1)' }
            ], {
                duration: 300,
                easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)'
            });
        }

        // Complete loading animation
        function completeLoading() {
            spinnerContainer.classList.add('done');
            loadingText.textContent = "Ready to shop!";
            
            // Show product categories
            document.querySelectorAll('.product-category').forEach((category, index) => {
                setTimeout(() => {
                    category.classList.add('visible');
                }, index * 200);
            });
        }

        // Initialize
        document.addEventListener('DOMContentLoaded', () => {
            createParticles();
            
            // Change loading message
            setInterval(changeLoadingMessage, 2000);
            
            // Simulate adding items to cart during loading
            setTimeout(simulateCartAddition, 2000);
            setTimeout(simulateCartAddition, 4000);
            setTimeout(simulateCartAddition, 6000);
            
            // Complete loading after 7 seconds
            setTimeout(completeLoading, 7000);
        });
    </script>
</body>
</html>

5) NeuroSync AR Spinner

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Futuristic AR Interface Spinner</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        :root {
            --spinner-primary: rgba(64, 224, 208, 0.7);
            --spinner-secondary: rgba(0, 191, 255, 0.5);
            --spinner-accent: rgba(147, 112, 219, 0.6);
            --spinner-highlight: rgba(255, 255, 255, 0.8);
            --bg-gradient-start: #0f1526;
            --bg-gradient-end: #1e293b;
        }

        body {
            width: 100%;
            height: 100vh;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: linear-gradient(135deg, var(--bg-gradient-start), var(--bg-gradient-end));
            font-family: 'Segoe UI', 'Roboto', sans-serif;
            overflow: hidden;
            perspective: 1000px;
            color: white;
        }

        .container {
            position: relative;
            width: 100%;
            max-width: 700px;
            height: 700px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 20px;
        }

        .title {
            position: absolute;
            top: 40px;
            font-size: 1.8rem;
            font-weight: 300;
            letter-spacing: 2px;
            text-transform: uppercase;
            color: white;
            text-shadow: 0 0 10px rgba(64, 224, 208, 0.8);
            z-index: 10;
        }

        .subtitle {
            position: absolute;
            top: 80px;
            font-size: 1rem;
            font-weight: 300;
            max-width: 500px;
            text-align: center;
            color: rgba(255, 255, 255, 0.7);
            z-index: 10;
        }

        .spinner-container {
            position: relative;
            width: 400px;
            height: 400px;
            display: flex;
            justify-content: center;
            align-items: center;
            transform-style: preserve-3d;
            cursor: pointer;
        }

        .spinner-ring {
            position: absolute;
            border-radius: 50%;
            border: 2px solid;
            transform-style: preserve-3d;
            will-change: transform;
            transition: all 0.3s ease;
            box-shadow: 0 0 20px rgba(64, 224, 208, 0.3);
            backdrop-filter: blur(5px);
        }

        .ring-1 {
            width: 350px;
            height: 350px;
            border-color: var(--spinner-primary);
            animation: spin1 15s linear infinite;
        }

        .ring-2 {
            width: 280px;
            height: 280px;
            border-color: var(--spinner-secondary);
            animation: spin2 12s linear infinite;
        }

        .ring-3 {
            width: 210px;
            height: 210px;
            border-color: var(--spinner-accent);
            animation: spin3 10s linear infinite;
        }

        .core {
            position: absolute;
            width: 140px;
            height: 140px;
            border-radius: 50%;
            background: radial-gradient(circle at 30% 30%, var(--spinner-highlight), var(--spinner-primary));
            box-shadow: 0 0 40px rgba(64, 224, 208, 0.6);
            display: flex;
            justify-content: center;
            align-items: center;
            color: white;
            font-size: 1.5rem;
            font-weight: 300;
            letter-spacing: 1px;
            animation: pulse 3s ease-in-out infinite;
            cursor: pointer;
        }

        @keyframes spin1 {
            0% { transform: rotateZ(0deg) rotateX(20deg) rotateY(0deg); }
            100% { transform: rotateZ(360deg) rotateX(20deg) rotateY(0deg); }
        }

        @keyframes spin2 {
            0% { transform: rotateZ(0deg) rotateX(0deg) rotateY(20deg); }
            100% { transform: rotateZ(-360deg) rotateX(0deg) rotateY(20deg); }
        }

        @keyframes spin3 {
            0% { transform: rotateZ(0deg) rotateX(-20deg) rotateY(-20deg); }
            100% { transform: rotateZ(360deg) rotateX(-20deg) rotateY(-20deg); }
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); opacity: 1; }
            50% { transform: scale(1.05); opacity: 0.9; }
        }

        .data-point {
            position: absolute;
            width: 12px;
            height: 12px;
            background-color: var(--spinner-highlight);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--spinner-highlight);
        }

        .holographic-element {
            position: absolute;
            background-color: rgba(255, 255, 255, 0.1);
            backdrop-filter: blur(2px);
            border-radius: 4px;
            padding: 8px;
            font-size: 0.8rem;
            transition: all 0.3s ease;
            transform: scale(0);
            opacity: 0;
            box-shadow: 0 0 10px rgba(64, 224, 208, 0.3);
            border: 1px solid rgba(64, 224, 208, 0.3);
            pointer-events: none;
            z-index: 5;
        }

        .controls {
            position: absolute;
            bottom: 40px;
            display: flex;
            gap: 20px;
            z-index: 10;
        }

        .control-btn {
            background: rgba(255, 255, 255, 0.1);
            border: 1px solid var(--spinner-primary);
            color: white;
            padding: 8px 16px;
            border-radius: 20px;
            cursor: pointer;
            transition: all 0.3s ease;
            font-size: 0.9rem;
            backdrop-filter: blur(5px);
        }

        .control-btn:hover {
            background: rgba(64, 224, 208, 0.3);
            transform: translateY(-2px);
            box-shadow: 0 5px 15px rgba(64, 224, 208, 0.3);
        }

        .velocity-indicator {
            position: absolute;
            width: 400px;
            height: 5px;
            background: rgba(255, 255, 255, 0.1);
            border-radius: 3px;
            bottom: 100px;
            overflow: hidden;
        }

        .velocity-fill {
            height: 100%;
            width: 50%;
            background: linear-gradient(90deg, var(--spinner-primary), var(--spinner-accent));
            border-radius: 3px;
            transition: width 0.5s ease;
        }

        /* Particle effects */
        .particles {
            position: absolute;
            width: 100%;
            height: 100%;
            pointer-events: none;
        }

        .particle {
            position: absolute;
            width: 4px;
            height: 4px;
            background-color: var(--spinner-highlight);
            border-radius: 50%;
            opacity: 0;
            pointer-events: none;
        }

        /* Responsive adjustments */
        @media (max-width: 700px) {
            .spinner-container {
                width: 300px;
                height: 300px;
            }

            .ring-1 {
                width: 260px;
                height: 260px;
            }

            .ring-2 {
                width: 200px;
                height: 200px;
            }

            .ring-3 {
                width: 140px;
                height: 140px;
            }

            .core {
                width: 80px;
                height: 80px;
                font-size: 1rem;
            }

            .title {
                font-size: 1.5rem;
            }

            .subtitle {
                font-size: 0.9rem;
                max-width: 300px;
            }

            .velocity-indicator {
                width: 300px;
            }

            .controls {
                flex-direction: column;
                gap: 10px;
                align-items: center;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 class="title">NeuroSync AR Interface</h1>
        <p class="subtitle">Holographic multi-layer interface with neural-driven gesture control. Explore spatial data visualization in augmented environments.</p>
        
        <div class="spinner-container" id="spinnerContainer">
            <div class="spinner-ring ring-1" id="ring1"></div>
            <div class="spinner-ring ring-2" id="ring2"></div>
            <div class="spinner-ring ring-3" id="ring3"></div>
            <div class="core" id="core">ACTIVATE</div>
        </div>

        <div class="velocity-indicator">
            <div class="velocity-fill" id="velocityFill"></div>
        </div>

        <div class="controls">
            <button class="control-btn" id="speedupBtn">Increase Velocity</button>
            <button class="control-btn" id="slowdownBtn">Decrease Velocity</button>
            <button class="control-btn" id="toggleDimensionBtn">Toggle Dimension</button>
        </div>

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

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // DOM Elements
            const spinnerContainer = document.getElementById('spinnerContainer');
            const ring1 = document.getElementById('ring1');
            const ring2 = document.getElementById('ring2');
            const ring3 = document.getElementById('ring3');
            const core = document.getElementById('core');
            const velocityFill = document.getElementById('velocityFill');
            const speedupBtn = document.getElementById('speedupBtn');
            const slowdownBtn = document.getElementById('slowdownBtn');
            const toggleDimensionBtn = document.getElementById('toggleDimensionBtn');
            const particlesContainer = document.getElementById('particles');
            
            // State
            let isActive = false;
            let velocity = 1;
            let dimension3D = true;
            let velocityPercent = 50;
            let spinnerData = [
                { name: "Neural Interface", value: "98.2% synced" },
                { name: "Spatial Mapping", value: "Active" },
                { name: "Gesture Recognition", value: "Enabled" },
                { name: "User Presence", value: "Detected" },
                { name: "Environment Scan", value: "Complete" },
                { name: "Haptic Feedback", value: "Calibrated" }
            ];
            
            // Create data points on rings
            function createDataPoints() {
                // Clear existing data points
                document.querySelectorAll('.data-point').forEach(point => point.remove());
                document.querySelectorAll('.holographic-element').forEach(el => el.remove());
                
                // Create new data points
                const rings = [ring1, ring2, ring3];
                
                rings.forEach((ring, ringIndex) => {
                    const numPoints = 6 - ringIndex;
                    const ringSize = parseInt(getComputedStyle(ring).width);
                    
                    for (let i = 0; i < numPoints; i++) {
                        // Create data point
                        const point = document.createElement('div');
                        point.classList.add('data-point');
                        
                        // Position around the ring
                        const angle = (i / numPoints) * Math.PI * 2;
                        const radius = ringSize / 2;
                        const x = Math.cos(angle) * radius;
                        const y = Math.sin(angle) * radius;
                        
                        point.style.left = `calc(50% + ${x}px)`;
                        point.style.top = `calc(50% + ${y}px)`;
                        
                        ring.appendChild(point);
                        
                        // Create holographic element
                        if (ringIndex === 0) {
                            const holoElement = document.createElement('div');
                            holoElement.classList.add('holographic-element');
                            
                            const dataIndex = i % spinnerData.length;
                            holoElement.innerHTML = `
                                <strong>${spinnerData[dataIndex].name}</strong><br>
                                ${spinnerData[dataIndex].value}
                            `;
                            
                            const offset = 40;
                            holoElement.style.left = `calc(50% + ${x * 1.2}px - ${offset}px)`;
                            holoElement.style.top = `calc(50% + ${y * 1.2}px - ${offset}px)`;
                            
                            spinnerContainer.appendChild(holoElement);
                            
                            // Associate data point with holographic element
                            point.addEventListener('mouseenter', () => {
                                holoElement.style.transform = 'scale(1)';
                                holoElement.style.opacity = '1';
                            });
                            
                            point.addEventListener('mouseleave', () => {
                                holoElement.style.transform = 'scale(0)';
                                holoElement.style.opacity = '0';
                            });
                        }
                    }
                });
            }
            
            // Create particles
            function createParticles(num) {
                for (let i = 0; i < num; i++) {
                    const particle = document.createElement('div');
                    particle.classList.add('particle');
                    particlesContainer.appendChild(particle);
                    
                    // Random position within the spinner container
                    const x = Math.random() * 400 - 200;
                    const y = Math.random() * 400 - 200;
                    
                    // Random animation
                    const duration = 1 + Math.random() * 2;
                    const delay = Math.random() * 2;
                    const size = 2 + Math.random() * 3;
                    
                    particle.style.left = `calc(50% + ${x}px)`;
                    particle.style.top = `calc(50% + ${y}px)`;
                    particle.style.width = `${size}px`;
                    particle.style.height = `${size}px`;
                    
                    // Animate the particle
                    particle.animate([
                        { transform: `translate(0, 0)`, opacity: 0 },
                        { transform: `translate(${Math.random() * 100 - 50}px, ${Math.random() * 100 - 50}px)`, opacity: 0.8 },
                        { transform: `translate(${Math.random() * 200 - 100}px, ${Math.random() * 200 - 100}px)`, opacity: 0 }
                    ], {
                        duration: duration * 1000,
                        delay: delay * 1000,
                        iterations: Infinity
                    });
                }
            }
            
            // Update spinner animation based on velocity
            function updateSpinnerSpeed() {
                const speeds = [
                    { ring1: 15 / velocity, ring2: 12 / velocity, ring3: 10 / velocity }
                ];
                
                document.documentElement.style.setProperty('--ring1-speed', `${speeds[0].ring1}s`);
                document.documentElement.style.setProperty('--ring2-speed', `${speeds[0].ring2}s`);
                document.documentElement.style.setProperty('--ring3-speed', `${speeds[0].ring3}s`);
                
                ring1.style.animationDuration = `${speeds[0].ring1}s`;
                ring2.style.animationDuration = `${speeds[0].ring2}s`;
                ring3.style.animationDuration = `${speeds[0].ring3}s`;
                
                velocityFill.style.width = `${velocityPercent}%`;
            }
            
            // Toggle 3D perspective
            function toggleDimension() {
                dimension3D = !dimension3D;
                
                if (dimension3D) {
                    ring1.style.animation = "spin1 15s linear infinite";
                    ring2.style.animation = "spin2 12s linear infinite";
                    ring3.style.animation = "spin3 10s linear infinite";
                    toggleDimensionBtn.textContent = "Toggle 2D";
                } else {
                    ring1.style.animation = "spin1 15s linear infinite";
                    ring2.style.animation = "spin1 12s linear infinite reverse";
                    ring3.style.animation = "spin1 10s linear infinite";
                    toggleDimensionBtn.textContent = "Toggle 3D";
                }
                
                updateSpinnerSpeed();
            }
            
            // Activate the spinner
            function activateSpinner() {
                isActive = !isActive;
                
                if (isActive) {
                    core.textContent = "ACTIVE";
                    core.style.boxShadow = "0 0 50px rgba(64, 224, 208, 0.8)";
                    spinnerContainer.style.transform = "translateZ(50px)";
                    
                    // Show holographic elements
                    document.querySelectorAll('.holographic-element').forEach(el => {
                        setTimeout(() => {
                            el.style.transform = 'scale(1)';
                            el.style.opacity = '1';
                            
                            setTimeout(() => {
                                el.style.transform = 'scale(0)';
                                el.style.opacity = '0';
                            }, 2000);
                        }, Math.random() * 1000);
                    });
                    
                    // Create more particles
                    createParticles(20);
                } else {
                    core.textContent = "ACTIVATE";
                    core.style.boxShadow = "0 0 40px rgba(64, 224, 208, 0.6)";
                    spinnerContainer.style.transform = "translateZ(0)";
                    
                    // Clear particles
                    particlesContainer.innerHTML = '';
                    createParticles(5);
                }
            }
            
            // Increase velocity
            function increaseVelocity() {
                if (velocityPercent < 100) {
                    velocityPercent += 10;
                    velocity = 0.5 + (velocityPercent / 50);
                    updateSpinnerSpeed();
                }
            }
            
            // Decrease velocity
            function decreaseVelocity() {
                if (velocityPercent > 10) {
                    velocityPercent -= 10;
                    velocity = 0.5 + (velocityPercent / 50);
                    updateSpinnerSpeed();
                }
            }
            
            // Interactive spinner rotation
            let isDragging = false;
            let lastMouseX = 0;
            let lastMouseY = 0;
            let rotationX = 20;
            let rotationY = 0;
            
            spinnerContainer.addEventListener('mousedown', (e) => {
                isDragging = true;
                lastMouseX = e.clientX;
                lastMouseY = e.clientY;
            });
            
            document.addEventListener('mousemove', (e) => {
                if (!isDragging) return;
                
                const deltaX = e.clientX - lastMouseX;
                const deltaY = e.clientY - lastMouseY;
                
                rotationX -= deltaY * 0.5;
                rotationY += deltaX * 0.5;
                
                rotationX = Math.max(-45, Math.min(45, rotationX));
                
                spinnerContainer.style.transform = `rotateX(${rotationX}deg) rotateY(${rotationY}deg)`;
                
                lastMouseX = e.clientX;
                lastMouseY = e.clientY;
            });
            
            document.addEventListener('mouseup', () => {
                isDragging = false;
            });
            
            // Touch events for mobile
            spinnerContainer.addEventListener('touchstart', (e) => {
                isDragging = true;
                lastMouseX = e.touches[0].clientX;
                lastMouseY = e.touches[0].clientY;
            });
            
            document.addEventListener('touchmove', (e) => {
                if (!isDragging) return;
                
                const deltaX = e.touches[0].clientX - lastMouseX;
                const deltaY = e.touches[0].clientY - lastMouseY;
                
                rotationX -= deltaY * 0.5;
                rotationY += deltaX * 0.5;
                
                rotationX = Math.max(-45, Math.min(45, rotationX));
                
                spinnerContainer.style.transform = `rotateX(${rotationX}deg) rotateY(${rotationY}deg)`;
                
                lastMouseX = e.touches[0].clientX;
                lastMouseY = e.touches[0].clientY;
            });
            
            document.addEventListener('touchend', () => {
                isDragging = false;
            });
            
            // Event listeners
            core.addEventListener('click', activateSpinner);
            speedupBtn.addEventListener('click', increaseVelocity);
            slowdownBtn.addEventListener('click', decreaseVelocity);
            toggleDimensionBtn.addEventListener('click', toggleDimension);
            
            // Initialize
            createDataPoints();
            createParticles(5);
            updateSpinnerSpeed();
            
            // Resize handler
            window.addEventListener('resize', createDataPoints);
            
            // Mouse movement effect for spinner
            document.addEventListener('mousemove', (e) => {
                if (isDragging) return;
                
                const rect = spinnerContainer.getBoundingClientRect();
                const centerX = rect.left + rect.width / 2;
                const centerY = rect.top + rect.height / 2;
                
                const offsetX = (e.clientX - centerX) / 30;
                const offsetY = (e.clientY - centerY) / 30;
                
                if (!isDragging) {
                    spinnerContainer.style.transform = `rotateX(${-offsetY}deg) rotateY(${offsetX}deg)`;
                }
            });
        });
    </script>
</body>
</html>

Use Subframe to Design Spinner (& Any UI!)

Designing your own spinner has never been easier with Subframe. Its drag-and-drop interface and intuitive, responsive canvas ensure pixel-perfect UI every time. Loved by designers and developers alike, Subframe makes the design process seamless and efficient.

Start for free and elevate your web design today!

6) Data Dashboard Ring Spinner

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Data Dashboard Ring Spinner</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 700px;
            width: 100%;
            max-width: 700px;
            background-color: #f8f9fa;
            margin: 0 auto;
            overflow: hidden;
            padding: 20px;
        }

        .dashboard-container {
            position: relative;
            width: 100%;
            max-width: 600px;
            height: 600px;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            background-color: #ffffff;
            border-radius: 20px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
            padding: 30px;
            overflow: hidden;
        }

        .spinner-container {
            position: relative;
            width: 280px;
            height: 280px;
            margin-bottom: 30px;
        }

        .control-panel {
            display: flex;
            gap: 15px;
            margin-bottom: 40px;
        }

        .control-btn {
            background: #f0f4f8;
            border: none;
            padding: 12px 20px;
            border-radius: 10px;
            color: #465866;
            font-weight: 600;
            font-size: 14px;
            cursor: pointer;
            transition: all 0.3s ease;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
        }

        .control-btn:hover {
            background: #e0e7ee;
            transform: translateY(-2px);
        }

        .control-btn.active {
            background: #3a86ff;
            color: white;
        }

        .data-insight {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            z-index: 10;
            width: 150px;
        }

        .data-value {
            font-size: 32px;
            font-weight: 700;
            color: #1d3557;
            margin-bottom: 5px;
        }

        .data-label {
            font-size: 14px;
            color: #6c757d;
            font-weight: 500;
        }

        .data-metrics {
            width: 100%;
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 20px;
            margin-top: 30px;
        }

        .metric-card {
            background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
            border-radius: 12px;
            padding: 15px;
            box-shadow: 0 4px 6px rgba(0, 0, 0, 0.02);
            transition: all 0.3s ease;
        }

        .metric-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 15px rgba(0, 0, 0, 0.05);
        }

        .metric-value {
            font-size: 20px;
            font-weight: 700;
            color: #1d3557;
            margin-bottom: 5px;
        }

        .metric-label {
            font-size: 13px;
            color: #6c757d;
            font-weight: 500;
        }

        .ring {
            position: absolute;
            border-radius: 50%;
            border: 4px solid transparent;
            opacity: 0.85;
            transition: all 0.5s ease;
        }

        .header {
            width: 100%;
            text-align: center;
            margin-bottom: 20px;
        }

        .title {
            font-size: 24px;
            font-weight: 700;
            color: #1d3557;
            margin-bottom: 8px;
        }

        .subtitle {
            font-size: 14px;
            color: #6c757d;
        }

        .tooltip {
            position: absolute;
            background: rgba(255, 255, 255, 0.95);
            border-radius: 8px;
            padding: 10px 15px;
            font-size: 12px;
            color: #333;
            box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s ease;
            z-index: 100;
            white-space: nowrap;
        }

        @media (max-width: 600px) {
            .dashboard-container {
                padding: 20px;
                height: auto;
            }

            .spinner-container {
                width: 220px;
                height: 220px;
            }

            .data-value {
                font-size: 28px;
            }

            .data-label {
                font-size: 12px;
            }

            .data-metrics {
                grid-template-columns: repeat(2, 1fr);
            }

            .control-panel {
                flex-wrap: wrap;
                justify-content: center;
            }
        }

        @media (max-width: 400px) {
            .spinner-container {
                width: 180px;
                height: 180px;
            }

            .data-metrics {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="dashboard-container">
        <div class="header">
            <h1 class="title">Data Processing Pipeline</h1>
            <p class="subtitle">Real-time visualization of system performance metrics</p>
        </div>

        <div class="control-panel">
            <button class="control-btn active" data-speed="1">Real-time</button>
            <button class="control-btn" data-speed="0.5">0.5x Speed</button>
            <button class="control-btn" data-speed="2">2x Speed</button>
            <button class="control-btn" id="pause-btn">Pause</button>
        </div>

        <div class="spinner-container">
            <div class="data-insight">
                <div class="data-value" id="central-value">86%</div>
                <div class="data-label">Processing Efficiency</div>
            </div>
            <!-- Rings will be added here by JS -->
        </div>

        <div class="data-metrics">
            <div class="metric-card" data-tooltip="Average time to process data packets">
                <div class="metric-value">142ms</div>
                <div class="metric-label">Response Time</div>
            </div>
            <div class="metric-card" data-tooltip="Active data streams being processed">
                <div class="metric-value">24</div>
                <div class="metric-label">Active Streams</div>
            </div>
            <div class="metric-card" data-tooltip="Data accuracy after processing">
                <div class="metric-value">99.8%</div>
                <div class="metric-label">Accuracy Rate</div>
            </div>
        </div>

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

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            // Configuration
            const ringCount = 6;
            const maxRadius = 130;
            const minRadius = 50;
            const spinnerContainer = document.querySelector('.spinner-container');
            const tooltip = document.getElementById('tooltip');
            
            let animationSpeed = 1;
            let isPaused = false;
            let rings = [];
            let startAngles = Array(ringCount).fill(0);
            let endAngles = Array(ringCount).fill(0);
            let targetEndAngles = Array(ringCount).fill(0);
            let spinSpeed = Array(ringCount).fill(0);
            
            // Create gradient colors for rings
            const colorPalettes = [
                { start: '#3a86ff', end: '#0066cc' }, // Blue
                { start: '#8338ec', end: '#5e23aa' }, // Purple
                { start: '#ff006e', end: '#c8004f' }, // Pink
                { start: '#fb5607', end: '#c84400' }, // Orange
                { start: '#ffbe0b', end: '#cc9700' }, // Yellow
                { start: '#06d6a0', end: '#039973' }  // Teal
            ];

            // Create rings
            for (let i = 0; i < ringCount; i++) {
                const radius = maxRadius - (i * ((maxRadius - minRadius) / ringCount));
                const size = radius * 2;
                const thickness = 8 + (ringCount - i) * 0.5;
                
                const ring = document.createElement('div');
                ring.className = 'ring';
                ring.style.width = `${size}px`;
                ring.style.height = `${size}px`;
                ring.style.top = `${(280 - size) / 2}px`;
                ring.style.left = `${(280 - size) / 2}px`;
                
                // Apply gradient
                const { start, end } = colorPalettes[i % colorPalettes.length];
                ring.style.borderWidth = `${thickness}px`;
                
                spinnerContainer.appendChild(ring);
                rings.push(ring);
                
                // Initialize ring animation properties
                startAngles[i] = (i * 30) % 360; // Stagger start angles
                endAngles[i] = startAngles[i];
                spinSpeed[i] = 0.8 + Math.random() * 0.4; // Slightly different speeds
                
                // Set initial arc
                updateRingArc(i);
            }

            function updateRingArc(index) {
                const ring = rings[index];
                const startAngle = startAngles[index];
                const endAngle = endAngles[index];
                const arcLength = ((endAngle - startAngle + 360) % 360);
                
                // Color palette for this ring
                const { start, end } = colorPalettes[index % colorPalettes.length];
                
                // Set the gradient and dash pattern
                const circumference = Math.PI * 2 * (parseFloat(ring.style.width) / 2);
                const dashLength = (arcLength / 360) * circumference;
                const dashGap = circumference - dashLength;
                
                ring.style.borderColor = 'transparent';
                ring.style.borderTopColor = start;
                ring.style.borderRightColor = end;
                ring.style.borderLeftColor = end;
                ring.style.transform = `rotate(${startAngle}deg)`;
                ring.style.borderRadius = '50%';
            }

            // Animation loop
            function animate() {
                if (!isPaused) {
                    for (let i = 0; i < ringCount; i++) {
                        // Generate new target end angles randomly
                        if (Math.random() < 0.01 * animationSpeed) {
                            targetEndAngles[i] = (startAngles[i] + 30 + Math.random() * 300) % 360;
                        }
                        
                        // Smoothly animate toward target end angles
                        const diff = ((targetEndAngles[i] - endAngles[i] + 360) % 360);
                        if (diff > 1) {
                            endAngles[i] = (endAngles[i] + Math.min(diff * 0.05, 2) * animationSpeed * spinSpeed[i]) % 360;
                            updateRingArc(i);
                        }
                        
                        // Rotate start angle (giving spinning effect)
                        startAngles[i] = (startAngles[i] + 0.25 * animationSpeed * spinSpeed[i]) % 360;
                        updateRingArc(i);
                    }
                    
                    // Randomly update central value
                    if (Math.random() < 0.01 * animationSpeed) {
                        const centralValue = document.getElementById('central-value');
                        const newValue = 75 + Math.floor(Math.random() * 20);
                        centralValue.textContent = `${newValue}%`;
                        
                        // Update color based on value
                        let color = '#1d3557'; // Default blue
                        if (newValue >= 90) color = '#06d6a0'; // Green for high
                        else if (newValue < 80) color = '#ff006e'; // Red for low
                        centralValue.style.color = color;
                    }
                }
                
                requestAnimationFrame(animate);
            }

            // Start animation
            animate();

            // Set up controls
            document.querySelectorAll('.control-btn[data-speed]').forEach(button => {
                button.addEventListener('click', function() {
                    document.querySelectorAll('.control-btn').forEach(btn => btn.classList.remove('active'));
                    this.classList.add('active');
                    animationSpeed = parseFloat(this.getAttribute('data-speed'));
                    isPaused = false;
                    document.getElementById('pause-btn').textContent = 'Pause';
                });
            });

            document.getElementById('pause-btn').addEventListener('click', function() {
                isPaused = !isPaused;
                this.textContent = isPaused ? 'Resume' : 'Pause';
            });

            // Tooltip for metric cards
            document.querySelectorAll('.metric-card').forEach(card => {
                card.addEventListener('mouseenter', function(e) {
                    const tooltipText = this.getAttribute('data-tooltip');
                    tooltip.textContent = tooltipText;
                    tooltip.style.opacity = '1';
                    
                    const rect = this.getBoundingClientRect();
                    const containerRect = document.querySelector('.dashboard-container').getBoundingClientRect();
                    
                    tooltip.style.left = `${rect.left - containerRect.left + rect.width/2 - tooltip.offsetWidth/2}px`;
                    tooltip.style.top = `${rect.top - containerRect.top - tooltip.offsetHeight - 10}px`;
                });
                
                card.addEventListener('mouseleave', function() {
                    tooltip.style.opacity = '0';
                });
            });

            // Simulate dynamic data updates for the metrics
            setInterval(() => {
                if (isPaused) return;
                
                document.querySelectorAll('.metric-card').forEach((card, index) => {
                    const valueEl = card.querySelector('.metric-value');
                    const currentText = valueEl.textContent;
                    
                    // Different update logic based on the metric type
                    if (index === 0) { // Response time
                        let value = parseInt(currentText);
                        value += Math.floor(Math.random() * 11) - 5; // -5 to +5
                        if (value < 120) value = 120;
                        if (value > 180) value = 180;
                        valueEl.textContent = `${value}ms`;
                    } else if (index === 1) { // Active streams
                        let value = parseInt(currentText);
                        if (Math.random() < 0.3) {
                            value += Math.random() < 0.5 ? 1 : -1;
                        }
                        if (value < 18) value = 18;
                        if (value > 32) value = 32;
                        valueEl.textContent = value;
                    } else if (index === 2) { // Accuracy
                        let value = parseFloat(currentText);
                        value = Math.round((value + (Math.random() * 0.2 - 0.1)) * 10) / 10;
                        if (value < 99.5) value = 99.5;
                        if (value > 100) value = 100;
                        valueEl.textContent = `${value.toFixed(1)}%`;
                    }
                });
            }, 3000);
        });
    </script>
</body>
</html>

7) Artisan Brush Spinner

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Creative Portfolio Loader</title>
    <style>
        :root {
            --pink: #ffb6c1;
            --blue: #87ceeb;
            --lavender: #e6e6fa;
            --mint: #98fb98;
            --peach: #ffdab9;
        }
        
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: 'Helvetica Neue', Arial, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            background-color: #f8f9fa;
            overflow: hidden;
        }
        
        .loader-container {
            position: relative;
            width: 100%;
            max-width: 700px;
            height: 100vh;
            max-height: 700px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 2rem;
        }
        
        .loader {
            position: relative;
            width: 200px;
            height: 200px;
            margin-bottom: 3rem;
        }
        
        .loader-element {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.1));
        }
        
        .brush-stroke {
            width: 40px;
            height: 120px;
            border-radius: 50%;
            transform-origin: center center;
            opacity: 0.9;
        }
        
        .brush-1 {
            background-color: var(--pink);
            animation: rotate-brush 3s ease-in-out infinite;
        }
        
        .brush-2 {
            background-color: var(--blue);
            animation: rotate-brush 3s ease-in-out infinite 0.5s;
            width: 50px;
            height: 100px;
        }
        
        .brush-3 {
            background-color: var(--lavender);
            animation: rotate-brush 3s ease-in-out infinite 1s;
            width: 35px;
            height: 90px;
        }
        
        .brush-4 {
            background-color: var(--mint);
            animation: rotate-brush 3s ease-in-out infinite 1.5s;
            width: 45px;
            height: 110px;
        }
        
        .brush-5 {
            background-color: var(--peach);
            animation: rotate-brush 3s ease-in-out infinite 2s;
            width: 30px;
            height: 80px;
        }
        
        .abstract-shape {
            width: 80px;
            height: 80px;
            border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
            background-color: #ffffff;
            opacity: 0.7;
            transform-origin: center center;
            animation: morph 8s linear infinite;
        }
        
        .loading-text {
            font-size: 1.25rem;
            color: #333;
            letter-spacing: 1px;
            margin-bottom: 1rem;
            font-weight: 500;
            opacity: 0;
            animation: fade-in 1.5s ease-in-out forwards;
        }
        
        .portfolio-title {
            font-size: 2.5rem;
            font-weight: 700;
            margin-bottom: 1rem;
            text-align: center;
            color: #333;
            opacity: 0;
            animation: fade-in 1.5s ease-in-out 0.5s forwards;
        }
        
        .portfolio-subtitle {
            font-size: 1.2rem;
            text-align: center;
            color: #666;
            max-width: 450px;
            line-height: 1.6;
            margin-bottom: 2rem;
            opacity: 0;
            animation: fade-in 1.5s ease-in-out 1s forwards;
        }
        
        .progress-container {
            width: 250px;
            height: 4px;
            background-color: rgba(0, 0, 0, 0.1);
            border-radius: 4px;
            overflow: hidden;
            opacity: 0;
            animation: fade-in 1.5s ease-in-out 1.5s forwards;
        }
        
        .progress-bar {
            height: 100%;
            width: 0;
            background-color: #333;
            border-radius: 4px;
            transition: width 0.3s ease;
        }
        
        .percentage {
            font-size: 0.9rem;
            color: #666;
            margin-top: 0.5rem;
            font-weight: 500;
            opacity: 0;
            animation: fade-in 1.5s ease-in-out 1.5s forwards;
        }
        
        @keyframes rotate-brush {
            0% {
                transform: translate(-50%, -50%) rotate(0deg) translateX(40px) rotate(0deg);
            }
            50% {
                transform: translate(-50%, -50%) rotate(180deg) translateX(40px) rotate(-180deg) scale(0.8);
            }
            100% {
                transform: translate(-50%, -50%) rotate(360deg) translateX(40px) rotate(-360deg);
            }
        }
        
        @keyframes morph {
            0% {
                border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
            }
            25% {
                border-radius: 70% 30% 30% 70% / 70% 70% 30% 30%;
            }
            50% {
                border-radius: 30% 30% 70% 70% / 60% 40% 60% 40%;
            }
            75% {
                border-radius: 50% 50% 20% 80% / 25% 80% 20% 75%;
            }
            100% {
                border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
            }
        }
        
        @keyframes fade-in {
            from {
                opacity: 0;
                transform: translateY(20px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        /* Interaction styles */
        .loader-container:hover .brush-stroke {
            animation-duration: 2s;
        }
        
        .loader-container:hover .abstract-shape {
            animation-duration: 5s;
        }
        
        /* Responsive styles */
        @media (max-width: 600px) {
            .loader {
                width: 150px;
                height: 150px;
                margin-bottom: 2rem;
            }
            
            .portfolio-title {
                font-size: 2rem;
            }
            
            .portfolio-subtitle {
                font-size: 1rem;
                padding: 0 1rem;
            }
            
            .brush-stroke {
                transform-origin: center center;
                transform: scale(0.8) translate(-60%, -60%);
            }
        }
    </style>
</head>
<body>
    <div class="loader-container">
        <div class="loader">
            <div class="loader-element abstract-shape"></div>
            <div class="loader-element brush-stroke brush-1"></div>
            <div class="loader-element brush-stroke brush-2"></div>
            <div class="loader-element brush-stroke brush-3"></div>
            <div class="loader-element brush-stroke brush-4"></div>
            <div class="loader-element brush-stroke brush-5"></div>
        </div>
        
        <div class="loading-text">CURATING CREATIVITY</div>
        <h1 class="portfolio-title">Studio Artisanal</h1>
        <p class="portfolio-subtitle">Crafting digital experiences with the thoughtfulness of an artisan and the vision of an artist. Prepare to enter a showcase of creative craftsmanship.</p>
        
        <div class="progress-container">
            <div class="progress-bar" id="progressBar"></div>
        </div>
        <div class="percentage" id="percentage">0%</div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const progressBar = document.getElementById('progressBar');
            const percentage = document.getElementById('percentage');
            let progress = 0;
            
            // Simulate loading progress
            const interval = setInterval(() => {
                progress += Math.floor(Math.random() * 5) + 1;
                
                if (progress >= 100) {
                    progress = 100;
                    clearInterval(interval);
                    
                    // You would typically redirect or show content here
                    // For this example, we'll just keep showing the loader
                    setTimeout(() => {
                        // Create a finish animation effect
                        document.querySelectorAll('.brush-stroke').forEach(brush => {
                            brush.style.animationPlayState = 'paused';
                            brush.style.transition = 'all 0.8s ease-out';
                            brush.style.opacity = '0';
                            brush.style.transform = 'translate(-50%, -50%) scale(1.5)';
                        });
                        
                        document.querySelector('.abstract-shape').style.animation = 'morph 2s ease-out forwards';
                    }, 1000);
                }
                
                progressBar.style.width = `${progress}%`;
                percentage.textContent = `${progress}%`;
            }, 200);
            
            // Interactive elements
            const loaderContainer = document.querySelector('.loader-container');
            
            loaderContainer.addEventListener('mousemove', (e) => {
                const { left, top, width, height } = loaderContainer.getBoundingClientRect();
                const x = (e.clientX - left) / width - 0.5;
                const y = (e.clientY - top) / height - 0.5;
                
                const brushes = document.querySelectorAll('.brush-stroke');
                brushes.forEach((brush, index) => {
                    const factor = (index + 1) * 4;
                    brush.style.transform = `translate(calc(-50% + ${x * factor}px), calc(-50% + ${y * factor}px)) 
                                           rotate(${x * y * 360}deg) 
                                           translateX(${40 + x * 10}px) 
                                           rotate(${-x * y * 360}deg)`;
                });
                
                const shape = document.querySelector('.abstract-shape');
                shape.style.borderRadius = `${50 + x * 20}% ${50 - x * 20}% ${50 + y * 20}% ${50 - y * 20}% / 
                                          ${50 - y * 20}% ${50 + y * 20}% ${50 - x * 20}% ${50 + x * 20}%`;
            });
            
            loaderContainer.addEventListener('mouseleave', () => {
                const brushes = document.querySelectorAll('.brush-stroke');
                brushes.forEach(brush => {
                    brush.style.transform = '';
                });
                
                const shape = document.querySelector('.abstract-shape');
                shape.style.borderRadius = '';
            });
        });
    </script>
</body>
</html>

8) Medical Records Loader

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Healthcare App Spinner</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            background-color: #f5f9fb;
            width: 100%;
            height: 100vh;
            display: flex;
            justify-content: center;
            align-items: center;
            overflow: hidden;
        }

        .container {
            width: 100%;
            max-width: 700px;
            height: 700px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 2rem;
            position: relative;
            overflow: hidden;
        }

        .background-pulse {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: radial-gradient(circle, rgba(169, 227, 236, 0.2) 0%, rgba(255, 255, 255, 0) 70%);
            animation: pulse 4s infinite alternate;
            z-index: -1;
        }

        @keyframes pulse {
            0% {
                transform: scale(1);
                opacity: 0.5;
            }
            100% {
                transform: scale(1.1);
                opacity: 0.8;
            }
        }

        .spinner-container {
            position: relative;
            width: 200px;
            height: 200px;
            margin-bottom: 2rem;
        }

        .spinner {
            width: 100%;
            height: 100%;
            border-radius: 50%;
            position: relative;
            display: flex;
            justify-content: center;
            align-items: center;
        }

        .spinner-ring {
            position: absolute;
            border-radius: 50%;
            border: 4px solid transparent;
        }

        .spinner-ring-1 {
            width: 100%;
            height: 100%;
            border-top-color: #4ECDC4;
            animation: spin 2s linear infinite;
        }

        .spinner-ring-2 {
            width: 85%;
            height: 85%;
            border-right-color: #1A535C;
            animation: spin 1.5s linear infinite reverse;
        }

        .spinner-ring-3 {
            width: 70%;
            height: 70%;
            border-bottom-color: #5DA9E9;
            animation: spin 3s linear infinite;
        }

        .spinner-center {
            position: absolute;
            width: 50%;
            height: 50%;
            background: linear-gradient(135deg, #4ECDC4, #5DA9E9);
            border-radius: 50%;
            display: flex;
            justify-content: center;
            align-items: center;
            box-shadow: 0 0 20px rgba(93, 169, 233, 0.3);
            animation: pulse-center 2s infinite alternate;
        }

        .spinner-icon {
            color: white;
            font-size: 24px;
        }

        @keyframes pulse-center {
            0% {
                transform: scale(1);
                box-shadow: 0 0 15px rgba(93, 169, 233, 0.3);
            }
            100% {
                transform: scale(1.05);
                box-shadow: 0 0 25px rgba(93, 169, 233, 0.5);
            }
        }

        @keyframes spin {
            from {
                transform: rotate(0deg);
            }
            to {
                transform: rotate(360deg);
            }
        }

        .message-container {
            text-align: center;
            max-width: 400px;
            padding: 1.5rem;
            background-color: rgba(255, 255, 255, 0.9);
            border-radius: 12px;
            box-shadow: 0 4px 20px rgba(26, 83, 92, 0.1);
            transform: translateY(0);
            transition: all 0.5s ease;
        }

        .message-container:hover {
            transform: translateY(-5px);
            box-shadow: 0 8px 25px rgba(26, 83, 92, 0.15);
        }

        .status {
            font-size: 1.2rem;
            font-weight: 600;
            color: #1A535C;
            margin-bottom: 0.5rem;
        }

        .description {
            color: #5D6D7E;
            line-height: 1.6;
            margin-bottom: 1rem;
        }

        .time-estimation {
            background: linear-gradient(135deg, rgba(78, 205, 196, 0.1), rgba(93, 169, 233, 0.1));
            padding: 0.8rem;
            border-radius: 8px;
            margin-bottom: 1rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .time-label {
            font-size: 0.9rem;
            color: #5D6D7E;
        }

        .time-value {
            font-weight: 600;
            color: #1A535C;
        }

        .wellness-tip {
            font-size: 0.9rem;
            color: #4ECDC4;
            font-style: italic;
            margin-top: 1rem;
            padding: 0.5rem;
            border-top: 1px solid rgba(78, 205, 196, 0.2);
        }

        .breathing-guide {
            display: flex;
            align-items: center;
            justify-content: center;
            margin-top: 1.5rem;
        }

        .breathing-circle {
            width: 15px;
            height: 15px;
            background-color: #5DA9E9;
            border-radius: 50%;
            margin: 0 5px;
            animation: breathe 4s infinite alternate ease-in-out;
            opacity: 0.7;
        }

        .breathing-circle:nth-child(2) {
            animation-delay: 0.5s;
        }

        .breathing-circle:nth-child(3) {
            animation-delay: 1s;
        }

        .breathing-circle:nth-child(4) {
            animation-delay: 1.5s;
        }

        .breathing-text {
            font-size: 0.85rem;
            color: #5D6D7E;
            margin-left: 10px;
        }

        @keyframes breathe {
            0% {
                transform: scale(0.8);
                opacity: 0.5;
            }
            100% {
                transform: scale(1.2);
                opacity: 1;
            }
        }

        .progress-bar {
            width: 100%;
            height: 6px;
            background-color: rgba(93, 169, 233, 0.1);
            border-radius: 3px;
            margin-top: 1rem;
            overflow: hidden;
            position: relative;
        }

        .progress-fill {
            position: absolute;
            height: 100%;
            width: 0%;
            background: linear-gradient(to right, #4ECDC4, #5DA9E9);
            border-radius: 3px;
            transition: width 0.5s ease;
        }

        @media (max-width: 500px) {
            .spinner-container {
                width: 150px;
                height: 150px;
            }

            .message-container {
                padding: 1rem;
                max-width: 300px;
            }

            .status {
                font-size: 1rem;
            }

            .description {
                font-size: 0.9rem;
            }
        }

        .wave {
            position: absolute;
            bottom: 0;
            left: 0;
            width: 100%;
            height: 100px;
            background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1440 320"><path fill="%234ecdc4" fill-opacity="0.1" d="M0,96L48,112C96,128,192,160,288,165.3C384,171,480,149,576,138.7C672,128,768,128,864,144C960,160,1056,192,1152,197.3C1248,203,1344,181,1392,170.7L1440,160L1440,320L1392,320C1344,320,1248,320,1152,320C1056,320,960,320,864,320C768,320,672,320,576,320C480,320,384,320,288,320C192,320,96,320,48,320L0,320Z"></path></svg>');
            background-size: cover;
            background-repeat: no-repeat;
            opacity: 0.7;
            z-index: -1;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="background-pulse"></div>
        <div class="wave"></div>
        
        <div class="spinner-container">
            <div class="spinner">
                <div class="spinner-ring spinner-ring-1"></div>
                <div class="spinner-ring spinner-ring-2"></div>
                <div class="spinner-ring spinner-ring-3"></div>
                <div class="spinner-center">
                    <div class="spinner-icon">+</div>
                </div>
            </div>
        </div>
        
        <div class="message-container">
            <div class="status" id="status">Retrieving your medical records</div>
            <p class="description">Our system is securely accessing your information while maintaining HIPAA compliance standards.</p>
            
            <div class="time-estimation">
                <span class="time-label">Estimated wait time:</span>
                <span class="time-value" id="timeEstimate">~2 minutes</span>
            </div>
            
            <div class="progress-bar">
                <div class="progress-fill" id="progressFill"></div>
            </div>
            
            <div class="wellness-tip" id="wellnessTip">
                Lowering your shoulders and taking deep breaths can help reduce blood pressure while you wait.
            </div>
            
            <div class="breathing-guide">
                <div class="breathing-circle"></div>
                <div class="breathing-circle"></div>
                <div class="breathing-circle"></div>
                <div class="breathing-circle"></div>
                <span class="breathing-text">Try breathing with the rhythm</span>
            </div>
        </div>
    </div>

    <script>
        const statusMessages = [
            "Retrieving your medical records",
            "Processing lab results",
            "Updating medication history",
            "Preparing your appointment details",
            "Setting up secure connection to your doctor"
        ];

        const wellnessTips = [
            "Lowering your shoulders and taking deep breaths can help reduce blood pressure while you wait.",
            "Staying hydrated can improve both mood and cognitive function throughout your day.",
            "A brief 5-minute walk every hour can help improve circulation and reduce stiffness.",
            "Focusing on a simple gratitude practice can boost your mental wellness during wait times.",
            "Regular sleep patterns support better immune function and overall health outcomes."
        ];

        const timeEstimates = [
            "~2 minutes",
            "~90 seconds",
            "~60 seconds",
            "~30 seconds",
            "Almost complete"
        ];

        let currentStep = 0;
        const totalSteps = statusMessages.length;
        const statusElement = document.getElementById('status');
        const timeEstimateElement = document.getElementById('timeEstimate');
        const wellnessTipElement = document.getElementById('wellnessTip');
        const progressFill = document.getElementById('progressFill');

        function updateLoader() {
            if (currentStep < totalSteps) {
                // Update the status message
                statusElement.innerHTML = statusMessages[currentStep];
                
                // Animate the status with a subtle fade
                statusElement.style.opacity = 0;
                setTimeout(() => {
                    statusElement.style.opacity = 1;
                }, 300);
                
                // Update the time estimate
                timeEstimateElement.textContent = timeEstimates[currentStep];
                
                // Update the wellness tip with a gentle transition
                wellnessTipElement.style.opacity = 0;
                setTimeout(() => {
                    wellnessTipElement.textContent = wellnessTips[currentStep];
                    wellnessTipElement.style.opacity = 1;
                }, 300);
                
                // Update progress bar
                const progressPercentage = ((currentStep + 1) / totalSteps) * 100;
                progressFill.style.width = `${progressPercentage}%`;
                
                currentStep++;
                
                // Schedule the next update
                setTimeout(updateLoader, 3000); // Change message every 3 seconds
            }
        }

        // Restart the animation when it completes
        function restartAnimation() {
            if (currentStep >= totalSteps) {
                currentStep = 0;
                progressFill.style.width = '0%';
                setTimeout(updateLoader, 1000);
            } else {
                setTimeout(restartAnimation, 1000);
            }
        }

        // Start the loader animation
        updateLoader();
        setTimeout(restartAnimation, 15000); // Check to restart after the sequence should have completed
        
        // Add hover effect to spinner
        const spinnerContainer = document.querySelector('.spinner-container');
        spinnerContainer.addEventListener('mouseenter', () => {
            const spinnerRings = document.querySelectorAll('.spinner-ring');
            spinnerRings.forEach(ring => {
                ring.style.borderWidth = '5px';
            });
        });
        
        spinnerContainer.addEventListener('mouseleave', () => {
            const spinnerRings = document.querySelectorAll('.spinner-ring');
            spinnerRings.forEach(ring => {
                ring.style.borderWidth = '4px';
            });
        });
    </script>
</body>
</html>

9) Wheel of Knowledge

Here's the code:

<html>
<head>
  <style>
    :root {
      --primary: #FF6B6B;
      --secondary: #4ECDC4;
      --accent1: #FFE66D;
      --accent2: #7A77FF;
      --dark: #292F36;
      --light: #F7FFF7;
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      font-family: 'Arial Rounded MT Bold', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    }

    body {
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      background-color: var(--light);
      overflow: hidden;
    }

    .container {
      width: 100%;
      max-width: 700px;
      height: 700px;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      position: relative;
      padding: 20px;
    }

    .title {
      text-align: center;
      margin-bottom: 30px;
      color: var(--dark);
      z-index: 10;
    }

    h1 {
      font-size: 2.5rem;
      margin-bottom: 10px;
    }

    .subtitle {
      font-size: 1.2rem;
      opacity: 0.8;
      max-width: 80%;
      margin: 0 auto;
    }

    .spinner-container {
      position: relative;
      width: 320px;
      height: 320px;
      margin: 30px 0;
    }

    .spinner {
      width: 100%;
      height: 100%;
      position: relative;
      transition: transform 3s cubic-bezier(0.2, 0.8, 0.2, 1);
    }

    .spinner-center {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 80px;
      height: 80px;
      background-color: var(--dark);
      border-radius: 50%;
      z-index: 10;
      display: flex;
      justify-content: center;
      align-items: center;
      cursor: pointer;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
      transition: all 0.3s ease;
    }

    .spinner-center:hover {
      transform: translate(-50%, -50%) scale(1.1);
      box-shadow: 0 12px 36px rgba(0, 0, 0, 0.15);
    }

    .spinner-center:active {
      transform: translate(-50%, -50%) scale(0.95);
    }

    .spinner-center-text {
      color: white;
      font-size: 0.9rem;
      font-weight: bold;
      text-transform: uppercase;
      letter-spacing: 1px;
    }

    .segment {
      position: absolute;
      width: 100%;
      height: 100%;
      clip-path: polygon(50% 50%, 50% 0%, 100% 0%, 100% 100%, 50% 100%);
      transform-origin: center;
      display: flex;
      justify-content: center;
      align-items: center;
      transition: all 0.5s ease;
    }

    .segment:hover {
      filter: brightness(1.1);
    }

    .segment-content {
      position: absolute;
      top: 25%;
      right: 30%;
      transform: rotate(45deg);
      z-index: 2;
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 5px;
    }
    
    .segment-icon {
      width: 50px;
      height: 50px;
      display: flex;
      justify-content: center;
      align-items: center;
      border-radius: 12px;
      background-color: rgba(255, 255, 255, 0.85);
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
      font-size: 1.8rem;
      transition: transform 0.3s ease;
    }

    .segment-text {
      font-size: 0.8rem;
      color: rgba(255, 255, 255, 0.9);
      font-weight: bold;
      text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    }

    .controls {
      display: flex;
      justify-content: center;
      gap: 20px;
      margin-top: 20px;
      z-index: 10;
    }

    .control-btn {
      padding: 12px 24px;
      border: none;
      border-radius: 50px;
      background-color: var(--secondary);
      color: white;
      font-weight: bold;
      cursor: pointer;
      transition: all 0.3s ease;
      box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
    }

    .control-btn:hover {
      transform: translateY(-2px);
      box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
    }

    .control-btn:active {
      transform: translateY(0);
    }

    .topic-display {
      margin-top: 30px;
      padding: 20px;
      background-color: white;
      border-radius: 15px;
      box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
      text-align: center;
      max-width: 80%;
      transform: scale(0);
      transition: all 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
      position: relative;
      z-index: 5;
    }

    .topic-display.active {
      transform: scale(1);
    }

    .topic-title {
      font-size: 1.5rem;
      color: var(--dark);
      margin-bottom: 10px;
    }

    .topic-description {
      font-size: 0.9rem;
      color: #666;
    }

    .fun-facts {
      margin-top: 15px;
      font-size: 0.9rem;
      font-style: italic;
      color: var(--primary);
    }

    .particles {
      position: absolute;
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      pointer-events: none;
      z-index: 1;
    }

    .particle {
      position: absolute;
      border-radius: 50%;
      opacity: 0;
      transform: scale(0);
    }

    @media (max-width: 600px) {
      .spinner-container {
        width: 280px;
        height: 280px;
      }

      .spinner-center {
        width: 70px;
        height: 70px;
      }

      .segment-icon {
        width: 40px;
        height: 40px;
        font-size: 1.4rem;
      }

      .segment-text {
        font-size: 0.7rem;
      }

      .title h1 {
        font-size: 1.8rem;
      }

      .subtitle {
        font-size: 1rem;
      }
    }

    /* Animations */
    @keyframes float {
      0%, 100% { transform: translateY(0) rotate(0); }
      50% { transform: translateY(-10px) rotate(5deg); }
    }

    @keyframes pulsate {
      0%, 100% { transform: scale(1); opacity: 1; }
      50% { transform: scale(1.05); opacity: 0.9; }
    }

    @keyframes particleBurst {
      0% { transform: scale(0); opacity: 0; }
      50% { transform: scale(1); opacity: 0.8; }
      100% { transform: scale(1.5); opacity: 0; }
    }

    .float-animation {
      animation: float 6s ease-in-out infinite;
    }

    .pulsate-animation {
      animation: pulsate 3s ease-in-out infinite;
    }

    /* Shape morphing */
    .shape-morph {
      position: absolute;
      width: 140px;
      height: 140px;
      background-color: var(--accent1);
      border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%;
      z-index: -1;
      opacity: 0.2;
      transition: all 2s ease;
    }

    .shape-morph:nth-child(1) {
      top: 10%;
      left: 10%;
      background-color: var(--primary);
      animation: morphAnimation1 15s ease-in-out infinite alternate;
    }

    .shape-morph:nth-child(2) {
      bottom: 10%;
      right: 10%;
      background-color: var(--secondary);
      animation: morphAnimation2 18s ease-in-out infinite alternate;
    }

    .shape-morph:nth-child(3) {
      top: 40%;
      right: 20%;
      background-color: var(--accent2);
      animation: morphAnimation3 20s ease-in-out infinite alternate;
    }

    @keyframes morphAnimation1 {
      0% { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
      25% { border-radius: 58% 42% 75% 25% / 76% 46% 54% 24%; }
      50% { border-radius: 50% 50% 33% 67% / 55% 27% 73% 45%; }
      75% { border-radius: 33% 67% 58% 42% / 63% 68% 32% 37%; }
      100% { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
    }

    @keyframes morphAnimation2 {
      0% { border-radius: 50% 50% 33% 67% / 55% 27% 73% 45%; }
      25% { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
      50% { border-radius: 58% 42% 75% 25% / 76% 46% 54% 24%; }
      75% { border-radius: 33% 67% 58% 42% / 63% 68% 32% 37%; }
      100% { border-radius: 50% 50% 33% 67% / 55% 27% 73% 45%; }
    }

    @keyframes morphAnimation3 {
      0% { border-radius: 33% 67% 58% 42% / 63% 68% 32% 37%; }
      25% { border-radius: 50% 50% 33% 67% / 55% 27% 73% 45%; }
      50% { border-radius: 30% 70% 70% 30% / 30% 30% 70% 70%; }
      75% { border-radius: 58% 42% 75% 25% / 76% 46% 54% 24%; }
      100% { border-radius: 33% 67% 58% 42% / 63% 68% 32% 37%; }
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="shape-morph"></div>
    <div class="shape-morph"></div>
    <div class="shape-morph"></div>

    <div class="title">
      <h1>Knowledge Spinner</h1>
      <p class="subtitle">Spin to discover fascinating subjects! Each color leads to a new learning adventure.</p>
    </div>

    <div class="spinner-container">
      <div class="spinner" id="spinner">
        <!-- Segments will be added by JavaScript -->
      </div>
      <div class="spinner-center" id="spinButton">
        <span class="spinner-center-text">SPIN</span>
      </div>
    </div>

    <div class="controls">
      <button class="control-btn" id="resetButton">Reset</button>
      <button class="control-btn" id="hintButton">Hint</button>
    </div>

    <div class="topic-display" id="topicDisplay">
      <h3 class="topic-title" id="topicTitle">Mathematics</h3>
      <p class="topic-description" id="topicDescription">Discover patterns and solve problems with numbers.</p>
      <p class="fun-facts" id="topicFacts">Did you know? Zero wasn't always a number!</p>
    </div>

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

  <script>
    // Define our educational topics
    const topics = [
      {
        name: "Mathematics",
        icon: "➗",
        color: "#FF6B6B",
        description: "Explore the magical world of numbers, shapes, and patterns!",
        facts: "Did you know? The Fibonacci sequence appears throughout nature in flowers and shells!"
      },
      {
        name: "Science",
        icon: "🔬",
        color: "#4ECDC4",
        description: "Discover how our world works through observation and experiments.",
        facts: "Fun fact: A bolt of lightning is five times hotter than the surface of the sun!"
      },
      {
        name: "Reading",
        icon: "📚",
        color: "#FFE66D",
        description: "Adventure through stories and boost your vocabulary skills.",
        facts: "Amazing! Your brain processes reading by creating a mental movie."
      },
      {
        name: "History",
        icon: "⏳",
        color: "#7A77FF", 
        description: "Travel back in time to learn how our world became what it is today.",
        facts: "Wow! The Great Pyramids were built when woolly mammoths still roamed Earth."
      },
      {
        name: "Art",
        icon: "🎨",
        color: "#FF9F1C",
        description: "Express yourself through colors, shapes, and creative thinking.",
        facts: "Did you know? The Mona Lisa has no visible eyebrows or eyelashes!"
      },
      {
        name: "Music",
        icon: "🎵",
        color: "#A5FFD6",
        description: "Learn rhythm, melody, and the joy of creating beautiful sounds.",
        facts: "Amazing! Music can help you remember things better and improve your mood."
      },
      {
        name: "Geography",
        icon: "🌍",
        color: "#C23B22",
        description: "Explore countries, landforms, and how humans interact with Earth.",
        facts: "Wow! There's a waterfall underwater in the Denmark Strait between Iceland and Greenland."
      },
      {
        name: "Coding",
        icon: "💻",
        color: "#03CEA4",
        description: "Learn to speak the language of computers and create your own games!",
        facts: "Cool! The first computer programmer was a woman named Ada Lovelace."
      }
    ];

    // DOM Elements
    const spinner = document.getElementById('spinner');
    const spinButton = document.getElementById('spinButton');
    const resetButton = document.getElementById('resetButton');
    const hintButton = document.getElementById('hintButton');
    const topicDisplay = document.getElementById('topicDisplay');
    const topicTitle = document.getElementById('topicTitle');
    const topicDescription = document.getElementById('topicDescription');
    const topicFacts = document.getElementById('topicFacts');
    const particlesContainer = document.getElementById('particles');

    let isSpinning = false;
    let currentRotation = 0;
    let selectedTopic = null;

    // Create spinner segments
    function createSpinner() {
      // Clear existing segments
      spinner.innerHTML = '';
      
      // Create segments based on topics
      topics.forEach((topic, index) => {
        const angle = (360 / topics.length) * index;
        const segment = document.createElement('div');
        segment.className = 'segment';
        segment.style.backgroundColor = topic.color;
        segment.style.transform = `rotate(${angle}deg)`;
        
        const segmentContent = document.createElement('div');
        segmentContent.className = 'segment-content';
        
        const iconElement = document.createElement('div');
        iconElement.className = 'segment-icon pulsate-animation';
        iconElement.textContent = topic.icon;
        
        const textElement = document.createElement('div');
        textElement.className = 'segment-text';
        textElement.textContent = topic.name;
        
        segmentContent.appendChild(iconElement);
        segmentContent.appendChild(textElement);
        segment.appendChild(segmentContent);
        
        spinner.appendChild(segment);
      });
    }

    // Spin the wheel
    function spinWheel() {
      if (isSpinning) return;
      
      isSpinning = true;
      topicDisplay.classList.remove('active');
      
      // Random number of full rotations (3-5) plus a random segment
      const spinAngle = 3600 + Math.floor(Math.random() * 720);
      const totalRotation = currentRotation + spinAngle;
      
      // Animate the spinner
      spinner.style.transform = `rotate(${totalRotation}deg)`;
      currentRotation = totalRotation;
      
      // Create particle burst effect
      createParticles();
      
      // Show result after spinning is complete
      setTimeout(() => {
        isSpinning = false;
        determineResult();
      }, 3000);
    }

    // Determine which topic was selected
    function determineResult() {
      // Calculate which segment is at the top position
      const segmentAngle = 360 / topics.length;
      let normalizedRotation = currentRotation % 360;
      // We need to invert the rotation value because the spinner rotates clockwise
      normalizedRotation = 360 - normalizedRotation;
      
      const segmentIndex = Math.floor(normalizedRotation / segmentAngle) % topics.length;
      selectedTopic = topics[segmentIndex];
      
      // Display the selected topic
      topicTitle.textContent = selectedTopic.name;
      topicDescription.textContent = selectedTopic.description;
      topicFacts.textContent = selectedTopic.facts;
      topicDisplay.style.backgroundColor = selectedTopic.color + '33'; // Add 33 for transparency
      topicDisplay.classList.add('active');
    }

    // Reset the spinner
    function resetSpinner() {
      isSpinning = false;
      currentRotation = 0;
      spinner.style.transform = 'rotate(0deg)';
      topicDisplay.classList.remove('active');
      selectedTopic = null;
    }

    // Show a hint
    function showHint() {
      if (selectedTopic) {
        alert(`Here's an activity idea for ${selectedTopic.name}: ${getActivityForTopic(selectedTopic.name)}`);
      } else {
        alert("Spin the wheel first to select a topic!");
      }
    }

    // Get a specific activity suggestion based on topic
    function getActivityForTopic(topicName) {
      const activities = {
        "Mathematics": "Create a nature scavenger hunt to find Fibonacci sequences in flowers and pinecones!",
        "Science": "Make a mini volcano using baking soda and vinegar to see chemical reactions in action.",
        "Reading": "Create your own comic book by drawing pictures and adding dialogue bubbles.",
        "History": "Build a time capsule with items that represent today's world.",
        "Art": "Try blind contour drawing - draw an object without looking at your paper!",
        "Music": "Create a homemade instrument using household items and play a tune.",
        "Geography": "Use playdough to create a 3D map of your neighborhood or country.",
        "Coding": "Try to create a simple animation using block-based coding at code.org"
      };
      
      return activities[topicName] || "Explore this topic through creative play!";
    }

    // Create particle burst effect
    function createParticles() {
      particlesContainer.innerHTML = '';
      
      const colors = topics.map(topic => topic.color);
      
      for (let i = 0; i < 30; i++) {
        const particle = document.createElement('div');
        particle.className = 'particle';
        
        const size = Math.random() * 10 + 5;
        const color = colors[Math.floor(Math.random() * colors.length)];
        
        particle.style.width = `${size}px`;
        particle.style.height = `${size}px`;
        particle.style.backgroundColor = color;
        
        // Position around the center of the spinner
        const centerX = spinner.offsetWidth / 2 + spinner.offsetLeft;
        const centerY = spinner.offsetHeight / 2 + spinner.offsetTop;
        
        const angle = Math.random() * Math.PI * 2;
        const distance = 50 + Math.random() * 100;
        
        const x = centerX + Math.cos(angle) * distance;
        const y = centerY + Math.sin(angle) * distance;
        
        particle.style.left = `${x}px`;
        particle.style.top = `${y}px`;
        
        // Set animation properties
        particle.style.animation = `particleBurst ${0.5 + Math.random()}s forwards`;
        
        particlesContainer.appendChild(particle);
      }
    }

    // Initialize the spinner
    createSpinner();

    // Event listeners
    spinButton.addEventListener('click', spinWheel);
    resetButton.addEventListener('click', resetSpinner);
    hintButton.addEventListener('click', () => {
      if (selectedTopic) {
        // Create a custom tooltip instead of an alert
        const tooltip = document.createElement('div');
        tooltip.className = 'topic-display active';
        tooltip.style.position = 'absolute';
        tooltip.style.zIndex = '100';
        tooltip.style.backgroundColor = selectedTopic.color + '33';
        tooltip.style.maxWidth = '90%';
        tooltip.style.top = '50%';
        tooltip.style.left = '50%';
        tooltip.style.transform = 'translate(-50%, -50%)';
        tooltip.style.padding = '20px';
        tooltip.style.boxShadow = '0 8px 32px rgba(0, 0, 0, 0.15)';
        tooltip.style.borderRadius = '15px';
        
        tooltip.innerHTML = `
          <h3 class="topic-title">Activity for ${selectedTopic.name}</h3>
          <p class="topic-description">${getActivityForTopic(selectedTopic.name)}</p>
          <button class="control-btn" style="margin-top: 15px;">Close</button>
        `;
        
        document.querySelector('.container').appendChild(tooltip);
        
        tooltip.querySelector('button').addEventListener('click', () => {
          tooltip.remove();
        });
        
        // Auto remove after 5 seconds
        setTimeout(() => {
          if (document.body.contains(tooltip)) {
            tooltip.remove();
          }
        }, 5000);
      } else {
        topicDisplay.innerHTML = `<h3 class="topic-title">Hint</h3><p class="topic-description">Spin the wheel first to select a topic!</p>`;
        topicDisplay.style.backgroundColor = '#f1f1f1';
        topicDisplay.classList.add('active');
        
        setTimeout(() => {
          topicDisplay.classList.remove('active');
        }, 2000);
      }
    });
  </script>
</body>
</html>

10) Travel Booking Globe Spinner

Here's the code:

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Travel Booking Globe Spinner</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
        }

        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #f5f2ed;
            overflow: hidden;
            perspective: 1000px;
        }

        .container {
            width: 100%;
            max-width: 700px;
            height: 700px;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            padding: 20px;
            position: relative;
        }

        .globe-container {
            position: relative;
            width: 300px;
            height: 300px;
            margin: 30px 0;
            transform-style: preserve-3d;
        }

        .globe {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background: linear-gradient(145deg, #8a6f4d, #d4b995);
            box-shadow: 0 0 60px rgba(210, 180, 140, 0.4);
            transform-style: preserve-3d;
            animation: float 6s ease-in-out infinite;
        }

        .globe::before {
            content: '';
            position: absolute;
            top: -10px;
            left: -10px;
            right: -10px;
            bottom: -10px;
            border-radius: 50%;
            border: 2px solid rgba(210, 180, 140, 0.3);
            box-shadow: inset 0 0 20px rgba(210, 180, 140, 0.4);
            animation: pulse 4s linear infinite;
        }

        .latitude, .longitude {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            border: 1px solid rgba(255, 255, 255, 0.2);
            box-shadow: 0 0 10px rgba(255, 255, 255, 0.1);
        }

        .latitude {
            transform: rotateX(90deg);
        }

        .longitude {
            transform: rotateY(90deg);
        }

        .latitude-lines {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            transform-style: preserve-3d;
        }

        .latitude-line {
            position: absolute;
            width: 100%;
            height: 1px;
            background-color: rgba(255, 255, 255, 0.2);
            transform-origin: center;
        }

        .longitude-lines {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            transform-style: preserve-3d;
        }

        .longitude-line {
            position: absolute;
            top: 0;
            width: 1px;
            height: 100%;
            background-color: rgba(255, 255, 255, 0.2);
            transform-origin: center;
        }

        .spinner {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            border: 3px solid transparent;
            border-top-color: #d4b995;
            border-bottom-color: #8a6f4d;
            animation: spin 3s linear infinite;
        }

        .spinner::before {
            content: '';
            position: absolute;
            top: 5px;
            left: 5px;
            right: 5px;
            bottom: 5px;
            border-radius: 50%;
            border: 3px solid transparent;
            border-left-color: #d4b995;
            border-right-color: #8a6f4d;
            animation: spin 2s linear infinite reverse;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        @keyframes pulse {
            0%, 100% { transform: scale(1); opacity: 0.7; }
            50% { transform: scale(1.05); opacity: 0.9; }
        }

        @keyframes float {
            0%, 100% { transform: translateY(0) rotateY(0); }
            50% { transform: translateY(-15px) rotateY(180deg); }
        }

        .destination-search {
            width: 100%;
            max-width: 500px;
            background-color: white;
            padding: 25px;
            border-radius: 15px;
            box-shadow: 0 10px 30px rgba(138, 111, 77, 0.2);
            margin-top: 30px;
            transform: translateY(20px);
            opacity: 0;
            animation: appear 1s forwards 0.5s;
            z-index: 10;
        }

        @keyframes appear {
            to {
                transform: translateY(0);
                opacity: 1;
            }
        }

        h1 {
            color: #5a4827;
            font-size: 2rem;
            margin-bottom: 10px;
            text-align: center;
        }

        p {
            color: #8a6f4d;
            margin-bottom: 20px;
            text-align: center;
            line-height: 1.5;
        }

        .search-form {
            display: flex;
            flex-direction: column;
            gap: 15px;
        }

        .search-row {
            display: flex;
            gap: 15px;
        }

        .search-field {
            flex: 1;
            position: relative;
        }

        label {
            display: block;
            color: #8a6f4d;
            margin-bottom: 5px;
            font-weight: 500;
        }

        input, select {
            width: 100%;
            padding: 12px 15px;
            border: 2px solid #d4b995;
            border-radius: 8px;
            background-color: #fff;
            color: #5a4827;
            font-size: 1rem;
            transition: all 0.3s ease;
        }

        input:focus, select:focus {
            outline: none;
            border-color: #8a6f4d;
            box-shadow: 0 0 0 3px rgba(138, 111, 77, 0.25);
        }

        button {
            background: linear-gradient(145deg, #8a6f4d, #d4b995);
            color: white;
            border: none;
            padding: 15px;
            border-radius: 8px;
            font-size: 1rem;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            margin-top: 10px;
            box-shadow: 0 4px 15px rgba(138, 111, 77, 0.3);
        }

        button:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 20px rgba(138, 111, 77, 0.4);
        }

        button:active {
            transform: translateY(0);
        }

        .destination-dots {
            position: absolute;
            width: 10px;
            height: 10px;
            background-color: rgba(210, 180, 140, 0.8);
            border-radius: 50%;
            box-shadow: 0 0 10px rgba(210, 180, 140, 0.6);
            z-index: 5;
            transform-style: preserve-3d;
        }

        .destination-label {
            position: absolute;
            color: white;
            font-size: 0.7rem;
            text-shadow: 0 0 3px rgba(0, 0, 0, 0.7);
            transform: translateZ(5px);
            pointer-events: none;
            white-space: nowrap;
        }

        .globe-pulse {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            background: radial-gradient(circle, rgba(210, 180, 140, 0.1) 0%, rgba(210, 180, 140, 0) 70%);
            transform: scale(1.2);
            animation: globePulse 3s infinite ease-in-out;
        }

        @keyframes globePulse {
            0%, 100% { opacity: 0.3; transform: scale(1.2); }
            50% { opacity: 0.7; transform: scale(1.3); }
        }

        @media (max-width: 700px) {
            .container {
                height: auto;
                padding: 15px;
            }
            .globe-container {
                width: 200px;
                height: 200px;
                margin: 20px 0;
            }
            .destination-search {
                padding: 20px;
                max-width: 90%;
            }
            h1 {
                font-size: 1.5rem;
            }
            .search-row {
                flex-direction: column;
                gap: 10px;
            }
            input, select, button {
                padding: 10px;
            }
        }

        @media (max-width: 400px) {
            .globe-container {
                width: 150px;
                height: 150px;
            }
            h1 {
                font-size: 1.3rem;
            }
        }
        
        /* Custom input fields styling */
        .search-field.date-field {
            position: relative;
        }
        
        .date-field input {
            padding-right: 40px;
        }
        
        .date-field::after {
            content: '📅';
            position: absolute;
            right: 15px;
            top: 40px;
            pointer-events: none;
        }
        
        .location-field::after {
            content: '📍';
            position: absolute;
            right: 15px;
            top: 40px;
            pointer-events: none;
        }
        
        .traveler-field::after {
            content: '👥';
            position: absolute;
            right: 15px;
            top: 40px;
            pointer-events: none;
        }
        
        /* Popular destinations feature */
        .popular-destinations {
            display: flex;
            gap: 10px;
            flex-wrap: wrap;
            margin-top: 15px;
            justify-content: center;
        }
        
        .destination-tag {
            background-color: rgba(210, 180, 140, 0.2);
            color: #5a4827;
            padding: 5px 10px;
            border-radius: 20px;
            font-size: 0.8rem;
            cursor: pointer;
            transition: all 0.3s ease;
            border: 1px solid transparent;
        }
        
        .destination-tag:hover {
            background-color: rgba(210, 180, 140, 0.4);
            border-color: #8a6f4d;
            transform: translateY(-2px);
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="globe-container" id="globe-container">
            <div class="globe">
                <div class="latitude"></div>
                <div class="longitude"></div>
                <div class="latitude-lines" id="latitude-lines"></div>
                <div class="longitude-lines" id="longitude-lines"></div>
                <div class="spinner"></div>
            </div>
            <div class="globe-pulse"></div>
        </div>
        
        <div class="destination-search">
            <h1>Discover Your Next Adventure</h1>
            <p>Spin the globe and find unexplored destinations waiting for your footsteps.</p>
            
            <div class="search-form">
                <div class="search-row">
                    <div class="search-field location-field">
                        <label for="destination">Destination</label>
                        <input type="text" id="destination" placeholder="Where to?">
                    </div>
                    <div class="search-field date-field">
                        <label for="departure">Departure</label>
                        <input type="text" id="departure" placeholder="Select date">
                    </div>
                </div>
                
                <div class="search-row">
                    <div class="search-field date-field">
                        <label for="return">Return</label>
                        <input type="text" id="return" placeholder="Select date">
                    </div>
                    <div class="search-field traveler-field">
                        <label for="travelers">Travelers</label>
                        <select id="travelers">
                            <option value="1">1 Adult</option>
                            <option value="2">2 Adults</option>
                            <option value="3">3 Adults</option>
                            <option value="4">2 Adults, 2 Children</option>
                        </select>
                    </div>
                </div>
                
                <button id="search-btn">Find My Journey</button>
            </div>
            
            <div class="popular-destinations">
                <span class="destination-tag">Bali</span>
                <span class="destination-tag">Santorini</span>
                <span class="destination-tag">Tokyo</span>
                <span class="destination-tag">Machu Picchu</span>
                <span class="destination-tag">Maldives</span>
            </div>
        </div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', () => {
            const globeContainer = document.getElementById('globe-container');
            const latitudeLines = document.getElementById('latitude-lines');
            const longitudeLines = document.getElementById('longitude-lines');
            const searchBtn = document.getElementById('search-btn');
            const destinationInput = document.getElementById('destination');
            const departureInput = document.getElementById('departure');
            const returnInput = document.getElementById('return');
            const destinationTags = document.querySelectorAll('.destination-tag');
            
            // Create latitude lines
            for (let i = 0; i < 9; i++) {
                const line = document.createElement('div');
                line.className = 'latitude-line';
                line.style.top = `${i * 33.3}px`;
                latitudeLines.appendChild(line);
            }
            
            // Create longitude lines
            for (let i = 0; i < 12; i++) {
                const line = document.createElement('div');
                line.className = 'longitude-line';
                line.style.left = `${150}px`;
                line.style.transform = `rotateY(${i * 15}deg)`;
                longitudeLines.appendChild(line);
            }
            
            // Sample destinations with coordinates (simplified for the demo)
            const destinations = [
                { name: 'New York', x: 74, y: 40 },
                { name: 'Paris', x: 48, y: 2 },
                { name: 'Tokyo', x: 35, y: 139 },
                { name: 'Sydney', x: -33, y: 151 },
                { name: 'Rio', x: -22, y: -43 },
                { name: 'Cairo', x: 30, y: 31 }
            ];
            
            // Place destinations dots on the globe
            destinations.forEach(dest => {
                const dot = document.createElement('div');
                dot.className = 'destination-dots';
                
                // Convert lat/long to 3D position on sphere (simplified)
                const phi = (90 - dest.x) * (Math.PI / 180);
                const theta = (dest.y + 180) * (Math.PI / 180);
                
                const x = -150 * Math.sin(phi) * Math.cos(theta);
                const y = 150 * Math.cos(phi);
                const z = 150 * Math.sin(phi) * Math.sin(theta);
                
                dot.style.transform = `translate3d(${x + 150}px, ${y + 150}px, ${z}px)`;
                
                const label = document.createElement('div');
                label.className = 'destination-label';
                label.textContent = dest.name;
                label.style.transform = `translate3d(${x + 155}px, ${y + 150}px, ${z + 5}px)`;
                
                globeContainer.appendChild(dot);
                globeContainer.appendChild(label);
            });
            
            // Interactive globe rotation
            let isDragging = false;
            let previousMousePosition = { x: 0, y: 0 };
            let rotation = { x: 0, y: 0 };
            const globe = document.querySelector('.globe');
            
            globeContainer.addEventListener('mousedown', (e) => {
                isDragging = true;
                previousMousePosition = {
                    x: e.clientX,
                    y: e.clientY
                };
            });
            
            document.addEventListener('mousemove', (e) => {
                if (!isDragging) return;
                
                const deltaMove = {
                    x: e.clientX - previousMousePosition.x,
                    y: e.clientY - previousMousePosition.y
                };
                
                rotation.y += deltaMove.x * 0.5;
                rotation.x -= deltaMove.y * 0.5;
                
                globe.style.transform = `rotateX(${rotation.x}deg) rotateY(${rotation.y}deg)`;
                
                previousMousePosition = {
                    x: e.clientX,
                    y: e.clientY
                };
            });
            
            document.addEventListener('mouseup', () => {
                isDragging = false;
            });

            // Simulate date picker functionality (simplified for the demo)
            departureInput.addEventListener('focus', () => {
                const today = new Date();
                const formattedDate = `${today.getMonth() + 1}/${today.getDate()}/${today.getFullYear()}`;
                departureInput.value = formattedDate;
            });
            
            returnInput.addEventListener('focus', () => {
                const today = new Date();
                today.setDate(today.getDate() + 7); // Default to a week from now
                const formattedDate = `${today.getMonth() + 1}/${today.getDate()}/${today.getFullYear()}`;
                returnInput.value = formattedDate;
            });
            
            // Popular destinations tag click
            destinationTags.forEach(tag => {
                tag.addEventListener('click', () => {
                    destinationInput.value = tag.textContent;
                    
                    // Visual feedback
                    tag.style.backgroundColor = 'rgba(138, 111, 77, 0.4)';
                    setTimeout(() => {
                        tag.style.backgroundColor = 'rgba(210, 180, 140, 0.2)';
                    }, 500);
                    
                    // Find the destination on the globe (simplified)
                    const dest = destinations.find(d => d.name.includes(tag.textContent));
                    if (dest) {
                        // Highlight effect on the globe (not exact matching but suggestive)
                        const dots = document.querySelectorAll('.destination-dots');
                        dots.forEach((dot, index) => {
                            if (index % destinations.length === destinations.indexOf(dest)) {
                                dot.style.background = '#d4b995';
                                dot.style.boxShadow = '0 0 15px #d4b995';
                                dot.style.transform += ' scale(1.5)';
                                setTimeout(() => {
                                    dot.style.background = 'rgba(210, 180, 140, 0.8)';
                                    dot.style.boxShadow = '0 0 10px rgba(210, 180, 140, 0.6)';
                                    dot.style.transform = dot.style.transform.replace(' scale(1.5)', '');
                                }, 2000);
                            }
                        });
                    }
                });
            });
            
            // Search button animation and functionality
            searchBtn.addEventListener('click', () => {
                if (!destinationInput.value) {
                    destinationInput.style.borderColor = '#ff6b6b';
                    setTimeout(() => {
                        destinationInput.style.borderColor = '#d4b995';
                    }, 800);
                    return;
                }
                
                searchBtn.innerHTML = 'Searching...';
                searchBtn.disabled = true;
                
                // Simulate search processing
                setTimeout(() => {
                    searchBtn.innerHTML = 'Journey Found!';
                    searchBtn.style.backgroundColor = '#5a8a4f';
                    
                    // Show success pulse on the globe
                    const pulse = document.createElement('div');
                    pulse.style.position = 'absolute';
                    pulse.style.width = '100%';
                    pulse.style.height = '100%';
                    pulse.style.borderRadius = '50%';
                    pulse.style.background = 'rgba(90, 138, 79, 0.2)';
                    pulse.style.animation = 'pulse 1s ease-out';
                    globe.appendChild(pulse);
                    
                    setTimeout(() => {
                        searchBtn.innerHTML = 'Find My Journey';
                        searchBtn.style.backgroundColor = '';
                        searchBtn.disabled = false;
                        globe.removeChild(pulse);
                    }, 2000);
                }, 1500);
            });
            
            // Auto rotation for the globe (gentle movement when not interacted with)
            let autoRotate = true;
            let autoRotateInterval;
            
            function startAutoRotation() {
                if (autoRotateInterval) clearInterval(autoRotateInterval);
                
                autoRotateInterval = setInterval(() => {
                    if (!isDragging && autoRotate) {
                        rotation.y += 0.2;
                        globe.style.transform = `rotateX(${rotation.x}deg) rotateY(${rotation.y}deg)`;
                    }
                }, 50);
            }
            
            startAutoRotation();
            
            // Pause auto-rotation when hovering over the globe
            globeContainer.addEventListener('mouseenter', () => {
                autoRotate = false;
            });
            
            globeContainer.addEventListener('mouseleave', () => {
                autoRotate = true;
            });
            
            // Touch events for mobile devices
            globeContainer.addEventListener('touchstart', (e) => {
                isDragging = true;
                previousMousePosition = {
                    x: e.touches[0].clientX,
                    y: e.touches[0].clientY
                };
                autoRotate = false;
            });
            
            document.addEventListener('touchmove', (e) => {
                if (!isDragging) return;
                
                const deltaMove = {
                    x: e.touches[0].clientX - previousMousePosition.x,
                    y: e.touches[0].clientY - previousMousePosition.y
                };
                
                rotation.y += deltaMove.x * 0.5;
                rotation.x -= deltaMove.y * 0.5;
                
                globe.style.transform = `rotateX(${rotation.x}deg) rotateY(${rotation.y}deg)`;
                
                previousMousePosition = {
                    x: e.touches[0].clientX,
                    y: e.touches[0].clientY
                };
            });
            
            document.addEventListener('touchend', () => {
                isDragging = false;
                setTimeout(() => {
                    autoRotate = true;
                }, 3000);
            });
        });
    </script>
</body>
</html>

Tips To Design a Great Spinner

  • Keep It Simple: Avoid overly complex designs. A clean, minimal spinner ensures clarity and avoids distracting users.
  • Ensure Visibility: Use contrasting colors to make the spinner easily noticeable against the background.
  • Maintain Consistency: Align the spinner's style with your overall UI design to create a cohesive user experience.
  • Optimize Performance: Ensure the spinner loads quickly and doesn't impact the page's performance.
  • Provide Feedback: Use spinners to indicate progress and reassure users that the process is ongoing.

Get Started with Subframe for Free

Ready to elevate your UI design game? With Subframe, you can create pixel-perfect interfaces, including spinners, in minutes. Its drag-and-drop editor ensures efficiency and precision.

Don't wait! Start for free and begin designing stunning UIs immediately. Experience the ease and power of Subframe today!

Join thousands of happy builders.

Subframe lets you build stunning UI with beautifully crafted components and a drag-and-drop visual editor.

Made in Webflow