// Geburtstagskarten-Webseite für Julian - Enhanced JavaScript document.addEventListener('DOMContentLoaded', function() { initMinigame(); initParticleEffects(); initScrollAnimations(); }); // Space Invaders Minigame class SpaceInvadersGame { constructor(canvas) { this.canvas = canvas; this.ctx = canvas.getContext('2d'); this.width = canvas.width; this.height = canvas.height; this.player = { x: this.width / 2 - 25, y: this.height - 60, width: 50, height: 30, speed: 5 }; this.bullets = []; this.aliens = []; this.alienBullets = []; this.particles = []; this.score = 0; this.lives = 3; this.aliensDestroyed = 0; this.totalAliens = 15; this.keys = {}; this.gameRunning = false; this.initAliens(); this.bindEvents(); } initAliens() { this.aliens = []; for (let row = 0; row < 3; row++) { for (let col = 0; col < 5; col++) { this.aliens.push({ x: col * 80 + 100, y: row * 60 + 50, width: 40, height: 30, alive: true, type: row // Different alien types }); } } } bindEvents() { document.addEventListener('keydown', (e) => { this.keys[e.keyCode] = true; if (e.keyCode === 32 || e.keyCode === 87) { // Spacebar OR W e.preventDefault(); this.shoot(); } }); document.addEventListener('keyup', (e) => { this.keys[e.keyCode] = false; }); } start() { this.gameRunning = true; this.gameLoop(); } gameLoop() { if (!this.gameRunning) return; this.update(); this.draw(); requestAnimationFrame(() => this.gameLoop()); } update() { // Player movement - Arrow keys OR WASD if ((this.keys[37] || this.keys[65]) && this.player.x > 0) { // Left arrow OR A this.player.x -= this.player.speed; } if ((this.keys[39] || this.keys[68]) && this.player.x < this.width - this.player.width) { // Right arrow OR D this.player.x += this.player.speed; } // Update bullets this.bullets = this.bullets.filter(bullet => { bullet.y -= 7; return bullet.y > 0; }); // Update alien bullets this.alienBullets = this.alienBullets.filter(bullet => { bullet.y += 4; return bullet.y < this.height; }); // Move aliens this.moveAliens(); // Alien shooting if (Math.random() < 0.02) { this.alienShoot(); } // Check collisions this.checkCollisions(); // Update particles this.updateParticles(); // Check win condition if (this.aliensDestroyed >= this.totalAliens) { this.gameWon(); } // Check lose conditions if (this.lives <= 0) { this.gameLost(); } // Check if aliens reached the bottom this.aliens.forEach(alien => { if (alien.alive && alien.y + alien.height >= this.player.y) { this.gameLost(); } }); } moveAliens() { // Initialize direction if not set if (this.alienDirection === undefined) { this.alienDirection = 1; } let moveDown = false; // Check if any alien hits the edge this.aliens.forEach(alien => { if (!alien.alive) return; if ((alien.x <= 0 && this.alienDirection < 0) || (alien.x >= this.width - alien.width && this.alienDirection > 0)) { moveDown = true; } }); if (moveDown) { // Move all aliens down and reverse direction this.aliens.forEach(alien => { if (alien.alive) { alien.y += 30; } }); this.alienDirection *= -1; } else { // Move aliens horizontally this.aliens.forEach(alien => { if (alien.alive) { alien.x += this.alienDirection * 1; } }); } } shoot() { this.bullets.push({ x: this.player.x + this.player.width / 2 - 2, y: this.player.y, width: 4, height: 10 }); } alienShoot() { const livingAliens = this.aliens.filter(alien => alien.alive); if (livingAliens.length > 0) { const shooter = livingAliens[Math.floor(Math.random() * livingAliens.length)]; this.alienBullets.push({ x: shooter.x + shooter.width / 2 - 2, y: shooter.y + shooter.height, width: 4, height: 10 }); } } checkCollisions() { // Bullet vs Aliens this.bullets.forEach((bullet, bulletIndex) => { this.aliens.forEach((alien, alienIndex) => { if (alien.alive && this.isColliding(bullet, alien)) { alien.alive = false; this.bullets.splice(bulletIndex, 1); this.aliensDestroyed++; this.score += (3 - alien.type) * 10; this.createExplosion(alien.x + alien.width/2, alien.y + alien.height/2); this.updateUI(); } }); }); // Alien bullets vs Player this.alienBullets.forEach((bullet, bulletIndex) => { if (this.isColliding(bullet, this.player)) { this.alienBullets.splice(bulletIndex, 1); this.lives--; this.createExplosion(this.player.x + this.player.width/2, this.player.y + this.player.height/2); this.updateUI(); } }); } isColliding(rect1, rect2) { return rect1.x < rect2.x + rect2.width && rect1.x + rect1.width > rect2.x && rect1.y < rect2.y + rect2.height && rect1.y + rect1.height > rect2.y; } createExplosion(x, y) { for (let i = 0; i < 8; i++) { this.particles.push({ x: x, y: y, vx: (Math.random() - 0.5) * 8, vy: (Math.random() - 0.5) * 8, life: 30, maxLife: 30 }); } } updateParticles() { this.particles = this.particles.filter(particle => { particle.x += particle.vx; particle.y += particle.vy; particle.life--; return particle.life > 0; }); } draw() { // Clear canvas this.ctx.fillStyle = 'rgba(0, 5, 15, 0.3)'; this.ctx.fillRect(0, 0, this.width, this.height); // Draw stars this.drawStars(); // Draw player this.ctx.fillStyle = '#00ffff'; this.ctx.fillRect(this.player.x, this.player.y, this.player.width, this.player.height); // Draw aliens this.aliens.forEach(alien => { if (alien.alive) { const colors = ['#ff6b6b', '#ffd700', '#00ff00']; this.ctx.fillStyle = colors[alien.type]; this.ctx.fillRect(alien.x, alien.y, alien.width, alien.height); // Alien eyes this.ctx.fillStyle = '#ffffff'; this.ctx.fillRect(alien.x + 8, alien.y + 8, 6, 6); this.ctx.fillRect(alien.x + 26, alien.y + 8, 6, 6); } }); // Draw bullets this.ctx.fillStyle = '#ffff00'; this.bullets.forEach(bullet => { this.ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height); }); // Draw alien bullets this.ctx.fillStyle = '#ff0000'; this.alienBullets.forEach(bullet => { this.ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height); }); // Draw particles this.particles.forEach(particle => { const alpha = particle.life / particle.maxLife; this.ctx.fillStyle = `rgba(255, 255, 0, ${alpha})`; this.ctx.fillRect(particle.x, particle.y, 3, 3); }); } drawStars() { this.ctx.fillStyle = '#ffffff'; for (let i = 0; i < 50; i++) { const x = (i * 37) % this.width; const y = (i * 73) % this.height; this.ctx.fillRect(x, y, 1, 1); } } updateUI() { document.getElementById('score').textContent = this.score; document.getElementById('aliensLeft').textContent = this.totalAliens - this.aliensDestroyed; document.getElementById('lives').textContent = '❤️'.repeat(this.lives); } gameWon() { this.gameRunning = false; setTimeout(() => { document.getElementById('minigameSection').style.display = 'none'; document.getElementById('giftSection').style.display = 'block'; initScratchCards(); showCelebration(); }, 1000); } gameLost() { this.gameRunning = false; setTimeout(() => { if (confirm('Game Over! Möchtest du es nochmal versuchen?')) { this.reset(); this.start(); } else { // Zurück zum Start-Button document.getElementById('gameContainer').style.display = 'none'; document.getElementById('startGameBtn').style.display = 'block'; } }, 1000); } reset() { this.score = 0; this.lives = 3; this.aliensDestroyed = 0; this.bullets = []; this.alienBullets = []; this.particles = []; this.alienDirection = 1; // Reset alien direction this.player.x = this.width / 2 - 25; // Reset player position this.initAliens(); this.updateUI(); } } function initMinigame() { const startBtn = document.getElementById('startGameBtn'); const gameContainer = document.getElementById('gameContainer'); const canvas = document.getElementById('gameCanvas'); let game; startBtn.addEventListener('click', () => { startBtn.style.display = 'none'; gameContainer.style.display = 'block'; game = new SpaceInvadersGame(canvas); game.start(); }); } function showCelebration() { const celebration = document.createElement('div'); celebration.innerHTML = `

🎉 MISSION ERFOLGREICH! 🎉

Herzlichen Glückwunsch!

Du hast alle Aliens besiegt und deine Geschenke freigeschaltet!

`; document.body.appendChild(celebration); } // Enhanced Scratch Card Functionality function initScratchCards() { const scratchCards = document.querySelectorAll('.scratch-card'); scratchCards.forEach(card => { const canvas = card.querySelector('.scratch-canvas'); const ctx = canvas.getContext('2d'); const hiddenKey = card.querySelector('.hidden-key'); const progressBar = card.querySelector('.progress-fill'); const progressText = card.querySelector('.progress-text'); let isDrawing = false; let scratchedPixels = 0; const totalPixels = canvas.width * canvas.height; const scratchRadius = 15; // Smaller radius for more precise scratching // Setup initial scratch surface setupScratchSurface(ctx, canvas, card); // Mouse events canvas.addEventListener('mousedown', startScratching); canvas.addEventListener('mousemove', scratch); canvas.addEventListener('mouseup', stopScratching); canvas.addEventListener('mouseleave', stopScratching); // Touch events for mobile canvas.addEventListener('touchstart', handleTouch, { passive: false }); canvas.addEventListener('touchmove', handleTouch, { passive: false }); canvas.addEventListener('touchend', stopScratching); function setupScratchSurface(ctx, canvas, card) { const isSpecial = card.classList.contains('special-scratch'); // Create scratch surface if (isSpecial) { // Gold gradient for special card const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); gradient.addColorStop(0, '#FFD700'); gradient.addColorStop(0.5, '#FFA500'); gradient.addColorStop(1, '#FF8C00'); ctx.fillStyle = gradient; } else { // Blue/gray gradient for regular cards const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); gradient.addColorStop(0, '#34495e'); gradient.addColorStop(0.5, '#2c3e50'); gradient.addColorStop(1, '#1a252f'); ctx.fillStyle = gradient; } ctx.fillRect(0, 0, canvas.width, canvas.height); // Add text overlay ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; ctx.font = 'bold 16px Orbitron, monospace'; ctx.textAlign = 'center'; ctx.fillText('🎮 STEAM KEY 🎮', canvas.width / 2, canvas.height / 2 - 10); ctx.font = '12px Inter, sans-serif'; ctx.fillText('Rubbeln zum Freischalten!', canvas.width / 2, canvas.height / 2 + 15); // Add sparkle effects addSparkles(ctx, canvas, isSpecial); } function addSparkles(ctx, canvas, isSpecial) { const sparkleCount = 15; for (let i = 0; i < sparkleCount; i++) { const x = Math.random() * canvas.width; const y = Math.random() * canvas.height; const size = Math.random() * 3 + 1; ctx.fillStyle = isSpecial ? 'rgba(255, 255, 255, 0.8)' : 'rgba(0, 255, 255, 0.6)'; ctx.beginPath(); ctx.arc(x, y, size, 0, 2 * Math.PI); ctx.fill(); // Add cross sparkle effect ctx.strokeStyle = ctx.fillStyle; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(x - size * 2, y); ctx.lineTo(x + size * 2, y); ctx.moveTo(x, y - size * 2); ctx.lineTo(x, y + size * 2); ctx.stroke(); } } function startScratching(e) { isDrawing = true; scratch(e); } function scratch(e) { if (!isDrawing) return; const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; scratchAt(x, y); } function handleTouch(e) { e.preventDefault(); const touch = e.touches[0]; if (!touch) return; const rect = canvas.getBoundingClientRect(); const x = touch.clientX - rect.left; const y = touch.clientY - rect.top; if (e.type === 'touchstart') { isDrawing = true; } if (isDrawing) { scratchAt(x, y); } } function scratchAt(x, y) { // Create circular scratch with gradient for more realistic effect ctx.globalCompositeOperation = 'destination-out'; const gradient = ctx.createRadialGradient(x, y, 0, x, y, scratchRadius); gradient.addColorStop(0, 'rgba(0,0,0,1)'); gradient.addColorStop(0.7, 'rgba(0,0,0,0.8)'); gradient.addColorStop(1, 'rgba(0,0,0,0.3)'); ctx.fillStyle = gradient; ctx.beginPath(); ctx.arc(x, y, scratchRadius, 0, 2 * Math.PI); ctx.fill(); // More precise calculation of scratched pixels scratchedPixels += Math.PI * scratchRadius * scratchRadius * 0.7; // Update progress const scratchPercent = Math.min(scratchedPixels / (totalPixels * 0.65), 1); progressBar.style.width = (scratchPercent * 100) + '%'; progressText.textContent = Math.floor(scratchPercent * 100) + '% freigerubbelt'; // Require 65% to be scratched for reveal if (scratchPercent >= 1) { revealKey(card); } // Add enhanced scratch particles createScratchParticles(x, y, card); } function stopScratching() { isDrawing = false; } function revealKey(card) { const canvas = card.querySelector('.scratch-canvas'); const hiddenKey = card.querySelector('.hidden-key'); const instruction = card.querySelector('.scratch-instruction'); const progressContainer = card.querySelector('.scratch-progress'); // Clear entire canvas canvas.style.opacity = '0'; // Update instruction instruction.innerHTML = '🎉 Steam-Key freigerubbelt! 🎉'; instruction.style.background = 'rgba(0, 255, 0, 0.3)'; // Create key display below the instruction const keyDisplay = document.createElement('div'); keyDisplay.className = 'revealed-key'; // Check if this is the special Elden Ring card const isSpecial = card.classList.contains('special-scratch'); keyDisplay.style.cssText = ` text-align: center; padding: 15px; background: rgba(0, 0, 0, 0.8); font-family: 'Orbitron', monospace; font-weight: bold; font-size: 1.4rem; color: ${isSpecial ? '#ffd700' : '#00ffff'}; text-shadow: 0 0 15px ${isSpecial ? '#ffd700' : '#00ffff'}; letter-spacing: 2px; border-top: 2px solid ${isSpecial ? '#ffd700' : '#00ffff'}; backdrop-filter: blur(5px); `; // Insert key display after instruction instruction.parentNode.insertBefore(keyDisplay, instruction.nextSibling); // Add celebration effect createCelebrationEffect(card); // Generate realistic looking Steam key generateSteamKey(keyDisplay, card); } }); } function createScratchParticles(x, y, card) { const particle = document.createElement('div'); particle.className = 'scratch-particle'; particle.style.position = 'absolute'; particle.style.left = x + 'px'; particle.style.top = y + 'px'; particle.style.width = '4px'; particle.style.height = '4px'; particle.style.borderRadius = '50%'; particle.style.backgroundColor = card.classList.contains('special-scratch') ? '#FFD700' : '#34495e'; particle.style.pointerEvents = 'none'; particle.style.animation = 'scratchParticle 0.5s ease-out forwards'; card.appendChild(particle); setTimeout(() => { if (particle.parentNode) { particle.parentNode.removeChild(particle); } }, 500); } function createCelebrationEffect(card) { const celebration = document.createElement('div'); celebration.className = 'celebration-effect'; celebration.innerHTML = '🎉✨🎁✨🎉'; celebration.style.position = 'absolute'; celebration.style.top = '-20px'; celebration.style.left = '50%'; celebration.style.transform = 'translateX(-50%)'; celebration.style.fontSize = '2rem'; celebration.style.animation = 'celebrate 2s ease-out forwards'; celebration.style.pointerEvents = 'none'; celebration.style.zIndex = '100'; card.style.position = 'relative'; card.appendChild(celebration); setTimeout(() => { if (celebration.parentNode) { celebration.parentNode.removeChild(celebration); } }, 2000); } function generateSteamKey(element, card) { const gameType = card.getAttribute('data-game'); // Get key from config or generate fallback let finalKey; if (window.STEAM_KEYS && window.STEAM_KEYS[gameType]) { finalKey = window.STEAM_KEYS[gameType]; } else { // Fallback key generation if config not loaded let keyPrefix; switch(gameType) { case 'atomic-heart': keyPrefix = 'AH9X2'; break; case 'prey': keyPrefix = 'PREY4'; break; case 'elden-ring': keyPrefix = 'ELDRG'; break; default: keyPrefix = 'GAME1'; } const segments = [ keyPrefix, generateKeySegment(5), generateKeySegment(5) ]; finalKey = segments.join('-'); } // Animated key reveal let displayKey = ''; let currentIndex = 0; const revealInterval = setInterval(() => { if (currentIndex < finalKey.length) { displayKey += finalKey[currentIndex]; element.textContent = displayKey + '_'; currentIndex++; } else { element.textContent = finalKey; clearInterval(revealInterval); element.style.animation = 'keyReveal 1s ease-out forwards'; } }, 100); } function generateKeySegment(length = 5) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let result = ''; for (let i = 0; i < length; i++) { result += chars.charAt(Math.floor(Math.random() * chars.length)); } return result; } // Particle Effects function initParticleEffects() { createFloatingParticles(); } function createFloatingParticles() { const particleContainer = document.createElement('div'); particleContainer.className = 'floating-particles'; particleContainer.style.position = 'fixed'; particleContainer.style.top = '0'; particleContainer.style.left = '0'; particleContainer.style.width = '100%'; particleContainer.style.height = '100%'; particleContainer.style.pointerEvents = 'none'; particleContainer.style.zIndex = '-1'; document.body.appendChild(particleContainer); // Create gaming-themed particles const particles = ['🎮', '⭐', '🚀', '👾', '🎁', '✨', '🎉', '🎊', '🎈', '🎂']; setInterval(() => { if (particleContainer.children.length < 10) { // Rarely (10% chance) create Julian's image instead of emoji - adjusted for better visibility if (Math.random() < 0.05) { createJulianParticle(particleContainer); } else { createParticle(particleContainer, particles); } } }, 2000); } function createParticle(container, particles) { const particle = document.createElement('div'); const emoji = particles[Math.floor(Math.random() * particles.length)]; particle.textContent = emoji; particle.style.position = 'absolute'; particle.style.fontSize = Math.random() * 20 + 10 + 'px'; particle.style.left = Math.random() * 100 + '%'; particle.style.top = '100%'; particle.style.opacity = Math.random() * 0.7 + 0.3; particle.style.animation = `floatUp ${Math.random() * 10 + 10}s linear forwards`; container.appendChild(particle); setTimeout(() => { if (particle.parentNode) { particle.parentNode.removeChild(particle); } }, 20000); } function createJulianParticle(container) { console.log('🎂 Julian particle wird erstellt!'); // Debug const particle = document.createElement('div'); const julianImg = document.createElement('img'); // Julian's image setup julianImg.src = 'images/julian.png'; julianImg.style.width = Math.random() * 30 + 40 + 'px'; // 40-70px size julianImg.style.height = 'auto'; julianImg.style.borderRadius = '50%'; julianImg.style.border = '3px solid #ffd700'; julianImg.style.boxShadow = '0 0 20px rgba(255, 215, 0, 0.8)'; julianImg.alt = '🎂'; // Success callback julianImg.onload = function() { console.log('✅ Julian Bild erfolgreich geladen!'); }; // Fallback if image doesn't load julianImg.onerror = function() { console.log('❌ Julian Bild konnte nicht geladen werden, verwende Fallback'); particle.innerHTML = '🎂'; particle.style.fontSize = '50px'; particle.style.textAlign = 'center'; particle.style.lineHeight = particle.style.width; }; particle.appendChild(julianImg); particle.style.position = 'absolute'; particle.style.left = Math.random() * 100 + '%'; particle.style.top = '100%'; particle.style.opacity = '1'; // Vollständig sichtbar für Debug particle.style.zIndex = '10'; // Höhere z-index für Sichtbarkeit particle.style.animation = `floatUp ${Math.random() * 8 + 12}s linear forwards`; container.appendChild(particle); // Special celebration when Julian appears setTimeout(() => { createJulianCelebration(); }, 1000); setTimeout(() => { if (particle.parentNode) { particle.parentNode.removeChild(particle); } }, 20000); } function createJulianCelebration() { // Create small burst of birthday emojis around Julian const celebrationEmojis = ['🎂', '🎉', '🎊', '🎁', '🥳']; for (let i = 0; i < 5; i++) { setTimeout(() => { const celebParticle = document.createElement('div'); celebParticle.textContent = celebrationEmojis[Math.floor(Math.random() * celebrationEmojis.length)]; celebParticle.style.position = 'fixed'; celebParticle.style.left = Math.random() * 100 + '%'; celebParticle.style.top = Math.random() * 100 + '%'; celebParticle.style.fontSize = '25px'; celebParticle.style.pointerEvents = 'none'; celebParticle.style.zIndex = '100'; celebParticle.style.animation = 'celebrate 2s ease-out forwards'; document.body.appendChild(celebParticle); setTimeout(() => { if (celebParticle.parentNode) { celebParticle.parentNode.removeChild(celebParticle); } }, 2000); }, i * 200); } } // Scroll Animations function initScrollAnimations() { const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -100px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; } }); }, observerOptions); // Observe game cards for scroll animations document.querySelectorAll('.game-card').forEach(card => { card.style.opacity = '0'; card.style.transform = 'translateY(50px)'; card.style.transition = 'all 0.8s ease'; observer.observe(card); }); } // Add CSS animations dynamically const style = document.createElement('style'); style.textContent = ` @keyframes scratchParticle { 0% { transform: scale(1); opacity: 1; } 100% { transform: scale(0) translateY(-20px); opacity: 0; } } @keyframes celebrate { 0% { transform: translateX(-50%) translateY(0) scale(1); opacity: 0; } 50% { transform: translateX(-50%) translateY(-30px) scale(1.2); opacity: 1; } 100% { transform: translateX(-50%) translateY(-50px) scale(0.8); opacity: 0; } } @keyframes keyReveal { 0% { transform: scale(0.8); opacity: 0; } 50% { transform: scale(1.1); } 100% { transform: scale(1); opacity: 1; } } @keyframes floatUp { 0% { transform: translateY(0); opacity: 0.7; } 10% { opacity: 1; } 90% { opacity: 1; } 100% { transform: translateY(-100vh); opacity: 0; } } `; document.head.appendChild(style); // Easter Egg: Konami Code let konamiSequence = []; const konamiCode = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65]; // ↑↑↓↓←→←→BA document.addEventListener('keydown', function(e) { konamiSequence.push(e.keyCode); if (konamiSequence.length > konamiCode.length) { konamiSequence.shift(); } if (konamiSequence.length === konamiCode.length && konamiSequence.every((key, i) => key === konamiCode[i])) { activateEasterEgg(); konamiSequence = []; } }); function activateEasterEgg() { // Secret birthday surprise const surprise = document.createElement('div'); surprise.innerHTML = `

🎮 GEHEIMER BONUS! 🎮

Du hast den Konami-Code entdeckt!

Extra Geburtstagswünsche für Julian! 🎉

`; document.body.appendChild(surprise); // Add extra particles for (let i = 0; i < 20; i++) { setTimeout(() => { createParticle(document.querySelector('.floating-particles'), ['🎉', '🎊', '🎁', '⭐']); }, i * 100); } } // Enhanced CSS Animations const additionalStyles = ` @keyframes scratchParticle { 0% { transform: scale(1) rotate(0deg); opacity: 1; } 100% { transform: scale(0) rotate(360deg) translateY(-30px); opacity: 0; } } @keyframes celebrate { 0% { transform: translateX(-50%) translateY(0) scale(1) rotate(0deg); opacity: 0; } 25% { transform: translateX(-50%) translateY(-20px) scale(1.1) rotate(5deg); opacity: 1; } 75% { transform: translateX(-50%) translateY(-40px) scale(1.2) rotate(-5deg); opacity: 1; } 100% { transform: translateX(-50%) translateY(-60px) scale(0.9) rotate(0deg); opacity: 0; } } @keyframes keyReveal { 0% { transform: scale(0.5) rotateY(90deg); opacity: 0; } 50% { transform: scale(1.1) rotateY(45deg); } 100% { transform: scale(1) rotateY(0deg); opacity: 1; } } @keyframes floatUp { 0% { transform: translateY(0) rotate(0deg); opacity: 0.8; } 50% { opacity: 1; } 100% { transform: translateY(-120vh) rotate(360deg); opacity: 0; } } @keyframes gameVictory { 0% { transform: scale(1); } 25% { transform: scale(1.1); } 50% { transform: scale(0.9); } 75% { transform: scale(1.05); } 100% { transform: scale(1); } } @keyframes julianSpin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .scratch-particle { animation: scratchParticle 0.8s ease-out forwards !important; } .celebration-effect { animation: celebrate 3s ease-out forwards !important; } .victory-animation { animation: gameVictory 2s ease-in-out infinite; } `; const styleSheet = document.createElement('style'); styleSheet.textContent = additionalStyles; document.head.appendChild(styleSheet); console.log('🎮 Enhanced Geburtstagskarte für Julian geladen! 🎂'); console.log('🚀 Spiele Space Invaders um die geheimen Geschenke freizuschalten!'); console.log('💡 Tipp: Versuche den Konami-Code für eine Überraschung! ↑↑↓↓←→←→BA');