commit 5355e725c194976660ba1eb19dab3dc90d5283d4 Author: SimolZimol <70102430+SimolZimol@users.noreply.github.com> Date: Fri Oct 31 16:33:22 2025 +0100 new file: .gitignore new file: README.md new file: images/atomic-heart.png new file: images/julian.png new file: images/prey.png new file: index.html new file: keys.example.js new file: script.js new file: style.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bc85e94 --- /dev/null +++ b/.gitignore @@ -0,0 +1,60 @@ +# Geburtstagskarte - Git Ignore File + +# Steam Keys (WICHTIG: Niemals committen!) +.env +keys.js + +# Backup der originalen keys.js (falls vorhanden) +keys.js.bak +keys.backup.js + +# Temporäre Dateien +*.tmp +*.temp +.DS_Store +Thumbs.db + +# Editor-spezifische Dateien +.vscode/ +.idea/ +*.sublime-project +*.sublime-workspace + +# Node.js (falls später hinzugefügt) +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Betriebssystem-Dateien +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Persönliche Notizen oder Screenshots +notes.txt +screenshots/ +test/ + +# Bilder sind OK zum committen (außer persönliche Screenshots) +# images/ - Ordner mit Spielbildern bleibt im Repo + +# Backup-Dateien +*.bak +*~ +*.swp +*.swo + +# Logs +*.log +logs/ + +# Komprimierte Dateien (falls Screenshots oder Backups erstellt werden) +*.zip +*.rar +*.7z +*.tar.gz \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a6f9a2 --- /dev/null +++ b/README.md @@ -0,0 +1,92 @@ +# 🎮 Julian's Geburtstagskarte + +Eine interaktive Geburtstagskarte mit Space Invaders Minigame und Rubbelkarten für Steam-Keys! + +## 📋 Setup-Anleitung + +### Steam-Keys eintragen: + +1. **Kopiere `keys.example.js` zu `keys.js`**: + ```bash + copy keys.example.js keys.js + ``` +2. **Öffne `keys.js`** in einem Texteditor +3. **Ersetze die Platzhalter-Keys** mit den echten Steam-Keys: + ```javascript + const STEAM_KEYS = { + 'atomic-heart': 'DEIN-ATOMIC-HEART-KEY', + 'prey': 'DEIN-PREY-KEY', + 'elden-ring': 'DEIN-ELDEN-RING-KEY' + }; + ``` +4. **Speichere die Datei** (wird automatisch von .gitignore geschützt) + +### Alternative: .env Datei verwenden: +- Bearbeite die `.env` Datei und trage dort die Keys ein +- Die Keys werden automatisch geladen + +## 🎮 Spielanleitung + +### Space Invaders: +- **Bewegung**: ← → Pfeiltasten ODER A D Tasten +- **Schießen**: Leertaste ODER W Taste +- **Ziel**: Alle 15 Aliens besiegen um die Geschenke freizuschalten + +### Rubbelkarten: +- **65% der Karte** muss freigerubbelt werden +- **Fortschrittsbalken** zeigt den aktuellen Stand +- **Echte Steam-Keys** werden nach dem Rubbeln enthüllt + +## 🎁 Enthaltene Spiele: +1. **Atomic Heart** - Sowjetisches Sci-Fi Abenteuer +2. **Prey** - Weltraum-Horror Thriller +3. **Elden Ring** 👑 - Das Hauptgeschenk! FromSoftware Meisterwerk + +## 🛠 Technische Details: +- Vollständig in HTML5, CSS3 und JavaScript +- Funktioniert offline nach dem ersten Laden +- Responsive Design für Desktop und Mobile +- Canvas-basiertes Space Invaders Spiel +- Erweiterte Rubbelkarten mit Fortschrittsanzeige + +## 🎉 Features: +- ✅ Space Invaders Minigame (15 Aliens) +- ✅ WASD + Pfeiltasten Steuerung +- ✅ Erweiterte Rubbelkarten (65% erforderlich) +- ✅ Konfigurierbare Steam-Keys +- ✅ Partikeleffekte und Animationen +- ✅ Easter Egg (Konami-Code) +- ✅ Mobile Touch-Support +- ✅ **Julian Easter Egg**: Seltenes schwebendes Julian-Bild (5% Chance) mit Celebration-Effekt! 🎂 + +## � Git-Sicherheit: + +⚠️ **WICHTIG**: Die `.gitignore` Datei schützt automatisch: +- `keys.js` - Enthält die echten Steam-Keys +- `.env` - Alternative Konfigurationsdatei +- Alle temporären und persönlichen Dateien + +✅ **Sicher zum Committen**: +- `keys.example.js` - Beispiel-Template ohne echte Keys +- Alle anderen Projektdateien + +## 📁 Projektstruktur: +``` +📁 geburstags karte/ +├── 🌐 index.html +├── 🎨 style.css +├── 🎮 script.js +├── 🔑 keys.example.js (Template - sicher) +├── 🔑 keys.js (Echte Keys - gitignore geschützt) +├── ⚙️ .env (Alternative Config - gitignore geschützt) +├── 🚫 .gitignore (Schutz für sensible Daten) +├── 📖 README.md +└── 📁 images/ + ├── 🖼️ atomic-heart.png (Hover-Bild) + ├── 🖼️ prey.png (Hover-Bild) + └── 🎂 julian.png (Easter Egg - seltenes schwebendes Bild) +``` + +## �💝 Von Simon mit Liebe gemacht! ❤️ + +Alles Gute zum Geburtstag, Julian! 🎂 \ No newline at end of file diff --git a/images/atomic-heart.png b/images/atomic-heart.png new file mode 100644 index 0000000..3f13c6b Binary files /dev/null and b/images/atomic-heart.png differ diff --git a/images/julian.png b/images/julian.png new file mode 100644 index 0000000..7bcc6cc Binary files /dev/null and b/images/julian.png differ diff --git a/images/prey.png b/images/prey.png new file mode 100644 index 0000000..d123e4a Binary files /dev/null and b/images/prey.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..84a9b78 --- /dev/null +++ b/index.html @@ -0,0 +1,176 @@ + + + + + + 🎮 Alles Gute zum Geburtstag, Julian! 🎂 + + + + +
+
+
+
+
+

ALLES GUTE ZUM GEBURTSTAG

+

JULIAN

+
+
🎂 1. November 2025 🎂
+
Mit Liebe von Simon ❤️
+
+ + +
+
+

🚀 SPIELE SPACE INVADERS UM DEINE GESCHENKE FREIZUSCHALTEN! 🚀

+

Besiege 15 Aliens um die geheimen Spiele zu enthüllen!

+ +
+ +
+ +
+
+

🎉 Herzlichen Glückwunsch, Julian! 🎉

+

Du hast das Minigame gemeistert! Hier sind deine drei fantastischen Spiele! + Tauche ein in epische Welten voller Abenteuer und Geheimnisse...

+
+ +
+ +
+
+
+ Atomic Heart Cover + Atomic Heart Hover +
+
+
ATOMIC HEART
+
+ Ein surreales Abenteuer in einer alternativen sowjetischen Realität voller Roboter und Geheimnisse +
+
+
+
+

🤖 ATOMIC HEART

+

Erkunde eine bizarre Welt voller mechanischer Wunder in der Sowjetunion der 1950er Jahre! Kämpfe gegen Roboter und entdecke dunkle Geheimnisse!

+
+ +
XXXXX-XXXXX-XXXXX
+
🎮 Rubbel vorsichtig für deinen Steam-Key!
+
+
+ 0% freigerubbelt +
+
+ + 🎮 Auf Steam ansehen + +
+
+ + +
+
+
+ Prey Cover + Prey Hover +
+
+
PREY
+
+ Überlebe auf der Raumstation Talos I gegen außerirdische Bedrohungen +
+
+
+
+

👽 PREY

+

Kämpfe ums Überleben auf einer von mysteriösen Aliens überrannten Raumstation. Nutze außergewöhnliche Fähigkeiten und jede Entscheidung zählt!

+
+ +
YYYYY-YYYYY-YYYYY
+
🎮 Rubbel vorsichtig für deinen Steam-Key!
+
+
+ 0% freigerubbelt +
+
+ + 🎮 Auf Steam ansehen + +
+
+ + +
+
👑 HAUPTGESCHENK 👑
+
+
+ Elden Ring Cover + Elden Ring Screenshot +
+
+
ELDEN RING
+
+ Das legendäre Dark Souls Meisterwerk von FromSoftware in einer offenen Welt! +
+
+
+
+
+

� ELDEN RING

+

Das absolut epische Meisterwerk! Erkunde die Lands Between in diesem Dark Fantasy-Abenteuer von FromSoftware und George R.R. Martin!

+
+ +
ZZZZZ-ZZZZZ-ZZZZZ
+
� Das Königliche Siegel - Rubbel mit Bedacht!
+
+
+ 0% freigerubbelt +
+
+ + 👑 Auf Steam ansehen + +
+
+
+ +
+
+

Herzlichen Glückwunsch zum Geburtstag

+

Lieber Julian, ich hoffe diese drei Super Spiele dir unzählige Stunden voller Spaß bereiten, Spannung und unvergesslicher Abenteuer! + Lass dich von den fantastischen Welten verzaubern und genieße jeden einzelnen Moment des Gamings.

+

Möge dein neues Lebensjahr genauso legendär werden wie die 8 davor!

+
+
Mit ganz viel Liebe und den allerbesten Wünschen
+
Simon der allerbesten ❤️
+
+
+
+
+ + +
+ + + + + \ No newline at end of file diff --git a/keys.example.js b/keys.example.js new file mode 100644 index 0000000..8938394 --- /dev/null +++ b/keys.example.js @@ -0,0 +1,20 @@ +// Steam Keys Configuration - BEISPIEL DATEI +// Kopiere diese Datei zu "keys.js" und trage die echten Steam-Keys ein + +const STEAM_KEYS = { + // Ersetze diese Beispiel-Keys mit den echten Steam-Keys: + 'atomic-heart': 'XXXXX-XXXXX-XXXXX', + 'prey': 'YYYYY-YYYYY-YYYYY', + 'elden-ring': 'ZZZZZ-ZZZZZ-ZZZZZ' +}; + +// Diese Datei wird von script.js geladen +window.STEAM_KEYS = STEAM_KEYS; + +/* +ANLEITUNG: +1. Kopiere diese Datei und benenne sie in "keys.js" um +2. Ersetze die XXXXX, YYYYY, ZZZZZ mit den echten Steam-Keys +3. Speichere die Datei +4. Die keys.js wird von .gitignore ignoriert und nicht committet +*/ \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..129603c --- /dev/null +++ b/script.js @@ -0,0 +1,1051 @@ +// 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'); \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..4d26df6 --- /dev/null +++ b/style.css @@ -0,0 +1,758 @@ +/* Geburtstagskarten-Webseite für Julian - Enhanced Styles */ + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: 'Inter', sans-serif; + background: + radial-gradient(circle at 20% 80%, rgba(120, 119, 198, 0.3) 0%, transparent 50%), + radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%), + radial-gradient(circle at 40% 40%, rgba(120, 198, 119, 0.2) 0%, transparent 50%), + linear-gradient(135deg, #0f0f23 0%, #1a1a2e 35%, #16213e 70%, #0f3460 100%); + color: #ffffff; + overflow-x: hidden; + min-height: 100vh; + position: relative; +} + +.fog-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: + radial-gradient(ellipse at center, transparent 0%, rgba(0,0,0,0.1) 50%, rgba(0,0,0,0.3) 100%); + pointer-events: none; + z-index: 1; + animation: fogDrift 30s ease-in-out infinite; +} + +@keyframes fogDrift { + 0%, 100% { opacity: 0.3; } + 50% { opacity: 0.6; } +} + +/* Sternen-Hintergrund */ +.stars { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: + radial-gradient(2px 2px at 20px 30px, #fff, transparent), + radial-gradient(2px 2px at 40px 70px, rgba(255,255,255,0.8), transparent), + radial-gradient(1px 1px at 90px 40px, #fff, transparent), + radial-gradient(1px 1px at 130px 80px, rgba(255,255,255,0.6), transparent), + radial-gradient(2px 2px at 160px 30px, #fff, transparent); + background-repeat: repeat; + background-size: 200px 100px; + animation: twinkle 20s linear infinite; + z-index: -1; +} + +@keyframes twinkle { + 0% { transform: translateY(0); } + 100% { transform: translateY(-100px); } +} + +.container { + max-width: 1200px; + margin: 0 auto; + padding: 20px; + position: relative; + z-index: 1; +} + +/* Header Styles */ +.birthday-header { + text-align: center; + margin-bottom: 50px; + padding: 40px 0; +} + +.glitch-effect { + position: relative; +} + +.main-title, .name-title { + font-family: 'Orbitron', monospace; + font-weight: 900; + text-transform: uppercase; + position: relative; + display: inline-block; +} + +.main-title { + font-size: clamp(2rem, 5vw, 4rem); + color: #00ffff; + text-shadow: + 0 0 10px #00ffff, + 0 0 20px #00ffff, + 0 0 30px #00ffff; + animation: glow 2s ease-in-out infinite alternate; + margin-bottom: 10px; +} + +.name-title { + font-size: clamp(3rem, 8vw, 6rem); + color: #ff6b6b; + text-shadow: + 0 0 15px #ff6b6b, + 0 0 30px #ff6b6b, + 0 0 45px #ff6b6b; + animation: glow-red 2s ease-in-out infinite alternate; +} + +@keyframes glow { + from { text-shadow: 0 0 10px #00ffff, 0 0 20px #00ffff, 0 0 30px #00ffff; } + to { text-shadow: 0 0 20px #00ffff, 0 0 30px #00ffff, 0 0 40px #00ffff; } +} + +@keyframes glow-red { + from { text-shadow: 0 0 15px #ff6b6b, 0 0 30px #ff6b6b, 0 0 45px #ff6b6b; } + to { text-shadow: 0 0 25px #ff6b6b, 0 0 40px #ff6b6b, 0 0 55px #ff6b6b; } +} + +.date { + font-size: 1.5rem; + color: #ffd700; + margin-top: 20px; + font-weight: 600; + text-shadow: 0 0 10px #ffd700; +} + +.from-signature { + font-size: 1.2rem; + color: #ff6b6b; + margin-top: 15px; + font-style: italic; + text-shadow: 0 0 8px #ff6b6b; +} + +/* Minigame Section */ +.minigame-section { + text-align: center; + margin: 50px 0; + padding: 40px 20px; + background: rgba(0, 20, 40, 0.6); + border-radius: 20px; + backdrop-filter: blur(10px); + border: 2px solid rgba(0, 255, 255, 0.3); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3); +} + +.minigame-intro h2 { + font-family: 'Orbitron', monospace; + color: #00ffff; + text-shadow: 0 0 20px #00ffff; + margin-bottom: 20px; + font-size: 2rem; +} + +.minigame-intro p { + font-size: 1.3rem; + margin-bottom: 30px; + color: #e0e0e0; +} + +.start-game-btn { + font-family: 'Orbitron', monospace; + font-size: 1.4rem; + font-weight: bold; + padding: 15px 40px; + background: linear-gradient(45deg, #ff6b6b, #ff8e8e); + color: white; + border: none; + border-radius: 50px; + cursor: pointer; + text-transform: uppercase; + box-shadow: 0 10px 30px rgba(255, 107, 107, 0.4); + transition: all 0.3s ease; + position: relative; + overflow: hidden; +} + +.start-game-btn:hover { + transform: translateY(-5px); + box-shadow: 0 15px 40px rgba(255, 107, 107, 0.6); +} + +.start-game-btn:before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); + transition: left 0.5s; +} + +.start-game-btn:hover:before { + left: 100%; +} + +.game-container { + margin-top: 30px; +} + +.game-ui { + display: flex; + justify-content: space-around; + margin-bottom: 20px; + font-family: 'Orbitron', monospace; + font-size: 1.2rem; +} + +.game-ui > div { + background: rgba(0, 0, 0, 0.5); + padding: 10px 20px; + border-radius: 10px; + border: 1px solid #00ffff; +} + +#gameCanvas { + border: 3px solid #00ffff; + border-radius: 15px; + background: radial-gradient(ellipse at center, #001122 0%, #000511 100%); + box-shadow: 0 0 30px #00ffff; +} + +.game-controls { + margin-top: 20px; + font-size: 1.1rem; + color: #cccccc; +} + +/* Intro Text */ +.intro-text { + text-align: center; + max-width: 600px; + margin: 0 auto 50px; + font-size: 1.2rem; + line-height: 1.6; + color: #e0e0e0; +} + +/* Games Grid */ +.games-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); + gap: 30px; + margin-bottom: 50px; +} + +.game-card { + background: rgba(255, 255, 255, 0.05); + border-radius: 20px; + overflow: hidden; + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3); + transition: all 0.3s ease; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + position: relative; +} + +.game-card:hover { + transform: translateY(-10px); + box-shadow: 0 25px 50px rgba(0, 0, 0, 0.4); +} + +.game-card.special-gift { + border: 2px solid #ffd700; + box-shadow: 0 15px 35px rgba(255, 215, 0, 0.3); +} + +.game-card.special-gift:hover { + box-shadow: 0 25px 50px rgba(255, 215, 0, 0.5); +} + +.special-badge { + position: absolute; + top: -10px; + right: -10px; + background: linear-gradient(45deg, #ffd700, #ffed4e); + color: #000; + padding: 8px 16px; + border-radius: 20px; + font-weight: bold; + font-size: 0.9rem; + z-index: 10; + box-shadow: 0 5px 15px rgba(255, 215, 0, 0.4); + animation: pulse 2s infinite; +} + +@keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } +} + +.game-image { + position: relative; + overflow: hidden; + height: 250px; +} + +.image-stack { + position: relative; + width: 100%; + height: 100%; +} + +.game-cover, .game-screenshot { + position: absolute; + width: 100%; + height: 100%; + object-fit: cover; + transition: all 0.5s ease; +} + +.game-cover { + z-index: 2; + opacity: 1; + transform: scale(0.95); /* Leicht rausgezoomt für bessere Sicht */ +} + +.game-screenshot { + z-index: 1; + opacity: 0; + transform: scale(1.05); /* Weniger Zoom beim Hover */ +} + +.game-card:hover .game-cover { + opacity: 0; + transform: scale(0.85); /* Mehr rauszoomen beim Hover */ +} + +.game-card:hover .game-screenshot { + opacity: 1; + transform: scale(0.95); /* Auch Screenshots weniger gezoomt */ +} + +/* Spezielle Anpassungen für Atomic Heart und Prey */ +.atomic-heart .game-cover, +.prey .game-cover { + transform: scale(0.9); /* Steam Cover leicht rausgezoomt */ + object-fit: cover; /* Normal für Steam-Bilder */ +} + +/* Hover-Bilder (deine neuen Bilder) anders behandeln */ +.atomic-heart .game-screenshot, +.prey .game-screenshot { + object-fit: contain; /* Bessere Darstellung für deine PNG-Bilder */ + background: linear-gradient(135deg, rgba(0,0,0,0.1), rgba(0,0,0,0.2)); + transform: scale(1.1); +} + +.atomic-heart:hover .game-cover, +.prey:hover .game-cover { + transform: scale(0.8); /* Steam Cover beim Hover */ +} + +.atomic-heart:hover .game-screenshot, +.prey:hover .game-screenshot { + transform: scale(0.9); /* Deine Bilder beim Hover optimal anzeigen */ +} + +/* Elden Ring bleibt unverändert */ +.elden-ring .game-cover, +.elden-ring .game-screenshot { + object-fit: cover; +} + +/* Elden Ring Golden Particles */ +.golden-particles { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + overflow: hidden; +} + +.elden-ring .golden-particles::before, +.elden-ring .golden-particles::after { + content: ''; + position: absolute; + width: 4px; + height: 4px; + background: radial-gradient(circle, #ffd700, #ffed4e); + border-radius: 50%; + animation: goldenFloat 8s ease-in-out infinite; +} + +.elden-ring .golden-particles::before { + top: 20%; + left: 15%; + animation-delay: 0s; +} + +.elden-ring .golden-particles::after { + top: 70%; + right: 20%; + animation-delay: 4s; +} + +@keyframes goldenFloat { + 0%, 100% { + transform: translateY(0) scale(1); + opacity: 0.6; + } + 50% { + transform: translateY(-20px) scale(1.5); + opacity: 1; + } +} + +.game-overlay { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: linear-gradient(transparent, rgba(0, 0, 0, 0.8)); + padding: 20px; + color: white; + opacity: 0; + transition: opacity 0.3s ease; +} + +.game-card:hover .game-overlay { + opacity: 1; +} + +.game-overlay .game-title { + font-family: 'Orbitron', monospace; + font-weight: bold; + font-size: 1.2rem; + margin-bottom: 5px; +} + +.game-overlay .game-description { + font-size: 0.9rem; + opacity: 0.9; +} + +.game-info { + padding: 25px; +} + +.game-info h3 { + font-family: 'Orbitron', monospace; + font-size: 1.4rem; + margin-bottom: 10px; + color: #00ffff; +} + +.game-info p { + line-height: 1.6; + margin-bottom: 20px; + color: #e0e0e0; +} + +/* Advanced Scratch Card Styles */ +.scratch-card { + position: relative; + margin: 25px 0; + border-radius: 15px; + overflow: hidden; + background: linear-gradient(135deg, #2c3e50, #34495e, #4a6741); + border: 2px solid #3498db; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); +} + +.scratch-card.advanced-scratch { + background: linear-gradient(135deg, #1e3c72, #2a5298, #3d5aa1); + border: 3px solid #00d4ff; + box-shadow: + 0 8px 32px rgba(0, 212, 255, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.1); +} + +.scratch-card.special-scratch { + background: linear-gradient(135deg, #d4af37, #ffd700, #ffed4e); + border: 3px solid #ffed4e; + box-shadow: + 0 8px 32px rgba(255, 215, 0, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.2); +} + +.scratch-canvas { + display: block; + cursor: crosshair; + background: linear-gradient(135deg, #34495e, #4a6741); + transition: box-shadow 0.3s ease; +} + +.scratch-card.advanced-scratch .scratch-canvas { + background: linear-gradient(135deg, #2a5298, #3d5aa1); +} + +.scratch-card.special-scratch .scratch-canvas { + background: linear-gradient(135deg, #ffd700, #ffed4e); +} + +.scratch-canvas:hover { + box-shadow: inset 0 0 20px rgba(255, 255, 255, 0.1); +} + +.hidden-key { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-family: 'Orbitron', monospace; + font-weight: bold; + font-size: 1.3rem; + color: #00ffff; + text-shadow: 0 0 15px #00ffff; + z-index: -1; + letter-spacing: 2px; +} + +.special-scratch .hidden-key { + color: #2c3e50; + text-shadow: 0 0 15px #2c3e50; + font-size: 1.4rem; +} + +.scratch-instruction { + text-align: center; + padding: 12px; + background: rgba(0, 0, 0, 0.4); + color: #ffffff; + font-size: 1rem; + font-weight: 600; + backdrop-filter: blur(5px); +} + +.scratch-progress { + padding: 15px; + background: rgba(0, 0, 0, 0.3); + backdrop-filter: blur(5px); +} + +.progress-bar { + width: 100%; + height: 8px; + background: rgba(255, 255, 255, 0.2); + border-radius: 10px; + overflow: hidden; + margin-bottom: 8px; +} + +.progress-bar.golden { + background: rgba(255, 215, 0, 0.3); +} + +.progress-fill { + height: 100%; + background: linear-gradient(90deg, #00ffff, #0099cc); + border-radius: 10px; + width: 0%; + transition: width 0.3s ease; +} + +.progress-bar.golden .progress-fill { + background: linear-gradient(90deg, #ffd700, #ffed4e); +} + +.progress-text { + font-family: 'Orbitron', monospace; + font-size: 0.9rem; + color: #ffffff; + font-weight: 600; +} + +/* Steam Links */ +.steam-link { + display: inline-block; + background: linear-gradient(45deg, #171a21, #2a475e); + color: #66c0f4; + padding: 12px 24px; + border-radius: 25px; + text-decoration: none; + font-weight: 600; + transition: all 0.3s ease; + border: 2px solid #66c0f4; +} + +.steam-link:hover { + background: linear-gradient(45deg, #66c0f4, #4a90e2); + color: #ffffff; + transform: translateY(-2px); + box-shadow: 0 5px 15px rgba(102, 192, 244, 0.4); +} + +.special-steam-link { + background: linear-gradient(45deg, #ffd700, #ffed4e); + color: #2c3e50; + border-color: #ffd700; +} + +.special-steam-link:hover { + background: linear-gradient(45deg, #ffed4e, #fff59d); + color: #1a1a1a; + box-shadow: 0 5px 15px rgba(255, 215, 0, 0.4); +} + +/* Birthday Message */ +.birthday-message { + text-align: center; + margin: 60px 0; +} + +.message-box { + background: rgba(255, 255, 255, 0.05); + padding: 40px; + border-radius: 20px; + max-width: 600px; + margin: 0 auto; + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.message-box h3 { + font-size: 2rem; + margin-bottom: 20px; + color: #ffd700; + text-shadow: 0 0 10px #ffd700; +} + +.message-box p { + line-height: 1.8; + margin-bottom: 20px; + font-size: 1.1rem; + color: #e0e0e0; +} + +.signature { + margin-top: 30px; + font-style: italic; + font-size: 1.2rem; + color: #ff6b6b; + font-weight: 600; +} + +/* Footer */ +footer { + text-align: center; + padding: 40px 0; +} + +.floating-icons { + font-size: 2rem; + animation: float 6s ease-in-out infinite; +} + +@keyframes float { + 0%, 100% { transform: translateY(0px); } + 50% { transform: translateY(-20px); } +} + +/* Responsive Design */ +@media (max-width: 768px) { + .container { + padding: 10px; + } + + .games-grid { + grid-template-columns: 1fr; + gap: 20px; + } + + .main-title { + font-size: 2rem; + } + + .name-title { + font-size: 3rem; + } + + .game-info { + padding: 20px; + } + + .message-box { + padding: 30px 20px; + } +} + +/* Enhanced Gaming Themes */ +.atomic-heart { + border-left: 6px solid #ff4757; + background: linear-gradient(135deg, rgba(255, 71, 87, 0.05), rgba(0, 0, 0, 0.05)); +} + +.atomic-heart .game-info h3 { + color: #ff4757; + text-shadow: 0 0 15px #ff4757; +} + +.prey { + border-left: 6px solid #5352ed; + background: linear-gradient(135deg, rgba(83, 82, 237, 0.05), rgba(0, 0, 0, 0.05)); +} + +.prey .game-info h3 { + color: #5352ed; + text-shadow: 0 0 15px #5352ed; +} + +.elden-ring { + border-left: 6px solid #ffd700; + background: linear-gradient(135deg, rgba(255, 215, 0, 0.08), rgba(255, 237, 78, 0.03)); +} + +.elden-ring .game-info h3 { + font-family: 'Cinzel', serif; + color: #ffd700; + text-shadow: 0 0 20px #ffd700; + font-size: 1.6rem; +} + +.elden-ring .game-info p { + font-size: 1.05rem; + line-height: 1.7; +} + +.signature { + margin-top: 40px; + text-align: center; +} + +.signature-text { + font-style: italic; + font-size: 1.1rem; + color: #e0e0e0; + margin-bottom: 10px; +} + +.signature-name { + font-size: 1.4rem; + color: #ff6b6b; + font-weight: bold; + text-shadow: 0 0 10px #ff6b6b; + font-family: 'Orbitron', monospace; +} + +/* Loading Animation */ +@keyframes fadeIn { + from { opacity: 0; transform: translateY(30px); } + to { opacity: 1; transform: translateY(0); } +} + +.game-card { + animation: fadeIn 0.8s ease forwards; +} + +.game-card:nth-child(1) { animation-delay: 0.2s; } +.game-card:nth-child(2) { animation-delay: 0.4s; } +.game-card:nth-child(3) { animation-delay: 0.6s; } \ No newline at end of file