Liquid effects can transform a mundane user interface into a visually captivating experience. These dynamic animations mimic the fluidity of water, adding a touch of elegance and sophistication to any design.
In this article, we will explore ten stunning liquid effect examples that can elevate your UI projects. From subtle ripples to dramatic splashes, these effects demonstrate the versatility and impact of liquid animations.
CODE1
Here's the code:
CODETEXT1
CODE2
Here's the code:
CODETEXT2
CODE3
Here's the code:
CODETEXT3
CODE4
Here's the code:
CODETEXT4
CODE5
Here's the code:
CODETEXT5
Subframe's drag-and-drop interface and intuitive, responsive canvas make designing liquid effects a breeze. Loved by designers and developers alike, it ensures pixel-perfect UI every time.
Start for free and transform your UI projects today!
CODE6
Here's the code:
CODETEXT6
CODE7
Here's the code:
CODETEXT7
CODE8
Here's the code:
CODETEXT8
CODE9
Here's the code:
CODETEXT9
CODE10
Here's the code:
CODETEXT10
Ready to elevate your UI designs? With Subframe, you can create stunning, pixel-perfect interfaces, including mesmerizing liquid effects, in minutes. Our drag-and-drop editor ensures efficiency and ease.
Start for free and begin designing immediately. Transform your projects today!
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Ripple Music Player</title> <style> :root { --primary: #8A2BE2; --secondary: #4169E1; --tertiary: #00BFFF; --text-light: #ffffff; --background: #121212; --card-bg: #1e1e1e; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; } body { display: flex; align-items: center; justify-content: center; min-height: 100vh; background-color: var(--background); overflow: hidden; padding: 20px; } .player-container { width: 100%; max-width: 650px; background: var(--card-bg); border-radius: 24px; padding: 32px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); position: relative; overflow: hidden; z-index: 1; } .player-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; } .logo { font-size: 24px; font-weight: 800; background: linear-gradient(45deg, var(--tertiary), var(--primary)); -webkit-background-clip: text; background-clip: text; color: transparent; letter-spacing: -0.5px; } .now-playing { color: var(--text-light); font-size: 14px; opacity: 0.7; display: flex; align-items: center; gap: 6px; } .pulse { width: 6px; height: 6px; border-radius: 50%; background: var(--tertiary); animation: pulse 1.5s infinite; } @keyframes pulse { 0% { transform: scale(0.8); opacity: 0.5; } 50% { transform: scale(1.2); opacity: 1; } 100% { transform: scale(0.8); opacity: 0.5; } } .album-art { width: 100%; height: 300px; border-radius: 16px; background-image: url('https://images.unsplash.com/photo-1514525253161-7a46d19cd819?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=1074&q=80'); background-size: cover; background-position: center; margin-bottom: 24px; position: relative; overflow: hidden; } .album-overlay { position: absolute; bottom: 0; left: 0; right: 0; background: linear-gradient(transparent, rgba(0, 0, 0, 0.8)); padding: 20px; color: var(--text-light); } .track-title { font-size: 24px; font-weight: 700; margin-bottom: 4px; } .artist { font-size: 16px; opacity: 0.8; } .controls { display: flex; justify-content: space-between; align-items: center; margin-top: 20px; } .progress-container { width: 100%; background: rgba(255, 255, 255, 0.1); height: 6px; border-radius: 10px; margin-bottom: 16px; overflow: hidden; } .progress-bar { height: 100%; width: 35%; background: linear-gradient(90deg, var(--tertiary), var(--primary)); border-radius: 10px; position: relative; } .time { display: flex; justify-content: space-between; color: var(--text-light); font-size: 12px; opacity: 0.7; margin-bottom: 24px; } .control-btn { background: none; border: none; color: var(--text-light); font-size: 20px; cursor: pointer; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; transition: transform 0.2s; } .control-btn:hover { transform: scale(1.1); } .play-btn { width: 60px; height: 60px; border-radius: 50%; background: linear-gradient(45deg, var(--primary), var(--secondary)); position: relative; overflow: hidden; cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--text-light); font-size: 24px; box-shadow: 0 4px 15px rgba(138, 43, 226, 0.4); z-index: 10; } .play-btn::before { content: ""; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(255, 255, 255, 0.2); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.5s, height 0.5s; } .ripple { position: absolute; background: rgba(255, 255, 255, 0.25); border-radius: 50%; transform: scale(0); animation: rippleEffect 1s linear; pointer-events: none; } @keyframes rippleEffect { to { transform: scale(4); opacity: 0; } } .upcoming-tracks { margin-top: 30px; } .section-header { color: var(--text-light); font-size: 18px; font-weight: 600; margin-bottom: 16px; display: flex; align-items: center; justify-content: space-between; } .view-all { font-size: 14px; color: var(--tertiary); cursor: pointer; font-weight: 500; } .track-list { display: flex; gap: 16px; overflow-x: auto; padding-bottom: 20px; scrollbar-width: thin; scrollbar-color: var(--secondary) var(--card-bg); } .track-list::-webkit-scrollbar { height: 6px; } .track-list::-webkit-scrollbar-track { background: var(--card-bg); border-radius: 10px; } .track-list::-webkit-scrollbar-thumb { background-color: var(--secondary); border-radius: 10px; } .track-item { min-width: 140px; background: rgba(255, 255, 255, 0.05); border-radius: 12px; padding: 12px; transition: transform 0.3s, background 0.3s; cursor: pointer; } .track-item:hover { transform: translateY(-5px); background: rgba(255, 255, 255, 0.1); } .track-thumbnail { width: 100%; height: 120px; border-radius: 8px; background-size: cover; background-position: center; margin-bottom: 10px; } .track-info { color: var(--text-light); } .track-info h4 { font-size: 14px; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .track-info p { font-size: 12px; opacity: 0.7; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } @media (max-width: 600px) { .player-container { padding: 24px; } .album-art { height: 220px; } .track-title { font-size: 20px; } .track-item { min-width: 120px; } .track-thumbnail { height: 100px; } } /* Material Icons Setup */ .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; font-size: 24px; line-height: 1; letter-spacing: normal; text-transform: none; display: inline-block; white-space: nowrap; word-wrap: normal; direction: ltr; -webkit-font-feature-settings: 'liga'; -webkit-font-smoothing: antialiased; } </style> <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet"> </head> <body> <div class="player-container"> <div class="player-header"> <div class="logo">WaveStream</div> <div class="now-playing"> <div class="pulse"></div> <span>NOW PLAYING</span> </div> </div> <div class="album-art"> <div class="album-overlay"> <div class="track-title">Electric Dreams</div> <div class="artist">Neon Pulse</div> </div> </div> <div class="progress-container"> <div class="progress-bar"></div> </div> <div class="time"> <span>1:45</span> <span>4:20</span> </div> <div class="controls"> <button class="control-btn"> <span class="material-icons">shuffle</span> </button> <button class="control-btn"> <span class="material-icons">skip_previous</span> </button> <div class="play-btn" id="playButton"> <span class="material-icons">play_arrow</span> </div> <button class="control-btn"> <span class="material-icons">skip_next</span> </button> <button class="control-btn"> <span class="material-icons">repeat</span> </button> </div> <div class="upcoming-tracks"> <div class="section-header"> <span>Recommended Next</span> <span class="view-all">View All</span> </div> <div class="track-list"> <div class="track-item"> <div class="track-thumbnail" style="background-image: url('https://images.unsplash.com/photo-1501084817091-a4f3d1d19e07?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80');"></div> <div class="track-info"> <h4>Midnight Ride</h4> <p>Lunar Echo</p> </div> </div> <div class="track-item"> <div class="track-thumbnail" style="background-image: url('https://images.unsplash.com/photo-1470225620780-dba8ba36b745?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80');"></div> <div class="track-info"> <h4>Digital Horizon</h4> <p>Cyber Waves</p> </div> </div> <div class="track-item"> <div class="track-thumbnail" style="background-image: url('https://images.unsplash.com/photo-1506157786151-b8491531f063?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80');"></div> <div class="track-info"> <h4>Ocean of Sound</h4> <p>Aqua Rhythm</p> </div> </div> <div class="track-item"> <div class="track-thumbnail" style="background-image: url('https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=870&q=80');"></div> <div class="track-info"> <h4>Neon Streets</h4> <p>Urban Pulse</p> </div> </div> </div> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const playButton = document.getElementById('playButton'); let isPlaying = false; // Ripple effect for the play button playButton.addEventListener('click', function(e) { // Toggle play/pause icon isPlaying = !isPlaying; const icon = playButton.querySelector('.material-icons'); icon.textContent = isPlaying ? 'pause' : 'play_arrow'; // Create ripple createRipple(e); }); function createRipple(event) { const button = event.currentTarget; // Remove existing ripples const existingRipples = button.querySelectorAll('.ripple'); existingRipples.forEach(ripple => { if (ripple.classList.contains('removing')) return; ripple.classList.add('removing'); setTimeout(() => { ripple.remove(); }, 500); }); // Get the position relative to the button const rect = button.getBoundingClientRect(); const size = Math.max(rect.width, rect.height) * 1.5; const ripple = document.createElement('span'); ripple.className = 'ripple'; ripple.style.width = ripple.style.height = `${size}px`; ripple.style.left = `${event.clientX - rect.left - size/2}px`; ripple.style.top = `${event.clientY - rect.top - size/2}px`; button.appendChild(ripple); // Remove ripple after animation setTimeout(() => { ripple.remove(); }, 1000); } // Make track items clickable const trackItems = document.querySelectorAll('.track-item'); trackItems.forEach(item => { item.addEventListener('click', function() { // Get the track info const title = this.querySelector('h4').textContent; const artist = this.querySelector('p').textContent; const thumbnail = this.querySelector('.track-thumbnail').style.backgroundImage; // Update the main player info document.querySelector('.track-title').textContent = title; document.querySelector('.artist').textContent = artist; document.querySelector('.album-art').style.backgroundImage = thumbnail; // Reset progress document.querySelector('.progress-bar').style.width = '0%'; document.querySelector('.time span:first-child').textContent = '0:00'; // Set to playing state isPlaying = true; playButton.querySelector('.material-icons').textContent = 'pause'; // Animate progress (for demo) animateProgress(); }); }); // Animate progress bar for visual effect function animateProgress() { const progressBar = document.querySelector('.progress-bar'); let width = 0; const interval = setInterval(() => { if (width >= 100 || !isPlaying) { clearInterval(interval); if (width >= 100) { isPlaying = false; playButton.querySelector('.material-icons').textContent = 'play_arrow'; } return; } width += 0.5; progressBar.style.width = `${width}%`; // Update time display const totalSeconds = 260; // 4:20 in seconds const currentSeconds = Math.floor(totalSeconds * (width / 100)); const minutes = Math.floor(currentSeconds / 60); const seconds = currentSeconds % 60; document.querySelector('.time span:first-child').textContent = `${minutes}:${seconds < 10 ? '0' + seconds : seconds}`; }, 100); } // Progress bar interaction const progressContainer = document.querySelector('.progress-container'); progressContainer.addEventListener('click', function(e) { const width = this.clientWidth; const clickX = e.offsetX; const percentage = (clickX / width) * 100; document.querySelector('.progress-bar').style.width = `${percentage}%`; // Update time display const totalSeconds = 260; // 4:20 in seconds const currentSeconds = Math.floor(totalSeconds * (percentage / 100)); const minutes = Math.floor(currentSeconds / 60); const seconds = currentSeconds % 60; document.querySelector('.time span:first-child').textContent = `${minutes}:${seconds < 10 ? '0' + seconds : seconds}`; }); // Add hover effect to control buttons const controlButtons = document.querySelectorAll('.control-btn'); controlButtons.forEach(button => { button.addEventListener('mouseenter', function() { this.style.transform = 'scale(1.1)'; }); button.addEventListener('mouseleave', function() { this.style.transform = 'scale(1)'; }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Lifestyle Liquid Navigation</title> <style> :root { --primary: #ff6b6b; --secondary: #4ecdc4; --accent: #ffd166; --dark: #292f36; --light: #f7fff7; --transition: 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Montserrat', sans-serif; } body { background: var(--light); color: var(--dark); height: 100vh; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow-x: hidden; } .container { width: 100%; max-width: 700px; height: 700px; display: flex; flex-direction: column; position: relative; overflow: hidden; background: linear-gradient(135deg, rgba(247, 255, 247, 0.9), rgba(78, 205, 196, 0.3)); border-radius: 20px; box-shadow: 0 15px 35px rgba(41, 47, 54, 0.1); } .hero { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 2rem; background-size: cover; background-position: center; position: relative; overflow: hidden; } .hero-content { text-align: center; z-index: 2; opacity: 0; transform: translateY(20px); transition: opacity 0.8s ease, transform 0.8s ease; } .hero-content.active { opacity: 1; transform: translateY(0); } .hero::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(41, 47, 54, 0.2); z-index: 1; } .hero h1 { font-size: 2.5rem; margin-bottom: 1rem; color: white; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3); } .hero p { font-size: 1.1rem; margin-bottom: 2rem; color: white; max-width: 500px; text-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); } .cta-button { background: var(--primary); color: white; border: none; padding: 12px 25px; border-radius: 30px; font-size: 1rem; font-weight: 600; cursor: pointer; box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4); transition: transform 0.3s ease, box-shadow 0.3s ease; outline: none; } .cta-button:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(255, 107, 107, 0.6); } nav { width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; position: relative; z-index: 10; padding: 0 1rem; } .menu { display: flex; justify-content: space-between; width: 100%; position: relative; max-width: 600px; padding: 10px 20px; background: rgba(255, 255, 255, 0.15); backdrop-filter: blur(10px); border-radius: 50px; box-shadow: 0 8px 32px rgba(31, 38, 135, 0.2); border: 1px solid rgba(255, 255, 255, 0.18); } .menu::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: -1; border-radius: 50px; background: linear-gradient(90deg, rgba(255, 107, 107, 0.3) 0%, rgba(78, 205, 196, 0.3) 50%, rgba(255, 209, 102, 0.3) 100%); filter: blur(4px); } .menu-item { position: relative; padding: 1rem; color: var(--dark); font-weight: 600; text-decoration: none; font-size: 1rem; text-align: center; transition: var(--transition); z-index: 2; cursor: pointer; user-select: none; display: flex; flex-direction: column; align-items: center; justify-content: center; } .menu-item::after { content: ''; position: absolute; bottom: -5px; left: 50%; width: 0; height: 2px; background: var(--primary); transform: translateX(-50%); transition: width 0.3s ease; } .menu-item:hover::after, .menu-item.active::after { width: 60%; } .menu-icon { display: block; font-size: 1.2rem; margin-bottom: 5px; transition: transform 0.3s ease; } .menu-item:hover .menu-icon { transform: translateY(-3px); } .menu-bubble { position: absolute; background: rgba(255, 255, 255, 0.2); border-radius: 50%; transform: scale(0); transition: transform 0.5s cubic-bezier(0.17, 0.67, 0.83, 0.67); z-index: 1; pointer-events: none; } .content-section { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; opacity: 0; transform: translateY(20px); transition: opacity 0.5s ease, transform 0.5s ease; z-index: 1; pointer-events: none; padding-top: 100px; } .content-section.active { opacity: 1; transform: translateY(0); pointer-events: all; } .content-wrapper { width: 90%; max-width: 600px; background: rgba(255, 255, 255, 0.9); border-radius: 15px; padding: 2rem; box-shadow: 0 10px 25px rgba(41, 47, 54, 0.1); max-height: 500px; overflow-y: auto; position: relative; } .content-wrapper::-webkit-scrollbar { width: 8px; } .content-wrapper::-webkit-scrollbar-track { background: rgba(247, 255, 247, 0.5); border-radius: 10px; } .content-wrapper::-webkit-scrollbar-thumb { background: var(--secondary); border-radius: 10px; } .content-wrapper h2 { font-size: 1.8rem; margin-bottom: 1rem; color: var(--dark); position: relative; display: inline-block; } .content-wrapper h2::after { content: ''; position: absolute; bottom: -5px; left: 0; width: 50px; height: 3px; background: var(--primary); border-radius: 3px; } .content-wrapper p { margin-bottom: 1.5rem; line-height: 1.6; color: var(--dark); } .feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; margin-top: 1rem; } .feature-item { background: rgba(255, 255, 255, 0.8); padding: 1rem; border-radius: 10px; text-align: center; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05); transition: transform 0.3s ease, box-shadow 0.3s ease; } .feature-item:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); } .feature-icon { font-size: 1.8rem; margin-bottom: 0.5rem; color: var(--primary); } .feature-title { font-weight: 600; margin-bottom: 0.5rem; } .back-button { position: absolute; top: 15px; right: 15px; background: rgba(255, 107, 107, 0.2); border: none; width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background 0.3s ease, transform 0.3s ease; } .back-button:hover { background: rgba(255, 107, 107, 0.4); transform: rotate(90deg); } .content-image { width: 100%; height: 200px; object-fit: cover; border-radius: 10px; margin-bottom: 1.5rem; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); } .mobile-toggle { display: none; background: none; border: none; color: var(--dark); font-size: 1.5rem; cursor: pointer; z-index: 100; } @media (max-width: 600px) { .menu { position: fixed; top: 0; left: 0; width: 100%; height: 100%; flex-direction: column; justify-content: center; align-items: center; gap: 2rem; background: rgba(255, 255, 255, 0.95); border-radius: 0; transform: translateY(-100%); opacity: 0; pointer-events: none; transition: transform 0.5s ease, opacity 0.5s ease; } .menu.active { transform: translateY(0); opacity: 1; pointer-events: all; } .mobile-toggle { display: block; position: absolute; top: 20px; right: 20px; } .hero h1 { font-size: 2rem; } .content-wrapper { padding: 1.5rem; } .feature-grid { grid-template-columns: 1fr 1fr; } } @keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } } .pulse { animation: pulse 2s infinite; } /* Liquid morphing SVG filter */ .svg-filters { position: absolute; width: 0; height: 0; z-index: -1; } </style> </head> <body> <div class="container"> <nav> <div class="menu"> <a class="menu-item active" data-section="mindfulness"> <span class="menu-icon">🧘</span> Mindfulness </a> <a class="menu-item" data-section="nutrition"> <span class="menu-icon">🥗</span> Nutrition </a> <a class="menu-item" data-section="fitness"> <span class="menu-icon">💪</span> Fitness </a> <a class="menu-item" data-section="travel"> <span class="menu-icon">✈️</span> Travel </a> <div class="menu-bubble"></div> </div> <button class="mobile-toggle">☰</button> </nav> <div class="hero" style="background-image: url('https://images.unsplash.com/photo-1506126613408-eca07ce68773?auto=format&fit=crop&q=80')"> <div class="hero-content active"> <h1>Balanced Living</h1> <p>Discover a mindful approach to modern lifestyle with our curated content on wellness, nutrition, fitness, and travel.</p> <button class="cta-button pulse">Start Your Journey</button> </div> </div> <div class="content-section active" data-section="mindfulness"> <div class="content-wrapper"> <button class="back-button">✕</button> <h2>Mindfulness & Wellness</h2> <img class="content-image" src="https://images.unsplash.com/photo-1545389336-cf090694435e?auto=format&fit=crop&q=80" alt="Mindfulness practices"> <p>Cultivate presence and awareness through our mindfulness practices designed for the modern lifestyle. Our approach combines ancient wisdom with contemporary neuroscience.</p> <p>The key to lasting wellness isn't just about quick fixes—it's about building sustainable practices that align with your unique needs and circumstances.</p> <div class="feature-grid"> <div class="feature-item"> <div class="feature-icon">🧠</div> <div class="feature-title">Meditation</div> <div>Daily 10-minute practices</div> </div> <div class="feature-item"> <div class="feature-icon">📝</div> <div class="feature-title">Journaling</div> <div>Guided reflection prompts</div> </div> <div class="feature-item"> <div class="feature-icon">🌿</div> <div class="feature-title">Nature Therapy</div> <div>Forest bathing guides</div> </div> <div class="feature-item"> <div class="feature-icon">💤</div> <div class="feature-title">Sleep Hygiene</div> <div>Science-backed routines</div> </div> </div> </div> </div> <div class="content-section" data-section="nutrition"> <div class="content-wrapper"> <button class="back-button">✕</button> <h2>Nourishing Nutrition</h2> <img class="content-image" src="https://images.unsplash.com/photo-1498837167922-ddd27525d352?auto=format&fit=crop&q=80" alt="Healthy nutrition"> <p>Food is more than fuel—it's information for your body. Our nutrition philosophy focuses on whole foods, intuitive eating, and sustainable practices that support both personal and planetary health.</p> <p>We believe in balance rather than restriction, helping you develop a relationship with food that's both nourishing and joyful.</p> <div class="feature-grid"> <div class="feature-item"> <div class="feature-icon">🥑</div> <div class="feature-title">Seasonal Recipes</div> <div>Local, sustainable ingredients</div> </div> <div class="feature-item"> <div class="feature-icon">🍵</div> <div class="feature-title">Functional Foods</div> <div>Targeted nutritional benefits</div> </div> <div class="feature-item"> <div class="feature-icon">🔬</div> <div class="feature-title">Nutrition Science</div> <div>Evidence-based approaches</div> </div> <div class="feature-item"> <div class="feature-icon">🌱</div> <div class="feature-title">Plant-Forward</div> <div>Environmentally conscious eating</div> </div> </div> </div> </div> <div class="content-section" data-section="fitness"> <div class="content-wrapper"> <button class="back-button">✕</button> <h2>Functional Fitness</h2> <img class="content-image" src="https://images.unsplash.com/photo-1518611012118-696072aa579a?auto=format&fit=crop&q=80" alt="Functional fitness"> <p>Movement is medicine. Our fitness approach emphasizes functionality, mobility, and strength that translates to real-life activities, not just aesthetic goals.</p> <p>We believe the best fitness routine is one you'll actually enjoy and maintain. Find your perfect movement practice through our diverse offering of approaches.</p> <div class="feature-grid"> <div class="feature-item"> <div class="feature-icon">🏋️</div> <div class="feature-title">Strength Training</div> <div>Progressive, functional programs</div> </div> <div class="feature-item"> <div class="feature-icon">🧘♀️</div> <div class="feature-title">Mobility Work</div> <div>Joint health & flexibility</div> </div> <div class="feature-item"> <div class="feature-icon">❤️</div> <div class="feature-title">Cardio</div> <div>Zone 2 training focus</div> </div> <div class="feature-item"> <div class="feature-icon">⏱️</div> <div class="feature-title">Recovery</div> <div>Science-backed protocols</div> </div> </div> </div> </div> <div class="content-section" data-section="travel"> <div class="content-wrapper"> <button class="back-button">✕</button> <h2>Mindful Travel</h2> <img class="content-image" src="https://images.unsplash.com/photo-1476514525535-07fb3b4ae5f1?auto=format&fit=crop&q=80" alt="Mindful travel"> <p>Travel expands more than just your horizons—it transforms your perspective. Our approach to travel emphasizes cultural immersion, environmental consciousness, and authentic experiences.</p> <p>Whether you're planning a weekend retreat or a month-long adventure, we focus on journeys that nourish the mind, body, and soul.</p> <div class="feature-grid"> <div class="feature-item"> <div class="feature-icon">🗺️</div> <div class="feature-title">Slow Travel</div> <div>Immersive local experiences</div> </div> <div class="feature-item"> <div class="feature-icon">🌳</div> <div class="feature-title">Eco Retreats</div> <div>Sustainable accommodations</div> </div> <div class="feature-item"> <div class="feature-icon">🧳</div> <div class="feature-title">Pack Light</div> <div>Minimalist travel guides</div> </div> <div class="feature-item"> <div class="feature-icon">🍊</div> <div class="feature-title">Wellness Tourism</div> <div>Healing destinations</div> </div> </div> </div> </div> </div> <!-- SVG Filters for liquid effects --> <svg class="svg-filters"> <defs> <filter id="liquid-filter"> <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur" /> <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="liquid" /> <feComposite in="SourceGraphic" in2="liquid" operator="atop"/> </filter> </defs> </svg> <script> document.addEventListener('DOMContentLoaded', function() { const menuItems = document.querySelectorAll('.menu-item'); const menuBubble = document.querySelector('.menu-bubble'); const contentSections = document.querySelectorAll('.content-section'); const backButtons = document.querySelectorAll('.back-button'); const mobileToggle = document.querySelector('.mobile-toggle'); const menu = document.querySelector('.menu'); const heroContent = document.querySelector('.hero-content'); const ctaButton = document.querySelector('.cta-button'); const hero = document.querySelector('.hero'); // Initialize hero background updateHeroBackground('mindfulness'); // Show the hero content with animation setTimeout(() => { heroContent.classList.add('active'); }, 300); // Handle menu item hover or click menuItems.forEach(item => { item.addEventListener('mouseenter', (e) => { createBubbleEffect(e); }); item.addEventListener('click', (e) => { menuItems.forEach(menuItem => menuItem.classList.remove('active')); item.classList.add('active'); const sectionName = item.getAttribute('data-section'); toggleSection(sectionName); updateHeroBackground(sectionName); // Close mobile menu if it's open if (menu.classList.contains('active')) { menu.classList.remove('active'); } // Animate the hero content heroContent.classList.remove('active'); setTimeout(() => { heroContent.classList.add('active'); }, 300); }); }); // Back button functionality backButtons.forEach(button => { button.addEventListener('click', () => { contentSections.forEach(section => { section.classList.remove('active'); }); // Show the hero content again heroContent.classList.remove('active'); setTimeout(() => { heroContent.classList.add('active'); }, 300); }); }); // Mobile menu toggle mobileToggle.addEventListener('click', () => { menu.classList.toggle('active'); }); // CTA button effect ctaButton.addEventListener('click', () => { // Get current active section const activeMenuItem = document.querySelector('.menu-item.active'); const sectionName = activeMenuItem.getAttribute('data-section'); toggleSection(sectionName); }); // Create bubble effect function function createBubbleEffect(e) { const item = e.currentTarget; const rect = item.getBoundingClientRect(); const size = Math.max(rect.width, rect.height) * 2; menuBubble.style.width = `${size}px`; menuBubble.style.height = `${size}px`; menuBubble.style.left = `${rect.left + rect.width/2 - size/2}px`; menuBubble.style.top = `${rect.top + rect.height/2 - size/2}px`; // Reset the animation menuBubble.style.transform = 'scale(0)'; void menuBubble.offsetWidth; // Trigger reflow // Start the animation menuBubble.style.transform = 'scale(1)'; // Apply filter for liquid effect menuBubble.style.filter = 'url(#liquid-filter)'; // Randomize the gradient colors slightly for each interaction const hueShift = Math.floor(Math.random() * 20); menuBubble.style.background = `radial-gradient( circle, hsla(${348 + hueShift}, 100%, 80%, 0.25) 0%, hsla(${174 + hueShift}, 72%, 60%, 0.25) 100% )`; } // Toggle content sections function toggleSection(sectionName) { contentSections.forEach(section => { if (section.getAttribute('data-section') === sectionName) { section.classList.add('active'); } else { section.classList.remove('active'); } }); } // Update hero background based on section function updateHeroBackground(sectionName) { let backgroundUrl; switch(sectionName) { case 'mindfulness': backgroundUrl = 'https://images.unsplash.com/photo-1506126613408-eca07ce68773?auto=format&fit=crop&q=80'; heroContent.querySelector('h1').textContent = 'Balanced Living'; heroContent.querySelector('p').textContent = 'Discover a mindful approach to modern lifestyle with our curated content on wellness, nutrition, fitness, and travel.'; break; case 'nutrition': backgroundUrl = 'https://images.unsplash.com/photo-1512621776951-a57141f2eefd?auto=format&fit=crop&q=80'; heroContent.querySelector('h1').textContent = 'Nourish Your Body'; heroContent.querySelector('p').textContent = 'Transform your relationship with food through a balanced, intuitive approach that celebrates whole foods and mindful eating.'; break; case 'fitness': backgroundUrl = 'https://images.unsplash.com/photo-1538805060514-97d9cc17730c?auto=format&fit=crop&q=80'; heroContent.querySelector('h1').textContent = 'Move With Purpose'; heroContent.querySelector('p').textContent = 'Discover functional fitness approaches that enhance your quality of life, focusing on strength, mobility and sustainable progress.'; break; case 'travel': backgroundUrl = 'https://images.unsplash.com/photo-1488085061387-422e29b40080?auto=format&fit=crop&q=80'; heroContent.querySelector('h1').textContent = 'Journey Mindfully'; heroContent.querySelector('p').textContent = 'Experience travel as transformation through authentic cultural immersion, sustainable practices, and soul-nourishing adventures.'; break; } // Apply with a smooth transition hero.style.transition = 'background-image 0.8s ease'; hero.style.backgroundImage = `url('${backgroundUrl}')`; } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Fluid Interface</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; } body { width: 100%; height: 100vh; overflow: hidden; background: #0a0e17; color: #fff; position: relative; } .blob-container { position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 0; filter: blur(40px); } .blob { position: absolute; border-radius: 50%; filter: blur(20px); opacity: 0.7; mix-blend-mode: screen; transform-origin: center; transition: all 0.5s ease; } .content { position: relative; z-index: 2; max-width: 650px; margin: 0 auto; padding: 40px 20px; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; } h1 { font-size: 2.5rem; margin-bottom: 20px; font-weight: 800; line-height: 1.2; background: linear-gradient(to right, #4facfe, #00f2fe); -webkit-background-clip: text; -webkit-text-fill-color: transparent; transition: transform 0.3s ease; } p { font-size: 1.1rem; line-height: 1.6; margin-bottom: 30px; color: rgba(255, 255, 255, 0.8); max-width: 580px; } .btn { background: linear-gradient(45deg, #4facfe, #00f2fe); color: white; border: none; padding: 12px 28px; border-radius: 30px; font-size: 1rem; font-weight: 600; cursor: pointer; transition: all 0.3s ease; position: relative; overflow: hidden; z-index: 1; letter-spacing: 0.5px; box-shadow: 0 4px 15px rgba(79, 172, 254, 0.3); margin-top: 10px; } .btn:hover { transform: translateY(-2px); box-shadow: 0 7px 20px rgba(79, 172, 254, 0.4); } .btn::before { content: ''; position: absolute; top: 0; left: 0; width: 0%; height: 100%; background: linear-gradient(45deg, #00f2fe, #4facfe); transition: all 0.5s ease; z-index: -1; } .btn:hover::before { width: 100%; } .btn:active { transform: translateY(1px); } .feature-list { display: flex; justify-content: center; gap: 25px; margin-top: 40px; flex-wrap: wrap; } .feature { background: rgba(255, 255, 255, 0.05); border-radius: 15px; padding: 20px; width: 180px; backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); transition: all 0.3s ease; cursor: pointer; } .feature:hover { transform: translateY(-5px); background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); } .feature-icon { font-size: 1.5rem; margin-bottom: 10px; color: #4facfe; } .feature-title { font-weight: 600; margin-bottom: 5px; font-size: 1rem; } .feature-desc { font-size: 0.85rem; color: rgba(255, 255, 255, 0.6); line-height: 1.4; margin-bottom: 0; } /* Responsive design */ @media (max-width: 700px) { h1 { font-size: 2rem; } p { font-size: 1rem; } .feature-list { gap: 15px; } .feature { width: calc(50% - 20px); padding: 15px; } } @media (max-width: 480px) { h1 { font-size: 1.8rem; } .content { padding: 30px 15px; } .feature { width: 100%; } } /* Interactive cursor effect */ .cursor-follower { position: fixed; width: 30px; height: 30px; background: rgba(79, 172, 254, 0.3); border-radius: 50%; pointer-events: none; z-index: 10000; transition: transform 0.1s, width 0.3s, height 0.3s, background 0.3s; transform: translate(-50%, -50%); mix-blend-mode: screen; } .cursor-grow { transform: translate(-50%, -50%) scale(2.5); background: rgba(79, 172, 254, 0.15); mix-blend-mode: screen; } </style> </head> <body> <div class="blob-container" id="blobContainer"></div> <div class="content"> <h1>Fluid Interface Experience</h1> <p>Immerse yourself in our dynamic liquid interface where digital elements flow with organic grace. The perfect foundation for products that prioritize calm, intuitive user experiences and natural interactions.</p> <button class="btn">Experience the Flow</button> <div class="feature-list"> <div class="feature"> <div class="feature-icon">✨</div> <div class="feature-title">Fluid Animation</div> <div class="feature-desc">Smooth transitions mimic natural liquid movement patterns</div> </div> <div class="feature"> <div class="feature-icon">🎨</div> <div class="feature-title">Adaptive Colors</div> <div class="feature-desc">Gradients shift subtly with interaction and time</div> </div> <div class="feature"> <div class="feature-icon">⚡</div> <div class="feature-title">Performant</div> <div class="feature-desc">Optimized rendering even on mobile devices</div> </div> </div> </div> <div class="cursor-follower" id="cursorFollower"></div> <script> // Create animated blobs const blobContainer = document.getElementById('blobContainer'); const colors = [ '#4facfe', '#00f2fe', '#3f5efb', '#6a82fb', '#0acffe', '#495aff' ]; // Create blobs function createBlobs(count) { for (let i = 0; i < count; i++) { const blob = document.createElement('div'); blob.classList.add('blob'); // Random properties const size = Math.random() * 300 + 150; const color = colors[Math.floor(Math.random() * colors.length)]; // Position randomly but keep within container const posX = Math.random() * 100; const posY = Math.random() * 100; // Style the blob blob.style.width = `${size}px`; blob.style.height = `${size}px`; blob.style.background = color; blob.style.left = `${posX}%`; blob.style.top = `${posY}%`; // Add to container blobContainer.appendChild(blob); // Start animation animateBlob(blob); } } // Animate each blob function animateBlob(blob) { const speed = Math.random() * 60 + 20; // between 20-80 seconds function move() { // New random position const newPosX = Math.random() * 100; const newPosY = Math.random() * 100; // New random size const newSize = Math.random() * 300 + 150; // Apply new styles blob.style.transition = ` left ${speed}s ease-in-out, top ${speed}s ease-in-out, width ${speed/2}s ease-in-out, height ${speed/2}s ease-in-out `; blob.style.left = `${newPosX}%`; blob.style.top = `${newPosY}%`; blob.style.width = `${newSize}px`; blob.style.height = `${newSize}px`; // Schedule next movement setTimeout(move, speed * 1000); } // Start the movement move(); } // Initialize blobs createBlobs(6); // Interactive cursor effect const cursorFollower = document.getElementById('cursorFollower'); const interactiveElements = document.querySelectorAll('.btn, .feature, h1'); document.addEventListener('mousemove', (e) => { cursorFollower.style.left = `${e.clientX}px`; cursorFollower.style.top = `${e.clientY}px`; }); // Add "grow" effect when hovering over interactive elements interactiveElements.forEach(element => { element.addEventListener('mouseenter', () => { cursorFollower.classList.add('cursor-grow'); }); element.addEventListener('mouseleave', () => { cursorFollower.classList.remove('cursor-grow'); }); }); // Hide cursor on mobile devices if ('ontouchstart' in window) { cursorFollower.style.display = 'none'; } // Button click effect const btn = document.querySelector('.btn'); btn.addEventListener('click', function(e) { // Create ripple effect let ripple = document.createElement('span'); ripple.style.position = 'absolute'; ripple.style.background = 'rgba(255,255,255,0.7)'; ripple.style.borderRadius = '50%'; ripple.style.pointerEvents = 'none'; ripple.style.width = '100px'; ripple.style.height = '100px'; ripple.style.transform = 'translate(-50%, -50%) scale(0)'; ripple.style.animation = 'ripple 1s linear'; // Position the ripple where clicked ripple.style.left = `${e.offsetX}px`; ripple.style.top = `${e.offsetY}px`; // Add ripple to button this.appendChild(ripple); // Define the ripple animation if (!document.querySelector('#rippleStyle')) { const style = document.createElement('style'); style.id = 'rippleStyle'; style.textContent = ` @keyframes ripple { to { transform: translate(-50%, -50%) scale(3); opacity: 0; } } `; document.head.appendChild(style); } // Remove ripple after animation setTimeout(() => { ripple.remove(); }, 1000); // Add subtle pulse to blobs when button is clicked const blobs = document.querySelectorAll('.blob'); blobs.forEach(blob => { blob.style.transform = 'scale(1.1)'; setTimeout(() => { blob.style.transform = 'scale(1)'; }, 500); }); }); </script> </body> </html>
<html> <head> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif; background-color: #f5f8fa; display: flex; justify-content: center; align-items: center; min-height: 100vh; color: #2c3e50; overflow: hidden; } .container { width: 100%; max-width: 600px; padding: 2rem; border-radius: 18px; background-color: #ffffff; box-shadow: 0 8px 30px rgba(0, 78, 146, 0.08); text-align: center; position: relative; z-index: 1; overflow: hidden; } .card-shape { width: 220px; height: 140px; margin: 1.5rem auto; border-radius: 16px; background-color: #f8fafd; position: relative; overflow: hidden; box-shadow: 0 4px 12px rgba(0, 78, 146, 0.05); transition: transform 0.3s ease; } .card-shape:hover { transform: translateY(-5px); } .liquid { position: absolute; bottom: 0; left: 0; width: 100%; height: 0%; background: linear-gradient(to top, #0072CE, #0098E3); border-radius: 0 0 16px 16px; transition: height 0.8s cubic-bezier(0.34, 1.56, 0.64, 1); } .liquid::before { content: ''; position: absolute; top: -10px; left: 0; width: 100%; height: 20px; background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 320'%3E%3Cpath fill='%230098E3' fill-opacity='1' d='M0,224L48,213.3C96,203,192,181,288,176C384,171,480,181,576,192C672,203,768,213,864,202.7C960,192,1056,160,1152,154.7C1248,149,1344,171,1392,181.3L1440,192L1440,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'%3E%3C/path%3E%3C/svg%3E"); background-size: cover; animation: wave 3s linear infinite; } @keyframes wave { 0% { background-position-x: 0; } 100% { background-position-x: 1440px; } } .bubbles { position: absolute; bottom: 0; left: 0; width: 100%; height: 100%; overflow: hidden; pointer-events: none; } .bubble { position: absolute; bottom: -20px; width: 12px; height: 12px; background-color: rgba(255, 255, 255, 0.3); border-radius: 50%; opacity: 0; animation: rise 10s infinite ease-in; } @keyframes rise { 0% { bottom: -20px; transform: translateX(0); opacity: 0.1; } 50% { opacity: 0.4; transform: translateX(10px); } 100% { bottom: 120%; transform: translateX(-20px); opacity: 0; } } h1 { font-size: 1.8rem; color: #0058A3; margin-bottom: 1rem; font-weight: 600; } p { color: #546e7a; line-height: 1.6; margin-bottom: 1.5rem; max-width: 450px; margin-left: auto; margin-right: auto; } .actions { display: flex; gap: 1rem; justify-content: center; margin-top: 2rem; } button { background-color: #0072CE; color: white; border: none; padding: 0.8rem 1.5rem; border-radius: 30px; font-weight: 500; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 10px rgba(0, 114, 206, 0.2); position: relative; overflow: hidden; } button:hover { background-color: #005ea8; transform: translateY(-2px); box-shadow: 0 6px 15px rgba(0, 114, 206, 0.3); } button:active { transform: translateY(1px); } button span { position: relative; z-index: 1; } button.secondary { background-color: #e8f4fc; color: #0072CE; box-shadow: 0 4px 10px rgba(0, 114, 206, 0.1); } button.secondary:hover { background-color: #d5ebfa; } .loading-text { margin-top: 1.5rem; font-size: 1rem; color: #0072CE; font-weight: 500; opacity: 0; transition: opacity 0.3s ease; } .loading-percentage { font-weight: 700; font-size: 1.1rem; } .bank-chip { position: absolute; width: 35px; height: 25px; background: linear-gradient(135deg, #FFD700, #FFC107); border-radius: 4px; top: 20px; left: 20px; } .bank-logo { position: absolute; bottom: 20px; right: 20px; font-size: 12px; font-weight: bold; color: white; } .status-indicator { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background-color: #4CAF50; margin-right: 6px; } .particles { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: -1; pointer-events: none; } .particle { position: absolute; width: 6px; height: 6px; background-color: rgba(0, 114, 206, 0.1); border-radius: 50%; } .processing-info { display: flex; justify-content: space-between; margin-top: 1rem; font-size: 0.8rem; color: #78909c; padding: 0 1rem; opacity: 0; transition: opacity 0.5s ease; } .quick-tip { background-color: #f0f7fc; border-left: 3px solid #0072CE; padding: 1rem; border-radius: 0 8px 8px 0; margin-top: 1.5rem; text-align: left; font-size: 0.9rem; display: none; } .quick-tip h4 { color: #0072CE; margin-bottom: 0.5rem; } @media (max-width: 480px) { .container { padding: 1.5rem; } h1 { font-size: 1.5rem; } .actions { flex-direction: column; } button { width: 100%; } } </style> </head> <body> <div class="particles"></div> <div class="container"> <h1>Verifying Your Credentials</h1> <p>Our secure system is preparing your banking environment. This extra security layer helps protect your financial data.</p> <div class="card-shape"> <div class="bank-chip"></div> <div class="bank-logo">SECUREBANK</div> <div class="liquid"> <div class="bubbles"></div> </div> </div> <div class="loading-text"> Encrypting connection <span class="status-indicator"></span> <span class="loading-percentage">0%</span> </div> <div class="processing-info"> <span>Secure Channel</span> <span>128-bit Encryption</span> <span>PCI DSS Compliant</span> </div> <div class="quick-tip"> <h4>Quick Tip:</h4> <p>For maximum security, we suggest updating your password every 90 days with a combination of letters, numbers, and special characters.</p> </div> <div class="actions"> <button id="startBtn"><span>Secure Login</span></button> <button class="secondary" id="resetBtn"><span>Reset</span></button> </div> </div> <script> document.addEventListener('DOMContentLoaded', function() { const liquid = document.querySelector('.liquid'); const loadingText = document.querySelector('.loading-text'); const loadingPercentage = document.querySelector('.loading-percentage'); const processingInfo = document.querySelector('.processing-info'); const quickTip = document.querySelector('.quick-tip'); const startBtn = document.getElementById('startBtn'); const resetBtn = document.getElementById('resetBtn'); // Create particles const particles = document.querySelector('.particles'); for (let i = 0; i < 30; i++) { createParticle(); } // Create bubbles const bubblesContainer = document.querySelector('.bubbles'); for (let i = 0; i < 15; i++) { createBubble(); } function createParticle() { const particle = document.createElement('div'); particle.classList.add('particle'); const size = Math.random() * 8 + 3; particle.style.width = `${size}px`; particle.style.height = `${size}px`; particle.style.left = `${Math.random() * 100}%`; particle.style.top = `${Math.random() * 100}%`; particle.style.opacity = Math.random() * 0.5 + 0.1; particles.appendChild(particle); // Animate the particle animateParticle(particle); } function animateParticle(particle) { const duration = Math.random() * 20000 + 10000; // 10-30 seconds const xMovement = Math.random() * 100 - 50; const yMovement = Math.random() * 100 - 50; particle.animate([ { transform: 'translate(0, 0)' }, { transform: `translate(${xMovement}px, ${yMovement}px)` } ], { duration: duration, iterations: Infinity, direction: 'alternate', easing: 'ease-in-out' }); } function createBubble() { const bubble = document.createElement('div'); bubble.classList.add('bubble'); // Random position bubble.style.left = `${Math.random() * 100}%`; // Random size const size = Math.random() * 8 + 4; bubble.style.width = `${size}px`; bubble.style.height = `${size}px`; // Random delay const delay = Math.random() * 5; bubble.style.animationDelay = `${delay}s`; // Random duration const duration = Math.random() * 7 + 3; bubble.style.animationDuration = `${duration}s`; bubblesContainer.appendChild(bubble); } let isLoading = false; let progress = 0; let loadingInterval; startBtn.addEventListener('click', function() { if (isLoading) return; isLoading = true; progress = 0; loadingText.style.opacity = 1; processingInfo.style.opacity = 1; loadingInterval = setInterval(function() { progress += Math.random() * 3 + 1; if (progress >= 100) { progress = 100; clearInterval(loadingInterval); setTimeout(function() { quickTip.style.display = 'block'; loadingText.textContent = 'Verification complete! Ready for secure banking.'; }, 1000); } updateProgress(progress); }, 120); startBtn.disabled = true; startBtn.style.opacity = 0.7; startBtn.textContent = 'Processing...'; }); resetBtn.addEventListener('click', function() { if (!isLoading) return; clearInterval(loadingInterval); progress = 0; updateProgress(progress); isLoading = false; loadingText.style.opacity = 0; processingInfo.style.opacity = 0; quickTip.style.display = 'none'; startBtn.disabled = false; startBtn.style.opacity = 1; startBtn.innerHTML = '<span>Secure Login</span>'; loadingText.innerHTML = 'Encrypting connection <span class="status-indicator"></span> <span class="loading-percentage">0%</span>'; }); function updateProgress(value) { const percentage = Math.min(Math.floor(value), 100); loadingPercentage.textContent = `${percentage}%`; liquid.style.height = `${percentage}%`; // Change loading text at different stages if (percentage < 30) { loadingText.innerHTML = 'Establishing secure connection <span class="status-indicator"></span> <span class="loading-percentage">' + percentage + '%</span>'; } else if (percentage < 60) { loadingText.innerHTML = 'Verifying digital signature <span class="status-indicator"></span> <span class="loading-percentage">' + percentage + '%</span>'; } else if (percentage < 90) { loadingText.innerHTML = 'Preparing account information <span class="status-indicator"></span> <span class="loading-percentage">' + percentage + '%</span>'; } else { loadingText.innerHTML = 'Finalizing secure session <span class="status-indicator"></span> <span class="loading-percentage">' + percentage + '%</span>'; } // Add more bubbles as the liquid rises if (percentage > 40 && percentage < 90 && Math.random() > 0.8) { createBubble(); } } }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>NeofluxGames</title> <style> :root { --primary: #0cffdc; --secondary: #ff00ff; --tertiary: #4200ff; --background: #050714; --surface: rgba(16, 20, 39, 0.7); --text: #ffffff; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Rajdhani', 'Orbitron', sans-serif; color: var(--text); } body { background-color: var(--background); height: 100vh; overflow-x: hidden; position: relative; } .liquid-background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 0; overflow: hidden; } .liquid-blob { position: absolute; border-radius: 50%; filter: blur(40px); opacity: 0.3; background: var(--tertiary); transform: translate(-50%, -50%); transition: all 1s cubic-bezier(0.23, 1, 0.32, 1); } .container { max-width: 700px; height: 700px; margin: 0 auto; position: relative; z-index: 1; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--primary) var(--background); padding: 20px; } .container::-webkit-scrollbar { width: 5px; } .container::-webkit-scrollbar-track { background: transparent; } .container::-webkit-scrollbar-thumb { background-color: var(--primary); border-radius: 10px; } header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; padding-bottom: 15px; border-bottom: 1px solid rgba(12, 255, 220, 0.3); position: relative; } .logo { font-size: 1.8rem; font-weight: bold; background: linear-gradient(to right, var(--primary), var(--secondary)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-shadow: 0 0 10px rgba(12, 255, 220, 0.5); position: relative; } .logo::after { content: ''; position: absolute; height: 2px; width: 0; bottom: 0; left: 0; background: linear-gradient(to right, var(--primary), var(--secondary)); transition: width 0.3s ease; } .logo:hover::after { width: 100%; } nav ul { display: flex; list-style: none; gap: 20px; } nav li { position: relative; cursor: pointer; } nav li::before { content: ''; position: absolute; width: 0; height: 1px; bottom: -4px; left: 0; background-color: var(--primary); transition: width 0.3s ease; } nav li:hover::before { width: 100%; } .hero { display: flex; flex-direction: column; align-items: center; justify-content: center; margin-bottom: 40px; position: relative; overflow: hidden; border-radius: 15px; background: rgba(16, 20, 39, 0.4); backdrop-filter: blur(10px); padding: 30px; box-shadow: 0 8px 32px rgba(12, 255, 220, 0.1); border: 1px solid rgba(12, 255, 220, 0.2); } .hero h1 { font-size: 2.5rem; text-align: center; margin-bottom: 20px; line-height: 1.2; position: relative; } .hero h1 span { color: var(--primary); position: relative; display: inline-block; } .hero h1 span::after { content: ''; position: absolute; width: 100%; height: 5px; bottom: -5px; left: 0; background: linear-gradient(90deg, transparent, var(--primary), transparent); animation: pulse 2s infinite; } @keyframes pulse { 0%, 100% { opacity: 0.2; } 50% { opacity: 1; } } .hero p { text-align: center; margin-bottom: 25px; font-size: 1.1rem; line-height: 1.6; max-width: 85%; } .cta-button { padding: 12px 30px; border: none; border-radius: 30px; background: linear-gradient(45deg, var(--primary), var(--tertiary)); color: var(--text); font-weight: bold; cursor: pointer; position: relative; overflow: hidden; z-index: 1; font-size: 1rem; letter-spacing: 1px; transition: all 0.3s ease; box-shadow: 0 0 15px rgba(12, 255, 220, 0.5); } .cta-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(45deg, var(--tertiary), var(--secondary)); transition: all 0.6s ease; z-index: -1; } .cta-button:hover::before { left: 0; } .cta-button:hover { transform: translateY(-3px); box-shadow: 0 0 20px rgba(12, 255, 220, 0.7); } .featured-games { margin-bottom: 40px; } .section-title { font-size: 1.5rem; margin-bottom: 20px; padding-bottom: 10px; border-bottom: 1px solid rgba(12, 255, 220, 0.3); display: flex; align-items: center; position: relative; } .section-title::before { content: ''; width: 5px; height: 20px; background: var(--primary); margin-right: 10px; border-radius: 3px; box-shadow: 0 0 10px var(--primary); } .games-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 20px; } .game-card { background: var(--surface); border-radius: 15px; overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; position: relative; height: 250px; cursor: pointer; border: 1px solid rgba(12, 255, 220, 0.2); } .game-card:hover { transform: translateY(-10px); box-shadow: 0 10px 25px rgba(12, 255, 220, 0.3); } .game-img { width: 100%; height: 60%; object-fit: cover; transition: transform 0.5s ease; } .game-card:hover .game-img { transform: scale(1.05); } .game-info { padding: 15px; position: relative; } .game-title { font-size: 1rem; margin-bottom: 5px; } .game-genre { font-size: 0.8rem; opacity: 0.7; margin-bottom: 8px; } .game-rating { display: flex; align-items: center; } .stars { display: flex; } .star { color: var(--primary); font-size: 0.9rem; margin-right: 2px; } .news-section { margin-bottom: 40px; } .news-item { background: var(--surface); border-radius: 15px; padding: 20px; margin-bottom: 20px; transition: transform 0.3s ease, box-shadow 0.3s ease; border: 1px solid rgba(12, 255, 220, 0.2); position: relative; overflow: hidden; } .news-item::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: linear-gradient(to bottom, var(--primary), var(--tertiary)); } .news-item:hover { transform: translateX(5px); box-shadow: 0 5px 15px rgba(12, 255, 220, 0.2); } .news-date { font-size: 0.8rem; opacity: 0.7; margin-bottom: 10px; } .news-title { font-size: 1.2rem; margin-bottom: 10px; } .news-excerpt { font-size: 0.9rem; line-height: 1.5; } .glitch-effect { position: relative; display: inline-block; } .glitch-effect::before, .glitch-effect::after { content: attr(data-text); position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: var(--background); } .glitch-effect::before { color: #0ff; z-index: -1; } .glitch-effect::after { color: #f0f; z-index: -2; } .glitch-effect:hover::before { animation: glitch-anim-1 0.4s infinite linear alternate-reverse; } .glitch-effect:hover::after { animation: glitch-anim-2 0.4s infinite linear alternate-reverse; } @keyframes glitch-anim-1 { 0% { clip-path: inset(20% 0 80% 0); transform: translate(-2px, -2px); } 20% { clip-path: inset(60% 0 40% 0); transform: translate(2px, 2px); } 40% { clip-path: inset(40% 0 60% 0); transform: translate(-2px, 2px); } 60% { clip-path: inset(80% 0 20% 0); transform: translate(2px, -2px); } 80% { clip-path: inset(10% 0 90% 0); transform: translate(2px, 2px); } 100% { clip-path: inset(70% 0 30% 0); transform: translate(-2px, -2px); } } @keyframes glitch-anim-2 { 0% { clip-path: inset(30% 0 70% 0); transform: translate(2px, -2px); } 20% { clip-path: inset(50% 0 50% 0); transform: translate(-2px, 2px); } 40% { clip-path: inset(70% 0 30% 0); transform: translate(2px, 2px); } 60% { clip-path: inset(10% 0 90% 0); transform: translate(2px, -2px); } 80% { clip-path: inset(90% 0 10% 0); transform: translate(-2px, 2px); } 100% { clip-path: inset(20% 0 80% 0); transform: translate(-2px, -2px); } } .particle { position: absolute; border-radius: 50%; background: var(--primary); pointer-events: none; opacity: 0; } /* Liquid loading indicator */ .liquid-loader { position: fixed; bottom: 20px; right: 20px; width: 60px; height: 60px; background: rgba(16, 20, 39, 0.7); border-radius: 50%; display: flex; align-items: center; justify-content: center; z-index: 100; backdrop-filter: blur(5px); border: 1px solid rgba(12, 255, 220, 0.3); cursor: pointer; box-shadow: 0 0 15px rgba(12, 255, 220, 0.3); transition: transform 0.3s ease; } .liquid-loader:hover { transform: scale(1.1); } .liquid-loader::before { content: ''; position: absolute; width: 40px; height: 40px; background: linear-gradient(var(--primary), var(--tertiary)); border-radius: 40%; animation: rotate 4s linear infinite; } .liquid-loader::after { content: ''; position: absolute; width: 35px; height: 35px; background: var(--background); border-radius: 50%; } @keyframes rotate { 0% { transform: rotate(0deg); border-radius: 40%; } 50% { border-radius: 60%; } 100% { transform: rotate(360deg); border-radius: 40%; } } /* Responsive styles */ @media (max-width: 600px) { .games-grid { grid-template-columns: repeat(2, 1fr); } .hero h1 { font-size: 2rem; } nav ul { gap: 10px; } .logo { font-size: 1.5rem; } } @media (max-width: 400px) { .games-grid { grid-template-columns: 1fr; } .hero h1 { font-size: 1.8rem; } .hero p { font-size: 1rem; } } </style> </head> <body> <div class="liquid-background"></div> <div class="container"> <header> <div class="logo">NEOFLUX</div> <nav> <ul> <li>Discover</li> <li>Library</li> <li>Events</li> <li>Profile</li> </ul> </nav> </header> <div class="hero"> <h1>Experience Gaming in <span class="glitch-effect" data-text="LIQUID MOTION">LIQUID MOTION</span></h1> <p>Dive into our reactive interface where games, content, and controls flow intuitively with your every interaction. Explore a curated universe of next-gen titles that redefine immersion.</p> <button class="cta-button">INITIATE SESSION</button> </div> <section class="featured-games"> <h2 class="section-title">TRENDING FLUX</h2> <div class="games-grid"> <div class="game-card"> <img src="https://images.unsplash.com/photo-1542751371-adc38448a05e?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80" alt="Quantum Drift" class="game-img"> <div class="game-info"> <h3 class="game-title">Quantum Drift</h3> <p class="game-genre">Hyper Racing • Neural Link</p> <div class="game-rating"> <div class="stars"> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">☆</span> </div> </div> </div> </div> <div class="game-card"> <img src="https://images.unsplash.com/photo-1511512578047-dfb367046420?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80" alt="NeoTokyo Descent" class="game-img"> <div class="game-info"> <h3 class="game-title">NeoTokyo Descent</h3> <p class="game-genre">Cyberpunk RPG • Open World</p> <div class="game-rating"> <div class="stars"> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> </div> </div> </div> </div> <div class="game-card"> <img src="https://images.unsplash.com/photo-1550745165-9bc0b252726f?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&q=80" alt="Ethereal Echoes" class="game-img"> <div class="game-info"> <h3 class="game-title">Ethereal Echoes</h3> <p class="game-genre">Psychedelic Puzzle • Synesthetic</p> <div class="game-rating"> <div class="stars"> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">★</span> <span class="star">☆</span> </div> </div> </div> </div> </div> </section> <section class="news-section"> <h2 class="section-title">NEURAL FEED</h2> <div class="news-item"> <p class="news-date">NEURAL TIMESTAMP: 12.04.2142</p> <h3 class="news-title">Synaptic Controllers Now Support Emotional Feedback</h3> <p class="news-excerpt">The latest firmware update to NeoSense controllers allows games to react to your emotional state. Calibrate your neural link in settings for personalized response patterns.</p> </div> <div class="news-item"> <p class="news-date">NEURAL TIMESTAMP: 11.28.2142</p> <h3 class="news-title">Global Tournament: Quantum Drift Championship Qualifiers</h3> <p class="news-excerpt">Registration now open for the QDC. New biometric tracking features will monitor player pulse and brainwave patterns during high-velocity race segments.</p> </div> </section> <div class="liquid-loader" id="liquid-loader"></div> </div> <script> document.addEventListener('DOMContentLoaded', function() { // Create liquid background const liquidBackground = document.querySelector('.liquid-background'); const colors = ['#0cffdc', '#ff00ff', '#4200ff']; for (let i = 0; i < 5; i++) { const blob = document.createElement('div'); blob.classList.add('liquid-blob'); const size = Math.random() * 300 + 200; const color = colors[Math.floor(Math.random() * colors.length)]; blob.style.width = `${size}px`; blob.style.height = `${size}px`; blob.style.left = `${Math.random() * 100}%`; blob.style.top = `${Math.random() * 100}%`; blob.style.background = color; liquidBackground.appendChild(blob); } // Animate blobs function animateBlobs() { const blobs = document.querySelectorAll('.liquid-blob'); blobs.forEach(blob => { const newX = Math.random() * 100; const newY = Math.random() * 100; blob.style.left = `${newX}%`; blob.style.top = `${newY}%`; }); } // Initial animation animateBlobs(); // Continue animation setInterval(animateBlobs, 5000); // Add particle effect on mouse move const container = document.querySelector('.container'); container.addEventListener('mousemove', function(e) { const particle = document.createElement('div'); particle.classList.add('particle'); // Position the particle at the mouse position const rect = container.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; particle.style.left = `${x}px`; particle.style.top = `${y}px`; // Random size and color const size = Math.random() * 6 + 2; particle.style.width = `${size}px`; particle.style.height = `${size}px`; const particleColors = ['#0cffdc', '#ff00ff', '#4200ff']; particle.style.background = particleColors[Math.floor(Math.random() * particleColors.length)]; container.appendChild(particle); // Animate the particle setTimeout(() => { particle.style.opacity = '0.7'; const angle = Math.random() * Math.PI * 2; const velocity = Math.random() * 30 + 20; const tx = Math.cos(angle) * velocity; const ty = Math.sin(angle) * velocity; particle.style.transform = `translate(${tx}px, ${ty}px)`; setTimeout(() => { particle.remove(); }, 500); }, 10); }); // Interactive elements const ctaButton = document.querySelector('.cta-button'); ctaButton.addEventListener('click', function() { this.textContent = 'SESSION INITIATED'; // Create a ripple effect const ripple = document.createElement('div'); ripple.style.position = 'absolute'; ripple.style.width = '10px'; ripple.style.height = '10px'; ripple.style.background = 'rgba(255, 255, 255, 0.5)'; ripple.style.borderRadius = '50%'; ripple.style.transform = 'translate(-50%, -50%)'; ripple.style.animation = 'ripple 1s linear'; this.appendChild(ripple); setTimeout(() => { ripple.remove(); }, 1000); }); // Game cards hover effect const gameCards = document.querySelectorAll('.game-card'); gameCards.forEach(card => { card.addEventListener('mouseenter', function() { // Create a highlight effect around the card this.style.boxShadow = '0 0 20px rgba(12, 255, 220, 0.7)'; }); card.addEventListener('mouseleave', function() { this.style.boxShadow = 'none'; }); }); // Liquid loader animation const liquidLoader = document.getElementById('liquid-loader'); liquidLoader.addEventListener('click', function() { this.style.transform = 'scale(1.2)'; setTimeout(() => { this.style.transform = 'scale(1)'; }, 300); }); // Make all sections react to scroll const sections = document.querySelectorAll('section'); function isInViewport(element) { const rect = element.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); } function checkSections() { sections.forEach(section => { if (isInViewport(section)) { section.style.transform = 'translateY(0)'; section.style.opacity = '1'; } }); } // Initial section visibility sections.forEach(section => { section.style.transform = 'translateY(20px)'; section.style.opacity = '0'; section.style.transition = 'transform 0.5s ease, opacity 0.5s ease'; }); // Check sections on scroll container.addEventListener('scroll', checkSections); // Initial check checkSections(); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary-color: #2389da; --secondary-color: #64c4ff; --tertiary-color: #a0e4ff; --background-color: #f5f9fd; --text-color: #20324b; --accent-color: #1a73e8; --light-color: #eaf6ff; --dark-color: #0a2d4d; --success-color: #36b37e; --warning-color: #ffab00; --error-color: #ff5630; } * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { background-color: var(--background-color); color: var(--text-color); height: 700px; width: 700px; max-width: 100%; overflow-x: hidden; position: relative; } .dashboard { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: auto auto 1fr 1fr; gap: 16px; padding: 24px; height: 100%; width: 100%; max-width: 700px; overflow: hidden; } header { grid-column: 1 / span 4; display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; } .title h1 { font-size: 24px; font-weight: 600; color: var(--dark-color); margin-bottom: 4px; } .title p { font-size: 14px; color: var(--text-color); opacity: 0.7; } .controls { display: flex; gap: 12px; } button { background-color: var(--primary-color); color: white; border: none; border-radius: 6px; padding: 8px 16px; font-size: 14px; cursor: pointer; transition: all 0.3s ease; display: flex; align-items: center; gap: 8px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } button:hover { background-color: var(--accent-color); } button:active { transform: translateY(1px); } .button-icon { display: inline-flex; } .time-selector { grid-column: 1 / span 4; background-color: white; border-radius: 10px; padding: 16px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; position: relative; overflow: hidden; } .time-selector-buttons { display: flex; gap: 8px; } .time-button { background-color: var(--light-color); color: var(--dark-color); padding: 6px 12px; border-radius: 20px; font-size: 14px; cursor: pointer; transition: all 0.2s ease; } .time-button.active { background-color: var(--primary-color); color: white; } .time-button:hover:not(.active) { background-color: var(--tertiary-color); } .chart-card { background-color: white; border-radius: 10px; padding: 20px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); display: flex; flex-direction: column; position: relative; overflow: hidden; } .main-chart { grid-column: 1 / span 4; grid-row: 3 / span 1; } .stat-card { grid-column: span 1; grid-row: 4 / span 1; background-color: white; border-radius: 10px; padding: 16px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); display: flex; flex-direction: column; justify-content: space-between; position: relative; overflow: hidden; } .card-title { font-size: 16px; font-weight: 500; color: var(--text-color); margin-bottom: 16px; display: flex; justify-content: space-between; align-items: center; } .card-title .info-icon { cursor: pointer; opacity: 0.5; transition: opacity 0.2s ease; } .card-title .info-icon:hover { opacity: 1; } .chart-container { flex-grow: 1; position: relative; } .stat-value { font-size: 28px; font-weight: 600; color: var(--dark-color); margin-bottom: 4px; } .stat-change { font-size: 14px; display: flex; align-items: center; gap: 4px; } .positive { color: var(--success-color); } .negative { color: var(--error-color); } .wave-container { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 2; overflow: hidden; opacity: 0; transition: opacity 0.3s ease; } .wave { position: absolute; width: 200%; height: 200%; top: -50%; left: -50%; border-radius: 40%; background: rgba(160, 228, 255, 0.3); animation: wave 3.5s linear infinite; transform-origin: 50% 48%; z-index: 1; } .wave2 { position: absolute; width: 200%; height: 200%; top: -50%; left: -50%; border-radius: 40%; background: rgba(100, 196, 255, 0.2); animation: wave 3.5s linear infinite; animation-delay: 0.2s; transform-origin: 49% 51%; z-index: 2; } .wave3 { position: absolute; width: 200%; height: 200%; top: -50%; left: -50%; border-radius: 43%; background: rgba(35, 137, 218, 0.1); animation: wave 3.5s linear infinite; animation-delay: 0.4s; transform-origin: 51% 49%; z-index: 3; } @keyframes wave { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .skeleton { background: linear-gradient( 90deg, rgba(226, 236, 245, 0.6) 25%, rgba(240, 246, 252, 0.6) 37%, rgba(226, 236, 245, 0.6) 63% ); background-size: 400% 100%; animation: skeleton-loading 1.4s ease infinite; border-radius: 4px; } @keyframes skeleton-loading { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } } .tooltip { position: absolute; background-color: rgba(10, 45, 77, 0.9); color: white; padding: 8px 12px; border-radius: 4px; font-size: 12px; pointer-events: none; z-index: 10; opacity: 0; transition: opacity 0.2s; max-width: 200px; box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); } /* Mobile responsiveness */ @media (max-width: 700px) { .dashboard { grid-template-columns: 1fr 1fr; padding: 16px; } header { grid-column: 1 / span 2; flex-direction: column; align-items: flex-start; gap: 12px; } .time-selector { grid-column: 1 / span 2; flex-direction: column; align-items: flex-start; gap: 12px; } .time-selector-buttons { flex-wrap: wrap; } .main-chart { grid-column: 1 / span 2; } .stat-card { grid-column: span 1; } } @media (max-width: 480px) { .dashboard { grid-template-columns: 1fr; padding: 12px; } header { grid-column: 1; } .time-selector { grid-column: 1; } .main-chart { grid-column: 1; } .stat-card { grid-column: 1; } } </style> </head> <body> <div class="dashboard"> <header> <div class="title"> <h1>FluidDataViz</h1> <p>Interactive statistics with fluid wave refreshes</p> </div> <div class="controls"> <button id="refreshBtn" title="Refresh data with animation"> <span class="button-icon"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"/></svg> </span> Refresh Data </button> </div> </header> <div class="time-selector"> <div class="card-title">Time Period</div> <div class="time-selector-buttons"> <div class="time-button" data-period="day">Day</div> <div class="time-button active" data-period="week">Week</div> <div class="time-button" data-period="month">Month</div> <div class="time-button" data-period="quarter">Quarter</div> <div class="time-button" data-period="year">Year</div> </div> <div class="wave-container" id="timeWaveContainer"> <div class="wave"></div> <div class="wave2"></div> <div class="wave3"></div> </div> </div> <div class="chart-card main-chart"> <div class="card-title"> <span>User Engagement Trends</span> <span class="info-icon" data-tooltip="Shows the pattern of user interactions over time, including page views, active sessions, and conversion rates."> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <path d="M12 16v-4"></path> <path d="M12 8h.01"></path> </svg> </span> </div> <div class="chart-container" id="mainChart"></div> <div class="wave-container" id="mainChartWaveContainer"> <div class="wave"></div> <div class="wave2"></div> <div class="wave3"></div> </div> </div> <div class="stat-card"> <div class="card-title"> <span>Active Users</span> <span class="info-icon" data-tooltip="Total number of unique users who have engaged with the platform."> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <path d="M12 16v-4"></path> <path d="M12 8h.01"></path> </svg> </span> </div> <div class="stat-value" id="activeUsers">8,742</div> <div class="stat-change positive"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="18 15 12 9 6 15"></polyline> </svg> <span id="activeUsersChange">12.8%</span> </div> <div class="chart-container" id="activeUsersChart"></div> <div class="wave-container" id="activeUsersWaveContainer"> <div class="wave"></div> <div class="wave2"></div> <div class="wave3"></div> </div> </div> <div class="stat-card"> <div class="card-title"> <span>Avg. Session Time</span> <span class="info-icon" data-tooltip="Average duration users spend actively engaged per session."> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <path d="M12 16v-4"></path> <path d="M12 8h.01"></path> </svg> </span> </div> <div class="stat-value" id="sessionTime">4:32</div> <div class="stat-change positive"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="18 15 12 9 6 15"></polyline> </svg> <span id="sessionTimeChange">6.3%</span> </div> <div class="chart-container" id="sessionTimeChart"></div> <div class="wave-container" id="sessionTimeWaveContainer"> <div class="wave"></div> <div class="wave2"></div> <div class="wave3"></div> </div> </div> <div class="stat-card"> <div class="card-title"> <span>Conversion Rate</span> <span class="info-icon" data-tooltip="Percentage of visitors who complete a desired action."> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <path d="M12 16v-4"></path> <path d="M12 8h.01"></path> </svg> </span> </div> <div class="stat-value" id="conversionRate">3.8%</div> <div class="stat-change positive"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="18 15 12 9 6 15"></polyline> </svg> <span id="conversionRateChange">2.1%</span> </div> <div class="chart-container" id="conversionRateChart"></div> <div class="wave-container" id="conversionRateWaveContainer"> <div class="wave"></div> <div class="wave2"></div> <div class="wave3"></div> </div> </div> <div class="stat-card"> <div class="card-title"> <span>Bounce Rate</span> <span class="info-icon" data-tooltip="Percentage of visitors who navigate away after viewing only one page."> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <circle cx="12" cy="12" r="10"></circle> <path d="M12 16v-4"></path> <path d="M12 8h.01"></path> </svg> </span> </div> <div class="stat-value" id="bounceRate">28.7%</div> <div class="stat-change negative"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <polyline points="6 9 12 15 18 9"></polyline> </svg> <span id="bounceRateChange">1.4%</span> </div> <div class="chart-container" id="bounceRateChart"></div> <div class="wave-container" id="bounceRateWaveContainer"> <div class="wave"></div> <div class="wave2"></div> <div class="wave3"></div> </div> </div> </div> <div class="tooltip" id="tooltip"></div> <script> document.addEventListener('DOMContentLoaded', function() { // Chart data const chartData = { day: generateRandomData(24), week: generateRandomData(7), month: generateRandomData(30), quarter: generateRandomData(90), year: generateRandomData(12) }; let currentPeriod = 'week'; let isRefreshing = false; // Initialize charts initializeCharts(); // Event listeners document.getElementById('refreshBtn').addEventListener('click', refreshAllData); document.querySelectorAll('.time-button').forEach(button => { button.addEventListener('click', function() { const period = this.getAttribute('data-period'); if (period !== currentPeriod) { document.querySelector('.time-button.active').classList.remove('active'); this.classList.add('active'); currentPeriod = period; triggerWaveAnimation('timeWaveContainer'); setTimeout(() => updateCharts(period), 1000); } }); }); // Info icon tooltips document.querySelectorAll('.info-icon').forEach(icon => { icon.addEventListener('mouseenter', function(e) { const tooltip = document.getElementById('tooltip'); tooltip.textContent = this.getAttribute('data-tooltip'); // Position the tooltip const rect = this.getBoundingClientRect(); tooltip.style.top = `${rect.bottom + 10}px`; tooltip.style.left = `${rect.left - 100 + rect.width / 2}px`; tooltip.style.opacity = '1'; }); icon.addEventListener('mouseleave', function() { document.getElementById('tooltip').style.opacity = '0'; }); }); // Initialize all chart elements function initializeCharts() { createMainChart(chartData[currentPeriod]); createMiniChart('activeUsersChart', generateRandomData(10), '#64c4ff'); createMiniChart('sessionTimeChart', generateRandomData(10), '#36b37e'); createMiniChart('conversionRateChart', generateRandomData(10), '#2389da'); createMiniChart('bounceRateChart', generateRandomData(10), '#ff5630'); } // Main chart creation function createMainChart(data) { const chart = document.getElementById('mainChart'); chart.innerHTML = ''; const maxValue = Math.max(...data); const chartHeight = chart.clientHeight - 30; const barWidth = chart.clientWidth / data.length; // Create SVG element const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); svg.style.overflow = 'visible'; // Create background grid lines for (let i = 0; i <= 4; i++) { const yPos = chartHeight - (chartHeight * (i / 4)); const line = document.createElementNS('http://www.w3.org/2000/svg', 'line'); line.setAttribute('x1', '0'); line.setAttribute('y1', yPos); line.setAttribute('x2', '100%'); line.setAttribute('y2', yPos); line.setAttribute('stroke', '#e0e0e0'); line.setAttribute('stroke-width', '1'); line.setAttribute('stroke-dasharray', '3,3'); svg.appendChild(line); const text = document.createElementNS('http://www.w3.org/2000/svg', 'text'); text.setAttribute('x', '-5'); text.setAttribute('y', yPos + 4); text.setAttribute('text-anchor', 'end'); text.setAttribute('font-size', '10'); text.setAttribute('fill', '#999'); text.textContent = Math.round(maxValue * (i / 4)); svg.appendChild(text); } // Create gradient for bars const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs'); const gradient = document.createElementNS('http://www.w3.org/2000/svg', 'linearGradient'); gradient.setAttribute('id', 'barGradient'); gradient.setAttribute('x1', '0%'); gradient.setAttribute('y1', '0%'); gradient.setAttribute('x2', '0%'); gradient.setAttribute('y2', '100%'); const stop1 = document.createElementNS('http://www.w3.org/2000/svg', 'stop'); stop1.setAttribute('offset', '0%'); stop1.setAttribute('stop-color', '#2389da'); const stop2 = document.createElementNS('http://www.w3.org/2000/svg', 'stop'); stop2.setAttribute('offset', '100%'); stop2.setAttribute('stop-color', '#64c4ff'); gradient.appendChild(stop1); gradient.appendChild(stop2); defs.appendChild(gradient); svg.appendChild(defs); // Create line path let pathData = ''; data.forEach((value, index) => { const x = index * barWidth + barWidth / 2; const y = chartHeight - (value / maxValue * chartHeight); if (index === 0) { pathData += `M ${x} ${y}`; } else { pathData += ` L ${x} ${y}`; } }); // Add line const path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); path.setAttribute('d', pathData); path.setAttribute('fill', 'none'); path.setAttribute('stroke', '#2389da'); path.setAttribute('stroke-width', '2'); path.setAttribute('stroke-linecap', 'round'); path.setAttribute('stroke-linejoin', 'round'); svg.appendChild(path); // Add area fill const areaPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); areaPath.setAttribute('d', `${pathData} L ${data.length * barWidth - barWidth / 2} ${chartHeight} L ${barWidth / 2} ${chartHeight} Z`); areaPath.setAttribute('fill', 'url(#barGradient)'); areaPath.setAttribute('fill-opacity', '0.3'); svg.appendChild(areaPath); // Add data points data.forEach((value, index) => { const x = index * barWidth + barWidth / 2; const y = chartHeight - (value / maxValue * chartHeight); const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); circle.setAttribute('cx', x); circle.setAttribute('cy', y); circle.setAttribute('r', '4'); circle.setAttribute('fill', '#ffffff'); circle.setAttribute('stroke', '#2389da'); circle.setAttribute('stroke-width', '2'); // Add interaction for points circle.addEventListener('mouseenter', function(e) { this.setAttribute('r', '6'); const tooltip = document.getElementById('tooltip'); tooltip.textContent = `Value: ${value}`; const rect = chart.getBoundingClientRect(); tooltip.style.top = `${rect.top + y - 30}px`; tooltip.style.left = `${rect.left + x}px`; tooltip.style.opacity = '1'; }); circle.addEventListener('mouseleave', function() { this.setAttribute('r', '4'); document.getElementById('tooltip').style.opacity = '0'; }); svg.appendChild(circle); }); chart.appendChild(svg); } // Mini charts for stat cards function createMiniChart(id, data, color) { const chart = document.getElementById(id); chart.innerHTML = ''; const maxValue = Math.max(...data); const chartHeight = chart.clientHeight; const chartWidth = chart.clientWidth; const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); svg.setAttribute('width', '100%'); svg.setAttribute('height', '100%'); // Create sparkline path let pathData = ''; data.forEach((value, index) => { const x = (index / (data.length - 1)) * chartWidth; const y = chartHeight - (value / maxValue * chartHeight * 0.8) - (chartHeight * 0.1); if (index === 0) { pathData += `M ${x} ${y}`; } else { pathData += ` L ${x} ${y}`; } }); // Create area fill const areaPath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); areaPath.setAttribute('d', `${pathData} L ${chartWidth} ${chartHeight} L 0 ${chartHeight} Z`); areaPath.setAttribute('fill', color); areaPath.setAttribute('fill-opacity', '0.2'); svg.appendChild(areaPath); // Create line const linePath = document.createElementNS('http://www.w3.org/2000/svg', 'path'); linePath.setAttribute('d', pathData); linePath.setAttribute('fill', 'none'); linePath.setAttribute('stroke', color); linePath.setAttribute('stroke-width', '2'); linePath.setAttribute('stroke-linecap', 'round'); linePath.setAttribute('stroke-linejoin', 'round'); svg.appendChild(linePath); chart.appendChild(svg); } // Wave animation trigger function triggerWaveAnimation(containerId) { const container = document.getElementById(containerId); container.style.opacity = '1'; setTimeout(() => { container.style.opacity = '0'; }, 2500); } // Update charts with new period data function updateCharts(period) { createMainChart(chartData[period]); // Update mini charts updateMiniChart('activeUsersChart', generateRandomData(10), '#64c4ff'); updateMiniChart('sessionTimeChart', generateRandomData(10), '#36b37e'); updateMiniChart('conversionRateChart', generateRandomData(10), '#2389da'); updateMiniChart('bounceRateChart', generateRandomData(10), '#ff5630'); // Update stat values updateStatValues(); } function updateMiniChart(id, data, color) { createMiniChart(id, data, color); } // Refresh all data with wave animations function refreshAllData() { if (isRefreshing) return; isRefreshing = true; // Trigger all wave animations document.querySelectorAll('.wave-container').forEach(container => { container.style.opacity = '1'; }); // Use skeleton loading effect on stat values document.querySelectorAll('.stat-value, .stat-change').forEach(el => { const width = el.offsetWidth; const height = el.offsetHeight; el.innerHTML = ''; el.classList.add('skeleton'); el.style.width = `${width}px`; el.style.height = `${height}px`; }); // After animation, update data setTimeout(() => { // Hide wave animations document.querySelectorAll('.wave-container').forEach(container => { container.style.opacity = '0'; }); // Generate new data for current period chartData[currentPeriod] = generateRandomData(chartData[currentPeriod].length); // Update charts createMainChart(chartData[currentPeriod]); updateMiniChart('activeUsersChart', generateRandomData(10), '#64c4ff'); updateMiniChart('sessionTimeChart', generateRandomData(10), '#36b37e'); updateMiniChart('conversionRateChart', generateRandomData(10), '#2389da'); updateMiniChart('bounceRateChart', generateRandomData(10), '#ff5630'); // Update stat values document.querySelectorAll('.stat-value, .stat-change').forEach(el => { el.classList.remove('skeleton'); el.style.width = ''; el.style.height = ''; }); updateStatValues(); isRefreshing = false; }, 2500); } // Update stat values with new random data function updateStatValues() { // Active Users const activeUsers = Math.floor(Math.random() * 5000 + 5000); document.getElementById('activeUsers').textContent = activeUsers.toLocaleString(); const activeUsersChange = (Math.random() * 20 - 5).toFixed(1); const activeUsersChangeEl = document.getElementById('activeUsersChange'); activeUsersChangeEl.textContent = `${Math.abs(activeUsersChange)}%`; if (parseFloat(activeUsersChange) >= 0) { activeUsersChangeEl.parentElement.classList.add('positive'); activeUsersChangeEl.parentElement.classList.remove('negative'); activeUsersChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="18 15 12 9 6 15"></polyline>'; } else { activeUsersChangeEl.parentElement.classList.add('negative'); activeUsersChangeEl.parentElement.classList.remove('positive'); activeUsersChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="6 9 12 15 18 9"></polyline>'; } // Session Time const sessionMins = Math.floor(Math.random() * 8) + 1; const sessionSecs = Math.floor(Math.random() * 60); document.getElementById('sessionTime').textContent = `${sessionMins}:${sessionSecs.toString().padStart(2, '0')}`; const sessionTimeChange = (Math.random() * 15 - 3).toFixed(1); const sessionTimeChangeEl = document.getElementById('sessionTimeChange'); sessionTimeChangeEl.textContent = `${Math.abs(sessionTimeChange)}%`; if (parseFloat(sessionTimeChange) >= 0) { sessionTimeChangeEl.parentElement.classList.add('positive'); sessionTimeChangeEl.parentElement.classList.remove('negative'); sessionTimeChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="18 15 12 9 6 15"></polyline>'; } else { sessionTimeChangeEl.parentElement.classList.add('negative'); sessionTimeChangeEl.parentElement.classList.remove('positive'); sessionTimeChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="6 9 12 15 18 9"></polyline>'; } // Conversion Rate const conversionRate = (Math.random() * 6 + 1).toFixed(1); document.getElementById('conversionRate').textContent = `${conversionRate}%`; const conversionRateChange = (Math.random() * 4 - 1).toFixed(1); const conversionRateChangeEl = document.getElementById('conversionRateChange'); conversionRateChangeEl.textContent = `${Math.abs(conversionRateChange)}%`; if (parseFloat(conversionRateChange) >= 0) { conversionRateChangeEl.parentElement.classList.add('positive'); conversionRateChangeEl.parentElement.classList.remove('negative'); conversionRateChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="18 15 12 9 6 15"></polyline>'; } else { conversionRateChangeEl.parentElement.classList.add('negative'); conversionRateChangeEl.parentElement.classList.remove('positive'); conversionRateChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="6 9 12 15 18 9"></polyline>'; } // Bounce Rate const bounceRate = (Math.random() * 30 + 20).toFixed(1); document.getElementById('bounceRate').textContent = `${bounceRate}%`; const bounceRateChange = (Math.random() * 5 - 2.5).toFixed(1); const bounceRateChangeEl = document.getElementById('bounceRateChange'); bounceRateChangeEl.textContent = `${Math.abs(bounceRateChange)}%`; // For bounce rate, positive change is actually bad (negative sentiment) if (parseFloat(bounceRateChange) >= 0) { bounceRateChangeEl.parentElement.classList.add('negative'); bounceRateChangeEl.parentElement.classList.remove('positive'); bounceRateChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="6 9 12 15 18 9"></polyline>'; } else { bounceRateChangeEl.parentElement.classList.add('positive'); bounceRateChangeEl.parentElement.classList.remove('negative'); bounceRateChangeEl.parentElement.querySelector('svg').innerHTML = '<polyline points="18 15 12 9 6 15"></polyline>'; } } // Generate random chart data function generateRandomData(count) {
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Inter', 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 700px; background-color: #f7f9fc; color: #333; overflow: hidden; position: relative; } .container { width: 100%; max-width: 650px; padding: 30px; height: 650px; position: relative; display: flex; flex-direction: column; } .header { text-align: center; margin-bottom: 30px; } h1 { font-weight: 700; font-size: 28px; margin-bottom: 14px; background: linear-gradient(135deg, #3a6eff 0%, #5271ff 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } p.subtitle { color: #5e6a86; font-size: 16px; line-height: 1.5; max-width: 500px; margin: 0 auto; } .demo-area { flex: 1; background-color: #fff; border-radius: 18px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05); padding: 30px; display: flex; flex-direction: column; position: relative; overflow: hidden; } .demo-header { display: flex; justify-content: space-between; align-items: center; padding-bottom: 20px; border-bottom: 1px solid #eaeef5; margin-bottom: 24px; } .demo-title { font-size: 18px; font-weight: 600; color: #2c3e50; } .notifications-container { flex: 1; position: relative; overflow: hidden; } .control-panel { margin-top: 24px; display: flex; gap: 12px; justify-content: center; } .btn { background: #fff; border: 1px solid #dfe4ed; border-radius: 8px; padding: 10px 16px; font-size: 14px; font-weight: 500; color: #5271ff; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 8px; } .btn:hover { background: #f4f7ff; border-color: #5271ff; } .btn-primary { background: #5271ff; color: white; border-color: #5271ff; } .btn-primary:hover { background: #3a6eff; color: white; } .btn-icon { width: 16px; height: 16px; display: inline-flex; align-items: center; justify-content: center; } .notification { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); opacity: 0; visibility: hidden; width: 80%; max-width: 360px; background-color: #fff; border-radius: 12px; padding: 16px; box-shadow: 0 5px 20px rgba(0, 0, 0, 0.08); display: flex; align-items: flex-start; gap: 14px; transition: opacity 0.4s ease, transform 0.4s ease; z-index: 5; } .notification.show { opacity: 1; visibility: visible; transform: translate(-50%, -50%) scale(1); } .notification-icon { width: 24px; height: 24px; border-radius: 50%; background: #EBF5FF; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } .notification-icon svg { width: 14px; height: 14px; } .notification-content { flex: 1; } .notification-title { font-weight: 600; font-size: 15px; color: #2c3e50; margin-bottom: 5px; } .notification-message { font-size: 13px; color: #5e6a86; line-height: 1.5; } .notification-close { color: #a0aec0; cursor: pointer; background: transparent; border: none; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; padding: 0; margin-left: auto; flex-shrink: 0; } .notification-close:hover { color: #2c3e50; } .notification-action { margin-top: 10px; display: flex; gap: 8px; } .notification-btn { padding: 6px 10px; border-radius: 6px; font-size: 12px; font-weight: 500; cursor: pointer; transition: all 0.2s; } .notification-btn-primary { background: #5271ff; color: white; border: none; } .notification-btn-primary:hover { background: #3a6eff; } .notification-btn-secondary { background: transparent; border: none; color: #5e6a86; } .notification-btn-secondary:hover { color: #2c3e50; } .ripple-effect { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 20px; height: 20px; background: rgba(82, 113, 255, 0.1); border-radius: 50%; pointer-events: none; opacity: 0; z-index: 1; } @keyframes ripple { 0% { width: 20px; height: 20px; opacity: 0; } 25% { opacity: 0.6; } 100% { width: 500px; height: 500px; opacity: 0; } } /* Custom Notification Styles */ .notification.success .notification-icon { background: #E3F9E5; } .notification.success .notification-icon svg { color: #31C48D; } .notification.warning .notification-icon { background: #FEF3C7; } .notification.warning .notification-icon svg { color: #F59E0B; } .notification.error .notification-icon { background: #FDE8E8; } .notification.error .notification-icon svg { color: #E53E3E; } /* Device Frame */ .device-frame { position: absolute; top: 20px; right: 30px; width: 140px; height: 80px; display: flex; flex-direction: column; align-items: flex-start; gap: 10px; } .device-option { display: flex; align-items: center; gap: 8px; font-size: 13px; color: #5e6a86; cursor: pointer; transition: color 0.2s; padding: 5px; border-radius: 6px; } .device-option:hover { color: #2c3e50; background: rgba(234, 238, 245, 0.5); } .device-option.active { color: #5271ff; font-weight: 500; } .device-icon { width: 16px; height: 16px; } /* Responsive Adjustments */ @media (max-width: 600px) { .container { padding: 20px; } .demo-area { padding: 20px; } .notification { width: 90%; max-width: none; } .device-frame { display: none; } } </style> </head> <body> <div class="container"> <div class="header"> <h1>Liquid Ripple Notifications</h1> <p class="subtitle">A minimal notification system with dynamic fluid motion that draws attention to critical messages</p> </div> <div class="demo-area"> <div class="demo-header"> <div class="demo-title">Notification Preview</div> </div> <div class="notifications-container"> <!-- Notifications will be injected here --> <div id="notification-info" class="notification"> <div class="notification-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" color="#3B82F6"> <path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </div> <div class="notification-content"> <div class="notification-title">New feature available</div> <div class="notification-message">Try our new analytics dashboard with advanced data visualization tools.</div> <div class="notification-action"> <button class="notification-btn notification-btn-primary">View Now</button> <button class="notification-btn notification-btn-secondary">Later</button> </div> </div> <button class="notification-close" onclick="hideNotification('notification-info')"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> </div> <div id="notification-success" class="notification success"> <div class="notification-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /> </svg> </div> <div class="notification-content"> <div class="notification-title">Backup completed</div> <div class="notification-message">All your files have been successfully backed up to the cloud storage.</div> </div> <button class="notification-close" onclick="hideNotification('notification-success')"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> </div> <div id="notification-warning" class="notification warning"> <div class="notification-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /> </svg> </div> <div class="notification-content"> <div class="notification-title">Storage almost full</div> <div class="notification-message">You've used 85% of your storage space. Free up space to continue saving files.</div> <div class="notification-action"> <button class="notification-btn notification-btn-primary">Manage Storage</button> </div> </div> <button class="notification-close" onclick="hideNotification('notification-warning')"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> </div> <div id="notification-error" class="notification error"> <div class="notification-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> </svg> </div> <div class="notification-content"> <div class="notification-title">Connection lost</div> <div class="notification-message">Unable to sync your latest changes. Check your internet connection.</div> <div class="notification-action"> <button class="notification-btn notification-btn-primary">Retry</button> </div> </div> <button class="notification-close" onclick="hideNotification('notification-error')"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> <path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/> </svg> </button> </div> </div> <div class="control-panel"> <button class="btn" onclick="showNotification('notification-info')"> <span class="btn-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> </span> Info </button> <button class="btn" onclick="showNotification('notification-success')"> <span class="btn-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M5 13l4 4L19 7" /> </svg> </span> Success </button> <button class="btn" onclick="showNotification('notification-warning')"> <span class="btn-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" /> </svg> </span> Warning </button> <button class="btn" onclick="showNotification('notification-error')"> <span class="btn-icon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" /> </svg> </span> Error </button> </div> </div> </div> <script> // Current active notification let currentNotification = null; // Show notification with ripple effect function showNotification(id) { // Hide current notification if exists if (currentNotification) { hideNotification(currentNotification); } // Create and animate ripple effect const notificationsContainer = document.querySelector('.notifications-container'); const ripple = document.createElement('div'); ripple.classList.add('ripple-effect'); notificationsContainer.appendChild(ripple); // Trigger ripple animation setTimeout(() => { ripple.style.animation = 'ripple 1s ease-out forwards'; }, 10); // Show notification after ripple starts setTimeout(() => { const notification = document.getElementById(id); notification.classList.add('show'); currentNotification = id; // Remove ripple element after animation setTimeout(() => { ripple.remove(); }, 1000); }, 200); } // Hide notification function hideNotification(id) { const notification = document.getElementById(id); notification.classList.remove('show'); if (currentNotification === id) { currentNotification = null; } } // Show info notification on page load with a delay setTimeout(() => { showNotification('notification-info'); }, 800); // Add click event listeners to notification buttons (prevent default action) document.querySelectorAll('.notification-btn').forEach(button => { button.addEventListener('click', function(e) { e.preventDefault(); // Just for demo purposes, we'll close the notification when any button is clicked if (currentNotification) { hideNotification(currentNotification); } }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> :root { --primary-gradient-start: #06beb6; --primary-gradient-end: #48b1bf; --wave-color: rgba(255, 255, 255, 0.3); --text-color: #2d3748; --card-bg: #ffffff; --shadow-color: rgba(0, 0, 0, 0.1); --hover-shadow: rgba(0, 0, 0, 0.15); --success-color: #38b2ac; --button-bg: #4299e1; --button-hover: #3182ce; --button-active: #2b6cb0; } * { box-sizing: border-box; margin: 0; padding: 0; font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } body { background-color: #f7fafc; display: flex; justify-content: center; align-items: center; height: 100vh; width: 100%; overflow: hidden; color: var(--text-color); } .container { width: 100%; max-width: 600px; padding: 2rem; border-radius: 1rem; background-color: var(--card-bg); box-shadow: 0 10px 25px var(--shadow-color); transition: all 0.3s ease; } .container:hover { box-shadow: 0 15px 35px var(--hover-shadow); transform: translateY(-5px); } .header { margin-bottom: 2rem; } .title { font-size: 1.8rem; font-weight: 700; margin-bottom: 0.5rem; color: var(--text-color); } .subtitle { font-size: 1rem; color: #718096; margin-bottom: 1.5rem; } .file-info { display: flex; justify-content: space-between; margin-bottom: 0.75rem; font-size: 0.9rem; } .file-name { font-weight: 600; } .file-size { color: #718096; } .progress-container { position: relative; height: 3rem; background-color: #edf2f7; border-radius: 0.75rem; overflow: hidden; margin-bottom: 1.5rem; } .progress-bar { position: absolute; top: 0; left: 0; height: 100%; width: 0%; border-radius: 0.75rem; background: linear-gradient(90deg, var(--primary-gradient-start), var(--primary-gradient-end)); transition: width 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); box-shadow: 0 4px 6px rgba(6, 190, 182, 0.3); } .progress-liquid { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 1; opacity: 0.7; overflow: hidden; } .wave { position: absolute; background: var(--wave-color); border-radius: 30%; transform: translate(-50%, -50%); animation: wave 5s infinite linear; } .wave-1 { width: 200%; height: 200%; left: 50%; top: 50%; } .wave-2 { width: 180%; height: 180%; left: 50%; top: 50%; animation-delay: 0.3s; animation-direction: reverse; } @keyframes wave { 0% { transform: translate(-50%, -50%) rotate(0deg); } 100% { transform: translate(-50%, -50%) rotate(360deg); } } .progress-text { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; font-weight: 600; font-size: 1rem; z-index: 2; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); opacity: 0; transition: opacity 0.3s ease; } .transfer-details { display: flex; justify-content: space-between; margin-bottom: 2rem; font-size: 0.9rem; } .transfer-speed, .time-remaining { color: #718096; } .controls { display: flex; justify-content: space-between; align-items: center; } .transfer-status { font-size: 0.95rem; font-weight: 500; color: #4a5568; display: flex; align-items: center; } .status-icon { width: 1rem; height: 1rem; border-radius: 50%; background-color: #cbd5e0; margin-right: 0.5rem; transition: background-color 0.3s ease; } .status-icon.active { background-color: var(--success-color); box-shadow: 0 0 0 4px rgba(56, 178, 172, 0.2); animation: pulse 1.5s infinite; } @keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(56, 178, 172, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(56, 178, 172, 0); } 100% { box-shadow: 0 0 0 0 rgba(56, 178, 172, 0); } } .btn { background-color: var(--button-bg); color: white; border: none; padding: 0.6rem 1.2rem; border-radius: 0.5rem; cursor: pointer; font-weight: 500; font-size: 0.9rem; transition: all 0.2s ease; } .btn:hover { background-color: var(--button-hover); transform: translateY(-2px); } .btn:active { background-color: var(--button-active); transform: translateY(0); } .btn.cancel { background-color: #e53e3e; } .btn.cancel:hover { background-color: #c53030; } .btn.pause { background-color: #ed8936; } .btn.pause:hover { background-color: #dd6b20; } .btn.resume { background-color: #38a169; } .btn.resume:hover { background-color: #2f855a; } .btn:disabled { opacity: 0.6; cursor: not-allowed; transform: none; } .completed-animation { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; background-color: rgba(255, 255, 255, 0.9); border-radius: 1rem; opacity: 0; pointer-events: none; transition: opacity 0.5s ease; z-index: 10; } .completed-animation.show { opacity: 1; } .checkmark { stroke-dasharray: 1000; stroke-dashoffset: 1000; animation: dash 2s ease-in-out forwards; } @keyframes dash { to { stroke-dashoffset: 0; } } .file-actions { margin-top: 1.5rem; display: flex; gap: 0.75rem; opacity: 0; transform: translateY(10px); transition: all 0.3s ease; } .file-actions.show { opacity: 1; transform: translateY(0); } @media (max-width: 600px) { .container { padding: 1.5rem; max-width: 90%; } .title { font-size: 1.4rem; } .controls { flex-direction: column; align-items: flex-start; gap: 1rem; } .btn { width: 100%; } .file-actions { flex-direction: column; width: 100%; } .file-actions .btn { width: 100%; } } .tooltip { position: absolute; background: rgba(0, 0, 0, 0.75); color: white; padding: 0.5rem 0.75rem; border-radius: 0.25rem; font-size: 0.75rem; pointer-events: none; opacity: 0; transition: opacity 0.2s ease; z-index: 5; } .tooltip::after { content: ''; position: absolute; bottom: -5px; left: 50%; transform: translateX(-50%); width: 0; height: 0; border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 5px solid rgba(0, 0, 0, 0.75); } .tooltip.show { opacity: 1; } </style> </head> <body> <div class="container"> <div class="header"> <h1 class="title">FluidTransfer</h1> <p class="subtitle">Securely transferring your data with end-to-end encryption</p> </div> <div class="file-info"> <span class="file-name" id="file-name">project_presentation.zip</span> <span class="file-size">236.8 MB</span> </div> <div class="progress-container" id="progress-container"> <div class="progress-bar" id="progress-bar"> <div class="progress-liquid"> <div class="wave wave-1"></div> <div class="wave wave-2"></div> </div> </div> <div class="progress-text" id="progress-text">0%</div> <div class="tooltip" id="tooltip">Click to see detailed transfer stats</div> </div> <div class="transfer-details"> <span class="transfer-speed" id="transfer-speed">0 MB/s</span> <span class="time-remaining" id="time-remaining">Calculating...</span> </div> <div class="controls"> <div class="transfer-status"> <div class="status-icon" id="status-icon"></div> <span id="status-text">Preparing transfer</span> </div> <button class="btn" id="action-btn">Start Transfer</button> </div> <div class="file-actions" id="file-actions"> <button class="btn">Open File</button> <button class="btn">Show in Folder</button> </div> <div class="completed-animation" id="completed-animation"> <svg width="100" height="100" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="45" fill="none" stroke="#38b2ac" stroke-width="8"></circle> <path class="checkmark" d="M30 50 L45 65 L70 35" fill="none" stroke="#38b2ac" stroke-width="8" stroke-linecap="round" stroke-linejoin="round"></path> </svg> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const progressBar = document.getElementById('progress-bar'); const progressText = document.getElementById('progress-text'); const progressContainer = document.getElementById('progress-container'); const transferSpeed = document.getElementById('transfer-speed'); const timeRemaining = document.getElementById('time-remaining'); const statusIcon = document.getElementById('status-icon'); const statusText = document.getElementById('status-text'); const actionBtn = document.getElementById('action-btn'); const completedAnimation = document.getElementById('completed-animation'); const fileActions = document.getElementById('file-actions'); const tooltip = document.getElementById('tooltip'); const fileName = document.getElementById('file-name'); let progress = 0; let transferActive = false; let transferPaused = false; let transferInterval; let speedUpdateInterval; let currentSpeed = 0; let fileSize = 236.8; // MB let elapsedTime = 0; let transferredData = 0; // Show tooltip when hovering over progress bar progressContainer.addEventListener('mouseenter', () => { tooltip.style.top = `${progressContainer.offsetTop - tooltip.offsetHeight - 10}px`; tooltip.style.left = `${progressContainer.offsetLeft + progressContainer.offsetWidth / 2 - tooltip.offsetWidth / 2}px`; tooltip.classList.add('show'); }); progressContainer.addEventListener('mouseleave', () => { tooltip.classList.remove('show'); }); // Show detailed stats on click progressContainer.addEventListener('click', () => { if (transferActive) { const uploadedData = (progress / 100 * fileSize).toFixed(1); const remainingData = (fileSize - uploadedData).toFixed(1); alert(` Transfer Stats: - ${uploadedData} MB of ${fileSize} MB transferred - ${remainingData} MB remaining - Current speed: ${currentSpeed.toFixed(1)} MB/s - Network: Strong (5 bars) - Connection: Stable `); } }); // Action button click handler actionBtn.addEventListener('click', () => { if (!transferActive && !transferPaused) { startTransfer(); } else if (transferActive && !transferPaused) { pauseTransfer(); } else if (transferPaused) { resumeTransfer(); } }); // Simulate different file types const fileTypes = [ { name: 'project_presentation.zip', size: '236.8 MB' }, { name: 'vacation_photos.rar', size: '512.3 MB' }, { name: 'quarterly_report.pdf', size: '18.5 MB' }, { name: 'development_build.exe', size: '345.2 MB' }, { name: 'client_assets.iso', size: '1.2 GB' } ]; function changeFile() { const randomFile = fileTypes[Math.floor(Math.random() * fileTypes.length)]; fileName.textContent = randomFile.name; document.querySelector('.file-size').textContent = randomFile.size; fileSize = parseFloat(randomFile.size); if (randomFile.size.includes('GB')) { fileSize *= 1024; // Convert GB to MB } } if (Math.random() > 0.5) { changeFile(); } function startTransfer() { transferActive = true; transferPaused = false; statusIcon.classList.add('active'); actionBtn.textContent = 'Pause'; actionBtn.classList.add('pause'); statusText.textContent = 'Transferring'; // Gradually increase transfer speed to simulate network acceleration currentSpeed = 0.5; // Initial speed in MB/s transferInterval = setInterval(updateProgress, 100); speedUpdateInterval = setInterval(updateSpeed, 1000); // Make progress text visible progressText.style.opacity = 1; } function pauseTransfer() { transferActive = false; transferPaused = true; clearInterval(transferInterval); clearInterval(speedUpdateInterval); actionBtn.textContent = 'Resume'; actionBtn.classList.remove('pause'); actionBtn.classList.add('resume'); statusText.textContent = 'Paused'; statusIcon.classList.remove('active'); } function resumeTransfer() { transferActive = true; transferPaused = false; statusIcon.classList.add('active'); actionBtn.textContent = 'Pause'; actionBtn.classList.remove('resume'); actionBtn.classList.add('pause'); statusText.textContent = 'Transferring'; transferInterval = setInterval(updateProgress, 100); speedUpdateInterval = setInterval(updateSpeed, 1000); } function updateProgress() { if (progress < 100) { // Calculate how much to increment based on current speed // 100ms interval, so divide speed by 10 for percentage per interval const increment = (currentSpeed / fileSize * 100) / 10; progress += increment; if (progress > 100) progress = 100; // Update UI progressBar.style.width = `${progress}%`; progressText.textContent = `${Math.round(progress)}%`; // Update transferred data transferredData = (progress / 100) * fileSize; // Change gradient based on progress const hue1 = 180 - (progress / 100 * 40); // from cyan to blue const hue2 = 200 - (progress / 100 * 60); // slightly different hue progressBar.style.background = `linear-gradient(90deg, hsl(${hue1}, 100%, 50%), hsl(${hue2}, 70%, 50%))`; // Adjust wave speed based on transfer speed const waveSpeed = 5 - (currentSpeed / 10); // Faster transfer = faster waves document.querySelectorAll('.wave').forEach(wave => { wave.style.animationDuration = `${Math.max(2, waveSpeed)}s`; }); elapsedTime += 0.1; // 100ms // Calculate remaining time if (currentSpeed > 0) { const remainingData = fileSize - transferredData; const estimatedTimeRemaining = remainingData / currentSpeed; updateRemainingTime(estimatedTimeRemaining); } } else { completeTransfer(); } } function updateSpeed() { if (transferActive) { // Simulate variations in network speed const speedVariation = Math.random() * 2 - 0.5; // -0.5 to 1.5 currentSpeed = Math.max(0.5, Math.min(12, currentSpeed + speedVariation)); // Simulate network congestion at certain points if (progress > 60 && progress < 70 && Math.random() > 0.7) { currentSpeed *= 0.5; // Slow down temporarily } // Accelerate as we start and decelerate as we approach completion if (progress < 10) { currentSpeed = Math.min(currentSpeed * 1.2, 12); // Accelerate at start } else if (progress > 90) { currentSpeed = Math.max(currentSpeed * 0.9, 1); // Slow down at end } transferSpeed.textContent = `${currentSpeed.toFixed(1)} MB/s`; } } function updateRemainingTime(seconds) { if (seconds < 60) { timeRemaining.textContent = `${Math.ceil(seconds)} seconds left`; } else if (seconds < 3600) { const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.ceil(seconds % 60); timeRemaining.textContent = `${minutes}:${remainingSeconds.toString().padStart(2, '0')} minutes left`; } else { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); timeRemaining.textContent = `${hours}:${minutes.toString().padStart(2, '0')} hours left`; } } function completeTransfer() { clearInterval(transferInterval); clearInterval(speedUpdateInterval); transferActive = false; // Update UI statusText.textContent = 'Completed'; actionBtn.textContent = 'Start New Transfer'; actionBtn.classList.remove('pause', 'resume'); // Show completed animation completedAnimation.classList.add('show'); setTimeout(() => { completedAnimation.classList.remove('show'); // Show file actions fileActions.classList.add('show'); }, 2500); // Update final stats transferSpeed.textContent = `${(fileSize / elapsedTime).toFixed(1)} MB/s avg`; timeRemaining.textContent = `Completed in ${formatTime(elapsedTime)}`; // Prepare for a new transfer actionBtn.addEventListener('click', resetTransfer, { once: true }); } function formatTime(seconds) { if (seconds < 60) { return `${Math.round(seconds)} seconds`; } else if (seconds < 3600) { const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.round(seconds % 60); return `${minutes}m ${remainingSeconds}s`; } else { const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); return `${hours}h ${minutes}m`; } } function resetTransfer() { progress = 0; elapsedTime = 0; transferredData = 0; // Reset UI progressBar.style.width = '0%'; progressText.style.opacity = 0; progressText.textContent = '0%'; statusText.textContent = 'Ready to transfer'; transferSpeed.textContent = '0 MB/s'; timeRemaining.textContent = 'Calculating...'; statusIcon.classList.remove('active'); // Hide file actions fileActions.classList.remove('show'); // Change file changeFile(); // Reset button actionBtn.textContent = 'Start Transfer'; } // Add some initial animation to catch user's attention setTimeout(() => { progressBar.style.width = '5%'; setTimeout(() => { progressBar.style.width = '0%'; }, 800); }, 500); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>EcoDrops Nature Food</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } :root { --primary-green: #4d8c57; --light-green: #8fbf9b; --dark-green: #2c5d3f; --earthy-brown: #a67c52; --light-brown: #d9c5a0; --white: #ffffff; --off-white: #f8f9f5; } body { background-color: var(--off-white); color: #333; width: 100%; height: 700px; overflow-x: hidden; display: flex; justify-content: center; align-items: center; } .container { width: 90%; max-width: 700px; margin: 0 auto; position: relative; overflow: hidden; padding: 20px; background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect width="100" height="100" fill="%23f8f9f5"/><path d="M0 0L100 100M100 0L0 100" stroke="%23e9efe0" stroke-width="0.5"/></svg>'); border-radius: 15px; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.05); } .header { text-align: center; margin-bottom: 30px; position: relative; } .logo { font-size: 2.2rem; font-weight: 700; color: var(--dark-green); letter-spacing: -1px; margin-bottom: 5px; position: relative; display: inline-block; } .logo::after { content: ""; position: absolute; width: 8px; height: 8px; background: var(--earthy-brown); border-radius: 50%; right: -12px; top: 15px; } .tagline { font-size: 1rem; color: var(--primary-green); font-weight: 400; letter-spacing: 0.5px; max-width: 80%; margin: 0 auto; } .content { display: flex; flex-direction: column; gap: 30px; margin-bottom: 30px; } .intro { font-size: 1.1rem; line-height: 1.6; color: #444; position: relative; padding: 20px; border-radius: 12px; background-color: rgba(255, 255, 255, 0.7); backdrop-filter: blur(5px); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.03); } .highlight { color: var(--dark-green); font-weight: 600; } .featured-products { display: flex; gap: 15px; overflow-x: auto; padding: 5px 0 15px; position: relative; scrollbar-width: thin; scrollbar-color: var(--light-green) transparent; } .featured-products::-webkit-scrollbar { height: 6px; } .featured-products::-webkit-scrollbar-track { background: transparent; } .featured-products::-webkit-scrollbar-thumb { background-color: var(--light-green); border-radius: 20px; } .product-card { flex: 0 0 calc(33.33% - 10px); min-width: 200px; padding: 15px; background: white; border-radius: 10px; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05); transition: transform 0.3s ease, box-shadow 0.3s ease; position: relative; overflow: hidden; } .product-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0, 0, 0, 0.08); } .product-card::before { content: ""; position: absolute; top: -20px; right: -20px; width: 60px; height: 60px; background: var(--light-green); border-radius: 50%; opacity: 0.2; z-index: 0; } .product-image { width: 100%; height: 120px; object-fit: cover; border-radius: 8px; margin-bottom: 12px; } .product-name { font-weight: 600; color: var(--dark-green); margin-bottom: 5px; } .product-description { font-size: 0.85rem; color: #666; margin-bottom: 10px; } .product-price { font-weight: 600; color: var(--earthy-brown); } .cta-section { text-align: center; background: linear-gradient(135deg, rgba(143, 191, 155, 0.2) 0%, rgba(217, 197, 160, 0.2) 100%); padding: 25px 20px; border-radius: 12px; position: relative; overflow: hidden; } .cta-title { font-size: 1.4rem; color: var(--dark-green); margin-bottom: 15px; position: relative; z-index: 2; } .cta-text { font-size: 1rem; color: #555; margin-bottom: 25px; position: relative; z-index: 2; } .cta-buttons { display: flex; justify-content: center; gap: 15px; flex-wrap: wrap; position: relative; z-index: 2; } .btn { min-width: 150px; padding: 12px 24px; border-radius: 30px; font-weight: 600; font-size: 1rem; text-decoration: none; text-align: center; cursor: pointer; transition: transform 0.3s ease; position: relative; overflow: hidden; display: flex; align-items: center; justify-content: center; border: none; outline: none; } .btn-primary { background-color: var(--primary-green); color: white; } .btn-secondary { background-color: white; color: var(--dark-green); border: 2px solid var(--primary-green); } /* Liquid Drop Effect */ .liquid-drop { position: absolute; width: 15px; height: 15px; background-color: rgba(255, 255, 255, 0.7); border-radius: 50%; transform: scale(0); z-index: 1; pointer-events: none; } /* Blob decoration */ .blob { position: absolute; background: var(--light-green); border-radius: 50%; filter: blur(20px); opacity: 0.1; z-index: 0; } .blob-1 { width: 200px; height: 200px; top: -100px; left: -50px; } .blob-2 { width: 150px; height: 150px; bottom: -70px; right: -30px; background: var(--light-brown); } .footer { display: flex; justify-content: space-between; padding-top: 20px; border-top: 1px solid rgba(0, 0, 0, 0.05); font-size: 0.8rem; color: #777; } .eco-badge { display: flex; align-items: center; gap: 5px; color: var(--primary-green); font-weight: 600; } .eco-icon { width: 18px; height: 18px; } /* Leaf animation */ .leaf { position: absolute; width: 20px; height: 20px; background-color: var(--light-green); opacity: 0.5; border-radius: 0 50% 50% 50%; transform: rotate(45deg); pointer-events: none; z-index: 0; } @media (max-width: 600px) { .container { padding: 15px; } .logo { font-size: 1.8rem; } .tagline { font-size: 0.9rem; } .intro { font-size: 1rem; padding: 15px; } .product-card { min-width: 160px; } .cta-title { font-size: 1.2rem; } .cta-text { font-size: 0.9rem; } .btn { padding: 10px 20px; font-size: 0.9rem; min-width: 130px; } .cta-buttons { gap: 10px; } } </style> </head> <body> <div class="container"> <div class="blob blob-1"></div> <div class="blob blob-2"></div> <header class="header"> <h1 class="logo">EcoDrops</h1> <p class="tagline">Harvesting nature's goodness, one drop at a time</p> </header> <div class="content"> <div class="intro"> At EcoDrops, we believe that <span class="highlight">what flows from our farms to your table</span> should be as pure as the morning dew. Our regenerative farming practices nurture soil health while our biodegradable packaging honors our pledge to protect the earth that sustains us all. </div> <div class="featured-products"> <div class="product-card"> <div class="product-image" style="background-color: #D9E5D6;"></div> <h3 class="product-name">Wildflower Honey</h3> <p class="product-description">Collected from untreated meadows by rescue bees</p> <p class="product-price">$12.95</p> </div> <div class="product-card"> <div class="product-image" style="background-color: #BED1AF;"></div> <h3 class="product-name">Berry Basket</h3> <p class="product-description">Seasonal mix of forest-edge berries, unwashed</p> <p class="product-price">$8.50</p> </div> <div class="product-card"> <div class="product-image" style="background-color: #E3DAC9;"></div> <h3 class="product-name">Ancient Grains</h3> <p class="product-description">Heritage quinoa and amaranth, drought-resistant</p> <p class="product-price">$6.75</p> </div> </div> <div class="cta-section"> <h2 class="cta-title">Join Our Ecosystem</h2> <p class="cta-text">Subscribe to our seasonal harvest boxes and receive nature's bounty direct from our carbon-negative farms.</p> <div class="cta-buttons"> <button class="btn btn-primary" id="subscribe-btn">Subscribe Now</button> <button class="btn btn-secondary" id="learn-btn">Learn More</button> </div> </div> </div> <footer class="footer"> <div class="eco-badge"> <svg class="eco-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> <path d="M12 2L2 7l10 5 10-5-10-5z"></path> <path d="M2 17l10 5 10-5"></path> <path d="M2 12l10 5 10-5"></path> </svg> Zero Waste Certified </div> <div>© 2023 EcoDrops</div> </footer> </div> <script> document.addEventListener("DOMContentLoaded", function() { // Buttons for liquid drop effect const buttons = document.querySelectorAll('.btn'); buttons.forEach(button => { button.addEventListener('mouseenter', function(e) { createLiquidEffect(this); }); button.addEventListener('click', function(e) { e.preventDefault(); createWaveEffect(this); // Add success feedback const originalText = this.textContent; const isSubscribe = this.id === 'subscribe-btn'; this.disabled = true; this.textContent = isSubscribe ? 'Thanks!' : 'Coming soon!'; setTimeout(() => { this.disabled = false; this.textContent = originalText; }, 2000); }); }); // Create random floating leaves createLeaves(); function createLiquidEffect(element) { const drop = document.createElement('div'); drop.className = 'liquid-drop'; const colors = ['rgba(143, 191, 155, 0.7)', 'rgba(77, 140, 87, 0.7)', 'rgba(166, 124, 82, 0.6)']; const randomColor = colors[Math.floor(Math.random() * colors.length)]; drop.style.backgroundColor = randomColor; drop.style.left = Math.random() * 100 + '%'; drop.style.top = Math.random() * 100 + '%'; element.appendChild(drop); // Animate the drop requestAnimationFrame(() => { drop.style.transition = 'transform 1s ease-out, opacity 1s ease-out'; drop.style.transform = 'scale(15)'; drop.style.opacity = '0'; setTimeout(() => { drop.remove(); }, 1000); }); } function createWaveEffect(element) { const btnRect = element.getBoundingClientRect(); const centerX = btnRect.width / 2; const centerY = btnRect.height / 2; for (let i = 0; i < 8; i++) { setTimeout(() => { const drop = document.createElement('div'); drop.className = 'liquid-drop'; const colors = ['rgba(143, 191, 155, 0.7)', 'rgba(77, 140, 87, 0.7)']; const randomColor = colors[Math.floor(Math.random() * colors.length)]; drop.style.backgroundColor = randomColor; drop.style.left = centerX + 'px'; drop.style.top = centerY + 'px'; element.appendChild(drop); requestAnimationFrame(() => { drop.style.transition = 'transform 1.5s ease-out, opacity 1.5s ease-out'; drop.style.transform = 'scale(20)'; drop.style.opacity = '0'; setTimeout(() => { drop.remove(); }, 1500); }); }, i * 150); } } function createLeaves() { const container = document.querySelector('.container'); for (let i = 0; i < 5; i++) { const leaf = document.createElement('div'); leaf.className = 'leaf'; // Randomize leaf properties const size = 10 + Math.random() * 15; const left = Math.random() * 100; const delay = Math.random() * 5; const duration = 15 + Math.random() * 10; const rotation = Math.random() * 360; leaf.style.width = size + 'px'; leaf.style.height = size + 'px'; leaf.style.left = left + '%'; leaf.style.top = '-20px'; leaf.style.transform = `rotate(${rotation}deg)`; // Adjust opacity and color slightly leaf.style.opacity = 0.2 + Math.random() * 0.3; const colors = ['#4d8c57', '#8fbf9b', '#a67c52']; leaf.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)]; container.appendChild(leaf); // Animate the leaf falling leaf.style.transition = `top ${duration}s linear, left ${duration}s ease-in-out, transform ${duration}s ease-in-out`; leaf.style.transitionDelay = delay + 's'; setTimeout(() => { leaf.style.top = container.offsetHeight + 20 + 'px'; leaf.style.left = (parseInt(leaf.style.left) + (Math.random() * 30 - 15)) + '%'; leaf.style.transform = `rotate(${rotation + 360}deg)`; // Remove the leaf after animation completes setTimeout(() => { leaf.remove(); createLeaves(); }, (duration + delay) * 1000); }, 100); } } // Product card hover effect const productCards = document.querySelectorAll('.product-card'); productCards.forEach(card => { card.addEventListener('mouseenter', function() { this.style.transition = 'transform 0.3s ease, box-shadow 0.3s ease'; this.style.transform = 'translateY(-5px)'; this.style.boxShadow = '0 10px 20px rgba(0, 0, 0, 0.08)'; }); card.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = '0 4px 10px rgba(0, 0, 0, 0.05)'; }); }); }); </script> </body> </html>
<html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Liquid Portfolio</title> <style> :root { --primary: #2d2d35; --secondary: #e7e2dd; --accent: #a78f7f; --light: #f5f2ef; --dark: #1a1a20; --transition: all 0.4s cubic-bezier(0.25, 1, 0.5, 1); --font-display: 'Inter', sans-serif; --font-body: 'Inter', sans-serif; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: var(--font-body); background-color: var(--light); color: var(--primary); overflow-x: hidden; height: 100vh; width: 100%; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 1.5rem; } @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap'); .portfolio-header { text-align: center; margin-bottom: 1.5rem; width: 100%; } .portfolio-header h1 { font-family: var(--font-display); font-weight: 600; font-size: 1.8rem; letter-spacing: -0.02em; margin-bottom: 0.5rem; color: var(--dark); } .portfolio-header p { font-size: 0.9rem; font-weight: 400; line-height: 1.6; max-width: 500px; margin: 0 auto; color: var(--primary); opacity: 0.8; } .portfolio-container { width: 100%; max-width: 660px; position: relative; display: flex; flex-direction: column; gap: 1.5rem; margin: 0 auto; overflow: hidden; } .project-card { width: 100%; padding: 2rem; border-radius: 12px; background-color: var(--secondary); position: relative; cursor: pointer; overflow: hidden; transition: var(--transition); transform: translateY(0); opacity: 0; z-index: 2; } .project-card.active { opacity: 1; transform: translateY(0); } .project-card.ink-transition-out { animation: dissolveOut 1.2s forwards; } .project-card.ink-transition-in { animation: dissolveIn 1.2s forwards; } .project-card:hover { transform: translateY(-4px); } .project-title { font-family: var(--font-display); font-weight: 600; font-size: 1.4rem; margin-bottom: 0.8rem; position: relative; z-index: 2; } .project-title::after { content: ""; position: absolute; width: 40px; height: 2px; background: var(--accent); bottom: -6px; left: 0; transition: var(--transition); } .project-card:hover .project-title::after { width: 60px; } .project-tags { display: flex; gap: 0.5rem; margin-bottom: 1rem; flex-wrap: wrap; position: relative; z-index: 2; } .project-tag { padding: 0.3rem 0.8rem; font-size: 0.7rem; border-radius: 100px; background-color: rgba(255, 255, 255, 0.3); backdrop-filter: blur(10px); font-weight: 500; } .project-description { font-size: 0.9rem; line-height: 1.6; margin-bottom: 1.5rem; position: relative; z-index: 2; } .project-link { display: inline-flex; align-items: center; gap: 0.5rem; color: var(--dark); text-decoration: none; font-weight: 500; font-size: 0.85rem; position: relative; z-index: 2; transition: var(--transition); } .project-link:hover { color: var(--accent); } .project-link svg { width: 16px; height: 16px; transition: var(--transition); } .project-link:hover svg { transform: translateX(4px); } .canvas-container { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; } #inkCanvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .navigation { display: flex; gap: 1rem; margin-top: 1.5rem; align-items: center; justify-content: center; } .nav-btn { width: 40px; height: 40px; border-radius: 50%; background-color: var(--secondary); display: flex; align-items: center; justify-content: center; border: none; cursor: pointer; transition: var(--transition); } .nav-btn:hover { background-color: var(--accent); transform: scale(1.1); } .nav-btn svg { width: 18px; height: 18px; fill: var(--dark); } .nav-dots { display: flex; gap: 0.5rem; align-items: center; } .nav-dot { width: 8px; height: 8px; border-radius: 50%; background-color: var(--secondary); transition: var(--transition); cursor: pointer; } .nav-dot.active { background-color: var(--accent); width: 12px; height: 12px; } @keyframes dissolveOut { 0% { opacity: 1; clip-path: circle(150% at center); } 100% { opacity: 0; clip-path: circle(0% at center); } } @keyframes dissolveIn { 0% { opacity: 0; clip-path: circle(0% at center); } 100% { opacity: 1; clip-path: circle(150% at center); } } @media (max-width: 700px) { .portfolio-header h1 { font-size: 1.5rem; } .portfolio-header p { font-size: 0.8rem; } .project-card { padding: 1.5rem; } .project-title { font-size: 1.2rem; } } @media (max-width: 480px) { body { padding: 1rem; } .portfolio-header h1 { font-size: 1.3rem; } .project-card { padding: 1.2rem; } .project-title { font-size: 1.1rem; } .project-description { font-size: 0.8rem; } } </style> </head> <body> <div class="portfolio-header"> <h1>Design Portfolio</h1> <p>A curation of projects showcasing experimental interactions between digital and physical mediums</p> </div> <div class="portfolio-container"> <div class="project-card active" data-color="#a78f7f"> <h2 class="project-title">Liquid Typography System</h2> <div class="project-tags"> <span class="project-tag">Typography</span> <span class="project-tag">Motion</span> <span class="project-tag">Branding</span> </div> <p class="project-description">A responsive typeface that reacts to user input like flowing ink, designed for a contemporary art gallery's identity. Characters transform and blend beautifully when activated.</p> <a href="#" class="project-link"> View project details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z"/> </svg> </a> </div> <div class="project-card" data-color="#7f96a7"> <h2 class="project-title">Chromatic Dispersion</h2> <div class="project-tags"> <span class="project-tag">Web Design</span> <span class="project-tag">Animation</span> <span class="project-tag">Interaction</span> </div> <p class="project-description">An e-commerce interface where product categories blend like pigments in water, creating intuitive color-based navigation that enhances user experience and visual hierarchy.</p> <a href="#" class="project-link"> View project details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z"/> </svg> </a> </div> <div class="project-card" data-color="#a17f81"> <h2 class="project-title">Aqueous Data Visualization</h2> <div class="project-tags"> <span class="project-tag">Data Viz</span> <span class="project-tag">Processing</span> <span class="project-tag">UX Research</span> </div> <p class="project-description">A dashboard that transforms numerical data into fluid, organic patterns imitating ink diffusion. The system helps users intuitively understand complex datasets through visual metaphor.</p> <a href="#" class="project-link"> View project details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z"/> </svg> </a> </div> <div class="project-card" data-color="#899779"> <h2 class="project-title">Dissolving Boundaries</h2> <div class="project-tags"> <span class="project-tag">Installation</span> <span class="project-tag">Mixed Media</span> <span class="project-tag">Projection</span> </div> <p class="project-description">An interactive gallery installation where physical movement causes projected elements to bleed and merge like ink in water, dissolving the boundaries between viewer and artwork.</p> <a href="#" class="project-link"> View project details <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path d="M16.172 11l-5.364-5.364 1.414-1.414L20 12l-7.778 7.778-1.414-1.414L16.172 13H4v-2z"/> </svg> </a> </div> </div> <div class="navigation"> <button class="nav-btn prev-btn"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M10.828 12l4.95 4.95-1.414 1.414L8 12l6.364-6.364 1.414 1.414z"/> </svg> </button> <div class="nav-dots"></div> <button class="nav-btn next-btn"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M13.172 12l-4.95-4.95 1.414-1.414L16 12l-6.364 6.364-1.414-1.414z"/> </svg> </button> </div> <div class="canvas-container"> <canvas id="inkCanvas"></canvas> </div> <script> document.addEventListener('DOMContentLoaded', function() { const projectCards = document.querySelectorAll('.project-card'); const navDots = document.querySelector('.nav-dots'); const prevBtn = document.querySelector('.prev-btn'); const nextBtn = document.querySelector('.next-btn'); let currentIndex = 0; // Create navigation dots projectCards.forEach((_, index) => { const dot = document.createElement('div'); dot.classList.add('nav-dot'); if (index === 0) dot.classList.add('active'); dot.addEventListener('click', () => { if (index !== currentIndex) { navigateToProject(index); } }); navDots.appendChild(dot); }); // Setup canvas for ink effect const canvas = document.getElementById('inkCanvas'); const ctx = canvas.getContext('2d'); canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Ink drop particles class InkDrop { constructor(x, y, radius, color) { this.x = x; this.y = y; this.radius = radius; this.originalRadius = radius; this.targetRadius = radius * (2 + Math.random() * 4); this.color = color; this.opacity = 0.7; this.growSpeed = 0.2 + Math.random() * 0.8; this.angleSpeed = (Math.random() - 0.5) * 0.1; this.angle = Math.random() * Math.PI * 2; this.distance = 0; this.maxDistance = 50 + Math.random() * 100; this.waveIntensity = Math.random() * 5; } update() { this.radius += (this.targetRadius - this.radius) * 0.05; this.opacity -= 0.005; this.distance += this.growSpeed; this.angle += this.angleSpeed; // Wave-like movement this.x += Math.cos(this.angle) * this.waveIntensity; this.y += Math.sin(this.angle) * this.waveIntensity; return this.opacity > 0; } draw(ctx) { ctx.beginPath(); ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2); ctx.fillStyle = `${this.color}${Math.floor(this.opacity * 255).toString(16).padStart(2, '0')}`; ctx.fill(); } } // Ink effect system const inkSystem = { particles: [], addInkBurst(x, y, color, size = 1) { const numParticles = 15 + Math.floor(Math.random() * 10); for (let i = 0; i < numParticles; i++) { const radius = 5 + Math.random() * 10 * size; this.particles.push(new InkDrop( x + (Math.random() - 0.5) * 20, y + (Math.random() - 0.5) * 20, radius, color )); } }, update() { this.particles = this.particles.filter(particle => particle.update()); }, draw(ctx) { this.particles.forEach(particle => particle.draw(ctx)); }, clear() { ctx.clearRect(0, 0, canvas.width, canvas.height); } }; // Animation loop function animate() { inkSystem.clear(); inkSystem.update(); inkSystem.draw(ctx); requestAnimationFrame(animate); } animate(); // Navigation functions function navigateToProject(index) { if (index < 0 || index >= projectCards.length || index === currentIndex) return; const currentCard = projectCards[currentIndex]; const nextCard = projectCards[index]; const currentColor = currentCard.dataset.color || "#a78f7f"; const nextColor = nextCard.dataset.color || "#a78f7f"; // Get positions for the ink effect const currentRect = currentCard.getBoundingClientRect(); const nextRect = nextCard.getBoundingClientRect(); const currentCenterX = currentRect.left + currentRect.width / 2; const currentCenterY = currentRect.top + currentRect.height / 2; const nextCenterX = nextRect.left + nextRect.width / 2; const nextCenterY = nextRect.top + nextRect.height / 2; // Add ink burst effect inkSystem.addInkBurst(currentCenterX, currentCenterY, currentColor, 2); setTimeout(() => { inkSystem.addInkBurst(nextCenterX, nextCenterY, nextColor, 2); }, 300); // Transition classes currentCard.classList.add('ink-transition-out'); currentCard.classList.remove('active'); setTimeout(() => { nextCard.classList.add('active', 'ink-transition-in'); // Update navigation dots document.querySelectorAll('.nav-dot').forEach((dot, i) => { dot.classList.toggle('active', i === index); }); currentIndex = index; // Remove transition classes after animation setTimeout(() => { currentCard.classList.remove('ink-transition-out'); nextCard.classList.remove('ink-transition-in'); }, 1000); }, 400); } // Event listeners prevBtn.addEventListener('click', () => { navigateToProject((currentIndex - 1 + projectCards.length) % projectCards.length); }); nextBtn.addEventListener('click', () => { navigateToProject((currentIndex + 1) % projectCards.length); }); // Show only the first card initially projectCards.forEach((card, index) => { if (index !== 0) { card.style.display = 'none'; } }); // Show cards with a staggered animation on load setTimeout(() => { projectCards.forEach((card, index) => { card.style.display = 'block'; if (index === 0) { const rect = card.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; inkSystem.addInkBurst(centerX, centerY, card.dataset.color || "#a78f7f", 1.5); } }); }, 300); // Window resize handler for canvas window.addEventListener('resize', () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }); // Add hover effects for cards that trigger micro ink drops projectCards.forEach(card => { card.addEventListener('mouseenter', function(e) { if (this.classList.contains('active')) { const rect = this.getBoundingClientRect(); const x = e.clientX; const y = e.clientY; inkSystem.addInkBurst(x, y, this.dataset.color || "#a78f7f", 0.5); } }); }); }); </script> </body> </html>