Browse Source

Add animated monsters background to login screen

- Random monsters appear behind the login card
- Monsters cycle through random animations (idle, attack, skill, flip, etc.)
- Loads actual monster types from API for variety
- Animations stop when user logs in for performance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
master
HikeMap User 4 weeks ago
parent
commit
e30bdc5f1a
  1. 111
      index.html

111
index.html

@ -1242,6 +1242,8 @@
width: 90%; width: 90%;
max-width: 420px; max-width: 420px;
padding: 20px; padding: 20px;
position: relative;
z-index: 1;
} }
.login-screen-logo { .login-screen-logo {
text-align: center; text-align: center;
@ -1275,6 +1277,29 @@
background: #4CAF50; background: #4CAF50;
color: white; color: white;
} }
/* Login screen monster background */
.login-monsters-bg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
pointer-events: none;
opacity: 0.6;
}
.login-monster {
position: absolute;
width: 80px;
height: 80px;
transition: transform 0.3s ease;
}
.login-monster img {
width: 100%;
height: 100%;
object-fit: contain;
filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.3));
}
.login-version { .login-version {
text-align: center; text-align: center;
margin-top: 20px; margin-top: 20px;
@ -3235,6 +3260,7 @@
<body> <body>
<!-- Login Screen - shown before game loads --> <!-- Login Screen - shown before game loads -->
<div id="loginScreen"> <div id="loginScreen">
<div class="login-monsters-bg" id="loginMonstersBg"></div>
<div class="login-screen-content"> <div class="login-screen-content">
<div class="login-screen-logo"> <div class="login-screen-logo">
<h1>HikeMap</h1> <h1>HikeMap</h1>
@ -11024,6 +11050,8 @@
document.getElementById('gameContainer').classList.add('visible'); document.getElementById('gameContainer').classList.add('visible');
// Stop login music and transition to appropriate game music // Stop login music and transition to appropriate game music
stopMusic(); stopMusic();
// Stop login monster animations
stopLoginMonsters();
// Fix Leaflet map sizing - must recalculate after container becomes visible // Fix Leaflet map sizing - must recalculate after container becomes visible
setTimeout(() => { setTimeout(() => {
if (map) { if (map) {
@ -11107,6 +11135,89 @@
document.getElementById('loginScreenError').classList.remove('visible'); document.getElementById('loginScreenError').classList.remove('visible');
} }
// Login screen animated monsters background
const loginMonsterAnimations = ['idle', 'attack', 'skill', 'flipy', 'flipz', 'shrink_grow'];
let loginMonstersInterval = null;
async function initLoginMonsters() {
const container = document.getElementById('loginMonstersBg');
if (!container) return;
// Fallback monster IDs if we can't load from API
let monsterIds = ['moop', 'slime', 'goblin', 'bat', 'spider', 'rat'];
// Try to load monster types from API
try {
const response = await fetch('/api/monster-types');
if (response.ok) {
const types = await response.json();
if (types.length > 0) {
monsterIds = types.map(t => t.id);
}
}
} catch (e) {
console.log('Using fallback monster IDs for login screen');
}
// Create 8-12 monsters at random positions
const numMonsters = 8 + Math.floor(Math.random() * 5);
for (let i = 0; i < numMonsters; i++) {
const monsterId = monsterIds[Math.floor(Math.random() * monsterIds.length)];
const monster = document.createElement('div');
monster.className = 'login-monster';
monster.style.left = `${Math.random() * 90}%`;
monster.style.top = `${Math.random() * 85}%`;
monster.style.transform = `scale(${0.6 + Math.random() * 0.8})`;
monster.innerHTML = `<img src="/mapgameimgs/monsters/${monsterId}100.png"
onerror="this.src='/mapgameimgs/monsters/default100.png'" alt="monster">`;
container.appendChild(monster);
}
// Start random animations
animateLoginMonsters();
loginMonstersInterval = setInterval(animateLoginMonsters, 2500);
}
function animateLoginMonsters() {
const monsters = document.querySelectorAll('.login-monster img');
if (!monsters.length || typeof MONSTER_ANIMATIONS === 'undefined') return;
monsters.forEach(img => {
// 40% chance to animate each monster per cycle
if (Math.random() > 0.4) return;
const animName = loginMonsterAnimations[Math.floor(Math.random() * loginMonsterAnimations.length)];
const anim = MONSTER_ANIMATIONS[animName];
if (!anim) return;
// Generate unique animation name and apply
const uniqueAnimName = `login-${animName}-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
const styleSheet = document.styleSheets[0];
try {
styleSheet.insertRule(`@keyframes ${uniqueAnimName} { ${anim.keyframes} }`, styleSheet.cssRules.length);
} catch (e) { return; }
img.style.animation = `${uniqueAnimName} ${anim.duration}ms ${anim.easing || 'ease'} ${anim.loop ? 'infinite' : '1'}`;
// Clean up after animation
if (!anim.loop) {
setTimeout(() => {
img.style.animation = '';
}, anim.duration + 100);
}
});
}
function stopLoginMonsters() {
if (loginMonstersInterval) {
clearInterval(loginMonstersInterval);
loginMonstersInterval = null;
}
}
// Initialize login monsters when page loads
initLoginMonsters();
// Login screen tab switching // Login screen tab switching
document.getElementById('loginScreenLoginTab').addEventListener('click', () => { document.getElementById('loginScreenLoginTab').addEventListener('click', () => {
document.getElementById('loginScreenLoginTab').classList.add('active'); document.getElementById('loginScreenLoginTab').classList.add('active');

Loading…
Cancel
Save