diff --git a/love14/README.md b/love14/README.md new file mode 100644 index 00000000000..bd65d1a15ed --- /dev/null +++ b/love14/README.md @@ -0,0 +1,93 @@ +# Glowing Heart Animation + +A beautiful, interactive heart animation created with HTML, CSS, and JavaScript. This project features a multi-layered glowing blue heart with dynamic effects and interactive elements. + +## Features + +- **Multi-layered Heart Design**: 5 concentric heart layers with different sizes and opacity levels +- **Glowing Effects**: CSS box-shadow and border effects create a beautiful blue glow +- **Pulsing Animation**: Smooth scale and opacity animations with staggered timing +- **Interactive Elements**: + - Click hearts to create burst particle effects + - Play/pause button to control animation + - Mouse movement creates subtle parallax effects + - Touch support for mobile devices +- **Responsive Design**: Adapts to different screen sizes +- **Keyboard Controls**: Spacebar to pause/resume, R to reset + +## File Structure + +``` +love14/ +├── index.html # Main HTML structure +├── style.css # CSS styles and animations +├── script.js # JavaScript interactivity +└── README.md # This file +``` + +## How to Run + +1. **Simple Method**: Open `index.html` directly in a web browser +2. **Local Server** (Recommended): + - Use a local server like Live Server in VS Code + - Or run: `python -m http.server 3000` in the project directory + - Then visit: `http://localhost:3000/love14/index.html` + +## Code Analysis + +### HTML Structure (`index.html`) +- Clean, semantic HTML5 structure +- Container div for centering and positioning +- Multiple heart divs with different classes for layering +- Play button with icon for user interaction + +### CSS Styling (`style.css`) +- **Heart Creation**: Uses CSS pseudo-elements (`::before`, `::after`) to create heart shapes from squares +- **Layering System**: 5 heart layers with decreasing sizes and increasing opacity +- **Animation**: CSS `@keyframes` for smooth pulsing effect with staggered delays +- **Glow Effects**: Multiple `box-shadow` properties create the glowing appearance +- **Responsive Design**: Media queries for mobile optimization + +### JavaScript Functionality (`script.js`) +- **Event Listeners**: Handles clicks, mouse movement, keyboard input, and touch events +- **Particle System**: Creates burst effects when hearts are clicked +- **Animation Control**: Play/pause functionality with visual feedback +- **Parallax Effect**: Subtle movement based on mouse position +- **Touch Support**: Different behaviors for short taps vs long presses +- **Random Effects**: Periodic sparkle animations for added visual interest + +## Technical Details + +### Heart Shape Creation +The heart shape is created using CSS by: +1. Starting with a square element rotated 45 degrees +2. Adding two circular pseudo-elements positioned to form the heart curves +3. Using `border-radius: 50%` to create the circular parts + +### Animation System +- Uses CSS `animation` property with `ease-in-out` timing +- Staggered delays create a wave-like pulsing effect +- JavaScript controls animation state (play/pause) + +### Performance Optimizations +- Uses CSS transforms for smooth animations +- Efficient event handling with proper cleanup +- Minimal DOM manipulation for particle effects + +## Browser Compatibility + +- Modern browsers with CSS3 and ES6 support +- Mobile browsers with touch event support +- Tested on Chrome, Firefox, Safari, and Edge + +## Customization + +You can easily customize the animation by modifying: +- Colors in the CSS (change `rgba(0, 150, 255, ...)` values) +- Animation timing in the CSS `@keyframes` +- Number of heart layers by adding/removing HTML elements +- Particle effects in the JavaScript + +## License + +This project is open source and available under the MIT License. \ No newline at end of file diff --git a/love14/index.html b/love14/index.html new file mode 100644 index 00000000000..d23cdc2aa95 --- /dev/null +++ b/love14/index.html @@ -0,0 +1,24 @@ + + + + + + Glowing Heart Animation + + + +
+
+
+
+
+
+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/love14/script.js b/love14/script.js new file mode 100644 index 00000000000..dd07f32baab --- /dev/null +++ b/love14/script.js @@ -0,0 +1,213 @@ +// Heart Animation JavaScript +document.addEventListener('DOMContentLoaded', function() { + const hearts = document.querySelectorAll('.heart'); + const playButton = document.querySelector('.play-button'); + const container = document.querySelector('.container'); + + // Add click effect to hearts + hearts.forEach(heart => { + heart.addEventListener('click', function() { + createHeartBurst(this); + }); + }); + + // Play button functionality + playButton.addEventListener('click', function() { + toggleAnimation(); + }); + + // Add mouse move effect + container.addEventListener('mousemove', function(e) { + const rect = container.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + // Create subtle parallax effect + hearts.forEach((heart, index) => { + const speed = (index + 1) * 0.02; + const moveX = (x - rect.width / 2) * speed; + const moveY = (y - rect.height / 2) * speed; + + heart.style.transform = `rotate(-45deg) translate(${moveX}px, ${moveY}px)`; + }); + }); + + // Create heart burst effect + function createHeartBurst(heart) { + for (let i = 0; i < 8; i++) { + const particle = document.createElement('div'); + particle.className = 'heart-particle'; + particle.style.cssText = ` + position: absolute; + width: 10px; + height: 10px; + background: rgba(0, 150, 255, 0.8); + border-radius: 50%; + pointer-events: none; + z-index: 1000; + `; + + const angle = (i * 45) * Math.PI / 180; + const distance = 50; + const startX = heart.offsetLeft + heart.offsetWidth / 2; + const startY = heart.offsetTop + heart.offsetHeight / 2; + + particle.style.left = startX + 'px'; + particle.style.top = startY + 'px'; + + container.appendChild(particle); + + // Animate particle + setTimeout(() => { + const endX = startX + Math.cos(angle) * distance; + const endY = startY + Math.sin(angle) * distance; + + particle.style.transition = 'all 0.5s ease-out'; + particle.style.left = endX + 'px'; + particle.style.top = endY + 'px'; + particle.style.opacity = '0'; + particle.style.transform = 'scale(0)'; + + setTimeout(() => { + container.removeChild(particle); + }, 500); + }, 10); + } + } + + // Toggle animation + function toggleAnimation() { + const isPaused = hearts[0].style.animationPlayState === 'paused'; + + hearts.forEach(heart => { + heart.style.animationPlayState = isPaused ? 'running' : 'paused'; + }); + + // Change play button icon + const playIcon = playButton.querySelector('.play-icon'); + if (isPaused) { + playIcon.style.borderLeft = '15px solid rgba(255, 255, 255, 0.8)'; + playIcon.style.borderTop = '10px solid transparent'; + playIcon.style.borderBottom = '10px solid transparent'; + } else { + playIcon.style.borderLeft = 'none'; + playIcon.style.borderTop = 'none'; + playIcon.style.borderBottom = 'none'; + playIcon.style.border = '2px solid rgba(255, 255, 255, 0.8)'; + playIcon.style.width = '20px'; + playIcon.style.height = '20px'; + } + } + + // Add keyboard controls + document.addEventListener('keydown', function(e) { + switch(e.key) { + case ' ': + e.preventDefault(); + toggleAnimation(); + break; + case 'r': + case 'R': + resetAnimation(); + break; + } + }); + + // Reset animation + function resetAnimation() { + hearts.forEach(heart => { + heart.style.animation = 'none'; + heart.offsetHeight; // Trigger reflow + heart.style.animation = null; + }); + } + + // Add touch support for mobile + let touchStartTime = 0; + container.addEventListener('touchstart', function(e) { + touchStartTime = Date.now(); + }); + + container.addEventListener('touchend', function(e) { + const touchEndTime = Date.now(); + const touchDuration = touchEndTime - touchStartTime; + + if (touchDuration < 200) { + // Short tap - create burst + const touch = e.changedTouches[0]; + const element = document.elementFromPoint(touch.clientX, touch.clientY); + if (element && element.classList.contains('heart')) { + createHeartBurst(element); + } + } else { + // Long press - toggle animation + toggleAnimation(); + } + }); + + // Add window resize handler + window.addEventListener('resize', function() { + // Reset any transform effects + hearts.forEach(heart => { + heart.style.transform = 'rotate(-45deg)'; + }); + }); + + // Add some random sparkle effects + setInterval(() => { + if (Math.random() < 0.3) { + createRandomSparkle(); + } + }, 2000); + + function createRandomSparkle() { + const sparkle = document.createElement('div'); + sparkle.style.cssText = ` + position: absolute; + width: 4px; + height: 4px; + background: rgba(0, 150, 255, 1); + border-radius: 50%; + pointer-events: none; + z-index: 999; + left: ${Math.random() * 100}%; + top: ${Math.random() * 100}%; + animation: sparkle 1s ease-out forwards; + `; + + container.appendChild(sparkle); + + setTimeout(() => { + if (container.contains(sparkle)) { + container.removeChild(sparkle); + } + }, 1000); + } + + // Add sparkle animation to CSS + const style = document.createElement('style'); + style.textContent = ` + @keyframes sparkle { + 0% { + transform: scale(0) rotate(0deg); + opacity: 1; + } + 50% { + transform: scale(1) rotate(180deg); + opacity: 1; + } + 100% { + transform: scale(0) rotate(360deg); + opacity: 0; + } + } + `; + document.head.appendChild(style); + + console.log('Heart animation loaded successfully!'); + console.log('Controls:'); + console.log('- Click hearts to create burst effects'); + console.log('- Click play button or press SPACE to pause/resume'); + console.log('- Press R to reset animation'); + console.log('- Long press on mobile to toggle animation'); +}); \ No newline at end of file diff --git a/love14/style.css b/love14/style.css new file mode 100644 index 00000000000..58a965e7504 --- /dev/null +++ b/love14/style.css @@ -0,0 +1,259 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background-color: #000; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; + font-family: Arial, sans-serif; + overflow: hidden; +} + +.container { + position: relative; + width: 100%; + height: 100vh; + display: flex; + justify-content: center; + align-items: center; +} + +.heart-container { + position: relative; + width: 300px; + height: 300px; + display: flex; + justify-content: center; + align-items: center; +} + +.heart { + position: absolute; + width: 100px; + height: 100px; + background: transparent; + transform: rotate(-45deg); + animation: pulse 2s ease-in-out infinite; +} + +.heart::before, +.heart::after { + content: ''; + position: absolute; + width: 100px; + height: 100px; + background: inherit; + border-radius: 50%; +} + +.heart::before { + top: -50px; + left: 0; +} + +.heart::after { + top: 0; + left: 50px; +} + +/* Heart layers with different sizes and colors */ +.heart-1 { + width: 200px; + height: 200px; + background: rgba(0, 150, 255, 0.1); + border: 2px solid rgba(0, 150, 255, 0.3); + animation-delay: 0s; +} + +.heart-1::before, +.heart-1::after { + width: 200px; + height: 200px; +} + +.heart-1::before { + top: -100px; +} + +.heart-1::after { + left: 100px; +} + +.heart-2 { + width: 160px; + height: 160px; + background: rgba(0, 150, 255, 0.2); + border: 2px solid rgba(0, 150, 255, 0.4); + animation-delay: 0.4s; +} + +.heart-2::before, +.heart-2::after { + width: 160px; + height: 160px; +} + +.heart-2::before { + top: -80px; +} + +.heart-2::after { + left: 80px; +} + +.heart-3 { + width: 120px; + height: 120px; + background: rgba(0, 150, 255, 0.3); + border: 2px solid rgba(0, 150, 255, 0.5); + animation-delay: 0.8s; +} + +.heart-3::before, +.heart-3::after { + width: 120px; + height: 120px; +} + +.heart-3::before { + top: -60px; +} + +.heart-3::after { + left: 60px; +} + +.heart-4 { + width: 80px; + height: 80px; + background: rgba(0, 150, 255, 0.4); + border: 2px solid rgba(0, 150, 255, 0.6); + animation-delay: 1.2s; +} + +.heart-4::before, +.heart-4::after { + width: 80px; + height: 80px; +} + +.heart-4::before { + top: -40px; +} + +.heart-4::after { + left: 40px; +} + +.heart-5 { + width: 40px; + height: 40px; + background: rgba(0, 150, 255, 0.8); + border: 2px solid rgba(0, 150, 255, 1); + animation-delay: 1.6s; +} + +.heart-5::before, +.heart-5::after { + width: 40px; + height: 40px; +} + +.heart-5::before { + top: -20px; +} + +.heart-5::after { + left: 20px; +} + +/* Play button */ +.play-button { + position: absolute; + width: 60px; + height: 60px; + background: rgba(255, 255, 255, 0.1); + border: 2px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + transition: all 0.3s ease; + z-index: 10; +} + +.play-button:hover { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.5); + transform: scale(1.1); +} + +.play-icon { + width: 0; + height: 0; + border-left: 15px solid rgba(255, 255, 255, 0.8); + border-top: 10px solid transparent; + border-bottom: 10px solid transparent; + margin-left: 5px; +} + +/* Animations */ +@keyframes pulse { + 0%, 100% { + transform: rotate(-45deg) scale(1); + opacity: 0.7; + } + 50% { + transform: rotate(-45deg) scale(1.1); + opacity: 1; + } +} + +/* Glow effect */ +.heart { + box-shadow: + 0 0 20px rgba(0, 150, 255, 0.5), + 0 0 40px rgba(0, 150, 255, 0.3), + 0 0 60px rgba(0, 150, 255, 0.1); +} + +/* Particle effect */ +.heart::before, +.heart::after { + box-shadow: + 0 0 15px rgba(0, 150, 255, 0.4), + 0 0 30px rgba(0, 150, 255, 0.2); +} + +/* Responsive design */ +@media (max-width: 768px) { + .heart-container { + width: 200px; + height: 200px; + } + + .heart-1 { + width: 150px; + height: 150px; + } + + .heart-1::before, + .heart-1::after { + width: 150px; + height: 150px; + } + + .heart-1::before { + top: -75px; + } + + .heart-1::after { + left: 75px; + } +} \ No newline at end of file