Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>GeoGuessr - Image Origin Game</title> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet"> | |
<style> | |
:root { | |
--primary: #6366f1; | |
--secondary: #8b5cf6; | |
--accent: #06b6d4; | |
--success: #10b981; | |
--warning: #f59e0b; | |
--error: #ef4444; | |
--dark: #1e293b; | |
--light: #f8fafc; | |
--gray: #64748b; | |
--border: #e2e8f0; | |
} | |
* { | |
margin: 0; | |
padding: 0; | |
box-sizing: border-box; | |
} | |
body { | |
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; | |
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
min-height: 100vh; | |
color: var(--dark); | |
line-height: 1.6; | |
} | |
.container { | |
max-width: 1200px; | |
margin: 0 auto; | |
padding: 20px; | |
} | |
.header { | |
text-align: center; | |
margin-bottom: 40px; | |
color: white; | |
} | |
.header h1 { | |
font-size: 3rem; | |
margin-bottom: 10px; | |
text-shadow: 2px 2px 4px rgba(0,0,0,0.3); | |
} | |
.header p { | |
font-size: 1.2rem; | |
opacity: 0.9; | |
} | |
.game-card { | |
background: white; | |
border-radius: 20px; | |
box-shadow: 0 20px 40px rgba(0,0,0,0.1); | |
overflow: hidden; | |
margin-bottom: 30px; | |
} | |
.upload-section { | |
padding: 40px; | |
text-align: center; | |
border-bottom: 1px solid var(--border); | |
} | |
.upload-area { | |
border: 3px dashed var(--border); | |
border-radius: 15px; | |
padding: 60px; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
position: relative; | |
overflow: hidden; | |
} | |
.upload-area:hover { | |
border-color: var(--primary); | |
background: linear-gradient(135deg, #f5f7ff 0%, #f0f4ff 100%); | |
} | |
.upload-area.dragover { | |
border-color: var(--success); | |
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%); | |
} | |
.upload-icon { | |
font-size: 4rem; | |
color: var(--primary); | |
margin-bottom: 20px; | |
} | |
.file-input { | |
display: none; | |
} | |
.image-preview { | |
max-width: 100%; | |
max-height: 400px; | |
border-radius: 10px; | |
margin: 20px 0; | |
box-shadow: 0 10px 20px rgba(0,0,0,0.1); | |
} | |
.answer-section { | |
padding: 40px; | |
border-bottom: 1px solid var(--border); | |
} | |
.form-group { | |
margin-bottom: 20px; | |
} | |
label { | |
display: block; | |
margin-bottom: 8px; | |
font-weight: 600; | |
color: var(--dark); | |
} | |
input[type="text"], input[type="number"] { | |
width: 100%; | |
padding: 12px 16px; | |
border: 2px solid var(--border); | |
border-radius: 10px; | |
font-size: 16px; | |
transition: all 0.3s ease; | |
} | |
input[type="text"]:focus, input[type="number"]:focus { | |
outline: none; | |
border-color: var(--primary); | |
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1); | |
} | |
.btn { | |
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%); | |
color: white; | |
border: none; | |
padding: 14px 32px; | |
border-radius: 50px; | |
font-size: 16px; | |
font-weight: 600; | |
cursor: pointer; | |
transition: all 0.3s ease; | |
display: inline-flex; | |
align-items: center; | |
gap: 8px; | |
} | |
.btn:hover { | |
transform: translateY(-2px); | |
box-shadow: 0 10px 20px rgba(99, 102, 241, 0.3); | |
} | |
.btn:active { | |
transform: translateY(0); | |
} | |
.btn-secondary { | |
background: linear-gradient(135deg, var(--gray) 0%, var(--dark) 100%); | |
} | |
.btn-success { | |
background: linear-gradient(135deg, var(--success) 0%, #059669 100%); | |
} | |
.guessing-section { | |
padding: 40px; | |
} | |
.guess-form { | |
display: flex; | |
gap: 10px; | |
margin-bottom: 30px; | |
flex-wrap: wrap; | |
} | |
.guess-form input { | |
flex: 1; | |
min-width: 200px; | |
} | |
.guesses { | |
display: grid; | |
gap: 15px; | |
} | |
.guess-item { | |
background: var(--light); | |
border-radius: 12px; | |
padding: 20px; | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
transition: all 0.3s ease; | |
border: 2px solid transparent; | |
} | |
.guess-item:hover { | |
transform: translateX(5px); | |
box-shadow: 0 5px 15px rgba(0,0,0,0.1); | |
} | |
.guess-item.correct { | |
background: linear-gradient(135deg, #dcfce7 0%, #bbf7d0 100%); | |
border-color: var(--success); | |
} | |
.guess-item.incorrect { | |
background: linear-gradient(135deg, #fee2e2 0%, #fecaca 100%); | |
border-color: var(--error); | |
} | |
.guess-text { | |
font-size: 18px; | |
font-weight: 500; | |
} | |
.guess-score { | |
font-size: 24px; | |
font-weight: bold; | |
color: var(--primary); | |
} | |
.timer { | |
font-size: 2rem; | |
font-weight: bold; | |
color: var(--warning); | |
text-align: center; | |
margin: 20px 0; | |
} | |
.leaderboard { | |
background: white; | |
border-radius: 20px; | |
padding: 40px; | |
box-shadow: 0 20px 40px rgba(0,0,0,0.1); | |
} | |
.leaderboard h2 { | |
margin-bottom: 20px; | |
color: var(--dark); | |
} | |
.leaderboard-item { | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
padding: 15px; | |
border-bottom: 1px solid var(--border); | |
} | |
.leaderboard-item:last-child { | |
border-bottom: none; | |
} | |
.modal { | |
display: none; | |
position: fixed; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 100%; | |
background: rgba(0,0,0,0.8); | |
z-index: 1000; | |
animation: fadeIn 0.3s ease; | |
} | |
.modal-content { | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
background: white; | |
border-radius: 20px; | |
padding: 40px; | |
max-width: 400px; | |
width: 90%; | |
text-align: center; | |
animation: slideIn 0.3s ease; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; } | |
to { opacity: 1; } | |
} | |
@keyframes slideIn { | |
from { transform: translate(-50%, -60%); opacity: 0; } | |
to { transform: translate(-50%, -50%); opacity: 1; } | |
} | |
.close-modal { | |
position: absolute; | |
top: 15px; | |
right: 20px; | |
font-size: 2rem; | |
cursor: pointer; | |
color: var(--gray); | |
} | |
.close-modal:hover { | |
color: var(--dark); | |
} | |
@media (max-width: 768px) { | |
.container { | |
padding: 10px; | |
} | |
.header h1 { | |
font-size: 2rem; | |
} | |
.upload-section, .answer-section, .guessing-section { | |
padding: 20px; | |
} | |
.upload-area { | |
padding: 40px 20px; | |
} | |
.guess-form { | |
flex-direction: column; | |
} | |
.guess-item { | |
flex-direction: column; | |
text-align: center; | |
gap: 10px; | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container"> | |
<header class="header"> | |
<h1><i class="fas fa-map-marker-alt"></i> GeoGuessr</h1> | |
<p>Upload an image and let others guess where it's from!</p> | |
</header> | |
<div class="game-card"> | |
<div class="upload-section"> | |
<div class="upload-area" onclick="document.getElementById('fileInput').click()"> | |
<i class="fas fa-cloud-upload-alt upload-icon"></i> | |
<h3>Drop your image here or click to browse</h3> | |
<p>Upload any image and challenge others to guess its location</p> | |
<input type="file" id="fileInput" class="file-input" accept="image/*"> | |
</div> | |
<img id="imagePreview" class="image-preview" style="display: none;"> | |
</div> | |
<div class="answer-section" id="answerSection" style="display: none;"> | |
<h2>Set the Challenge</h2> | |
<div class="form-group"> | |
<label>Your username</label> | |
<input type="text" id="hostName" placeholder="Enter your username" value="Host"> | |
</div> | |
<div class="form-group" id="answerGroup"> | |
<label id="answerLabel">What's the correct answer? (Hidden from players)</label> | |
<input type="text" id="correctAnswer" placeholder="e.g., Eiffel Tower, Paris"> | |
</div> | |
<div class="form-group"> | |
<label>How many seconds for guessing?</label> | |
<input type="number" id="timeLimit" value="60" min="10" max="300"> | |
</div> | |
<button class="btn" onclick="startGame()"> | |
<i class="fas fa-play"></i> Start Challenge | |
</button> | |
</div> | |
<div class="guessing-section" id="guessingSection" style="display: none;"> | |
<h2>Where is this image from?</h2> | |
<div class="timer" id="timer">60</div> | |
<div class="guess-form"> | |
<input type="text" id="guessInput" placeholder="Your guess..."> | |
<button class="btn" onclick="submitGuess()">Submit Guess</button> | |
</div> | |
<div class="guesses" id="guessesList"></div> | |
</div> | |
</div> | |
<div class="leaderboard"> | |
<h2><i class="fas fa-trophy"></i> Top Players</h2> | |
<div id="leaderboardList"> | |
<!-- filled dynamically --> | |
</div> | |
</div> | |
</div> | |
<div class="modal" id="gameOverModal"> | |
<div class="modal-content"> | |
<span class="close-modal" onclick="closeModal()">×</span> | |
<i class="fas fa-trophy" style="font-size: 4rem; color: var(--success); margin-bottom: 20px;"></i> | |
<h2>Game Over!</h2> | |
<p id="modalMessage">Thanks for playing!</p> | |
<button class="btn btn-secondary" onclick="resetGame()">Play Again</button> | |
</div> | |
</div> | |
<script> | |
let gameData = { | |
image: null, | |
answer: '', | |
timeLimit: 60, | |
currentTime: 60, | |
timer: null, | |
guesses: [], | |
score: 0 | |
}; | |
// File upload handling | |
const fileInput = document.getElementById('fileInput'); | |
const uploadArea = document.querySelector('.upload-area'); | |
const imagePreview = document.getElementById('imagePreview'); | |
fileInput.addEventListener('change', handleFileSelect); | |
uploadArea.addEventListener('dragover', handleDragOver); | |
uploadArea.addEventListener('drop', handleDrop); | |
function handleFileSelect(e) { | |
const file = e.target.files[0]; | |
if (file && file.type.startsWith('image/')) { | |
displayImage(file); | |
} | |
} | |
function handleDragOver(e) { | |
e.preventDefault(); | |
uploadArea.classList.add('dragover'); | |
} | |
function handleDrop(e) { | |
e.preventDefault(); | |
uploadArea.classList.remove('dragover'); | |
const file = e.dataTransfer.files[0]; | |
if (file && file.type.startsWith('image/')) { | |
displayImage(file); | |
} | |
} | |
function displayImage(file) { | |
const reader = new FileReader(); | |
reader.onload = function(e) { | |
gameData.image = e.target.result; | |
imagePreview.src = e.target.result; | |
imagePreview.style.display = 'block'; | |
document.getElementById('answerSection').style.display = 'block'; | |
}; | |
reader.readAsDataURL(file); | |
} | |
function startGame() { | |
const answer = document.getElementById('correctAnswer').value.trim(); | |
const timeLimit = parseInt(document.getElementById('timeLimit').value); | |
if (!answer) { | |
alert('Please enter a correct answer!'); | |
return; | |
} | |
gameData.answer = answer; | |
gameData.timeLimit = timeLimit; | |
gameData.currentTime = timeLimit; | |
gameData.guesses = []; | |
// Hide the answer input from everyone (including host) | |
document.getElementById('answerGroup').style.display = 'none'; | |
document.getElementById('guessingSection').style.display = 'block'; | |
document.getElementById('timer').textContent = timeLimit; | |
document.getElementById('guessesList').innerHTML = ''; | |
startTimer(); | |
} | |
function startTimer() { | |
gameData.timer = setInterval(() => { | |
gameData.currentTime--; | |
document.getElementById('timer').textContent = gameData.currentTime; | |
if (gameData.currentTime <= 0) { | |
endGame(); | |
} | |
}, 1000); | |
} | |
function submitGuess() { | |
const guess = document.getElementById('guessInput').value.trim(); | |
if (!guess) return; | |
const isCorrect = guess.toLowerCase() === gameData.answer.toLowerCase(); | |
const points = isCorrect ? Math.round((gameData.currentTime / gameData.timeLimit) * 1000) : 0; | |
gameData.guesses.unshift({ | |
text: guess, | |
correct: isCorrect, | |
score: points | |
}); | |
displayGuess(guess, isCorrect, points); | |
if (isCorrect) { | |
gameData.score += points; | |
setTimeout(() => { | |
endGame(); | |
}, 1000); | |
} | |
document.getElementById('guessInput').value = ''; | |
} | |
function displayGuess(guess, correct, score) { | |
const guessesList = document.getElementById('guessesList'); | |
const guessItem = document.createElement('div'); | |
guessItem.className = `guess-item ${correct ? 'correct' : 'incorrect'}`; | |
guessItem.innerHTML = ` | |
<div class="guess-text">${guess}</div> | |
<div class="guess-score">${score > 0 ? `+${score}` : ''}</div> | |
`; | |
guessesList.insertBefore(guessItem, guessesList.firstChild); | |
} | |
function endGame() { | |
clearInterval(gameData.timer); | |
document.getElementById('modalMessage').innerHTML = ` | |
<strong>Correct Answer:</strong> ${gameData.answer}<br> | |
<strong>Your Score:</strong> ${gameData.score} points | |
`; | |
document.getElementById('gameOverModal').style.display = 'block'; | |
} | |
function closeModal() { | |
document.getElementById('gameOverModal').style.display = 'none'; | |
} | |
function resetGame() { | |
closeModal(); | |
gameData = { | |
image: null, | |
answer: '', | |
timeLimit: 60, | |
currentTime: 60, | |
timer: null, | |
guesses: [], | |
score: 0 | |
}; | |
imagePreview.style.display = 'none'; | |
document.getElementById('answerSection').style.display = 'none'; | |
document.getElementById('guessingSection').style.display = 'none'; | |
document.getElementById('correctAnswer').value = ''; | |
document.getElementById('guessInput').value = ''; | |
document.getElementById('guessesList').innerHTML = ''; | |
fileInput.value = ''; | |
} | |
// Allow Enter key for submitting guesses | |
document.getElementById('guessInput').addEventListener('keypress', function(e) { | |
if (e.key === 'Enter') { | |
submitGuess(); | |
} | |
}); | |
</script> | |
</body> | |
</html> |