231 lines
8.7 KiB
HTML
231 lines
8.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
<title>Reaktionstest - KinderWelt</title>
|
|
<style>
|
|
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
|
|
body {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
min-height: 100vh; display: flex; flex-direction: column; align-items: center;
|
|
font-family: 'Comic Sans MS', cursive, sans-serif; padding: 20px;
|
|
}
|
|
h1 { color: white; margin-bottom: 15px; font-size: 26px; }
|
|
.game-area {
|
|
width: 300px; height: 300px; border-radius: 20px;
|
|
display: flex; justify-content: center; align-items: center;
|
|
cursor: pointer; transition: all 0.1s; margin: 20px 0;
|
|
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
|
|
}
|
|
.game-area.wait { background: #ff6b6b; }
|
|
.game-area.ready { background: #4ade80; animation: pulse 0.5s infinite; }
|
|
.game-area.too-soon { background: #feca57; }
|
|
.game-area.start { background: #3b82f6; }
|
|
@keyframes pulse {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.05); }
|
|
}
|
|
.game-text {
|
|
color: white; font-size: 28px; font-weight: bold; text-align: center;
|
|
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
|
|
}
|
|
.stats {
|
|
display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px;
|
|
margin: 20px 0; max-width: 300px;
|
|
}
|
|
.stat-box {
|
|
background: white; border-radius: 15px; padding: 15px; text-align: center;
|
|
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
|
}
|
|
.stat-label { color: #666; font-size: 12px; }
|
|
.stat-value { color: #333; font-size: 24px; font-weight: bold; }
|
|
.stat-value.best { color: #4ade80; }
|
|
.controls { display: flex; gap: 15px; margin-top: 20px; }
|
|
.btn {
|
|
background: white; border: none; border-radius: 10px; padding: 12px 25px;
|
|
font-size: 16px; cursor: pointer; font-family: inherit; font-weight: bold;
|
|
}
|
|
.btn-back { background: #ff6b6b; color: white; text-decoration: none; }
|
|
.instructions { color: white; text-align: center; max-width: 400px; margin: 10px 0; }
|
|
.reaction-list { background: white; border-radius: 15px; padding: 15px; margin: 10px 0; }
|
|
.reaction-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #eee; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>⚡ Reaktionstest</h1>
|
|
|
|
<p class="instructions">
|
|
Warte bis es GRÜN wird, dann so schnell wie möglich klicken!
|
|
<br>Aber nicht zu früh...
|
|
</p>
|
|
|
|
<div class="stats">
|
|
<div class="stat-box">
|
|
<div class="stat-label">Letzte Zeit</div>
|
|
<div class="stat-value" id="lastTime">-</div>
|
|
</div>
|
|
<div class="stat-box">
|
|
<div class="stat-label">Bestzeit</div>
|
|
<div class="stat-value best" id="bestTime">-</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="game-area start" id="gameArea" onclick="handleClick()">
|
|
<div class="game-text" id="gameText">
|
|
Klicken zum
|
|
<br>Starten
|
|
</div>
|
|
</div>
|
|
|
|
<div class="reaction-list" id="reactionList" style="display:none">
|
|
<p style="font-weight:bold;margin-bottom:10px">Letzte Versuche:</p>
|
|
<div id="reactionHistory"></div>
|
|
</div>
|
|
|
|
<div class="controls">
|
|
<button class="btn" onclick="resetBest()">🗑️ Reset Bestzeit</button>
|
|
<a href="../index.html" class="btn btn-back">⬅️ Zurück</a>
|
|
</div>
|
|
|
|
<script>
|
|
// Zustände: start, waiting, ready, too_soon, result
|
|
let state = 'start';
|
|
let startTime = 0;
|
|
let waitTimer = null;
|
|
let bestTime = localStorage.getItem('reaktion_bestzeit');
|
|
let lastTime = null;
|
|
let reactionHistory = [];
|
|
|
|
const gameArea = document.getElementById('gameArea');
|
|
const gameText = document.getElementById('gameText');
|
|
|
|
// Bestzeit anzeigen
|
|
if (bestTime) {
|
|
document.getElementById('bestTime').textContent = bestTime + ' ms';
|
|
}
|
|
|
|
function handleClick() {
|
|
if (state === 'start') {
|
|
// Spiel starten
|
|
startWaiting();
|
|
} else if (state === 'waiting') {
|
|
// Zu früh!
|
|
tooSoon();
|
|
} else if (state === 'ready') {
|
|
// Reaktion messen
|
|
measureReaction();
|
|
} else if (state === 'too_soon' || state === 'result') {
|
|
// Neu starten
|
|
resetToStart();
|
|
}
|
|
}
|
|
|
|
function startWaiting() {
|
|
state = 'waiting';
|
|
startTime = 0;
|
|
gameArea.className = 'game-area wait';
|
|
gameText.innerHTML = 'Warte auf<br>GRÜN...';
|
|
|
|
// Zufällige Zeit 1-4 Sekunden
|
|
const delay = 1000 + Math.random() * 3000;
|
|
|
|
waitTimer = setTimeout(() => {
|
|
if (state === 'waiting') {
|
|
state = 'ready';
|
|
gameArea.className = 'game-area ready';
|
|
gameText.innerHTML = 'JETZT!<br>🖱️ Klick!';
|
|
startTime = Date.now();
|
|
}
|
|
}, delay);
|
|
}
|
|
|
|
function tooSoon() {
|
|
clearTimeout(waitTimer);
|
|
state = 'too_soon';
|
|
gameArea.className = 'game-area too-soon';
|
|
gameText.innerHTML = 'Zu früh!<br>😅<br><small>Nochmal klicken</small>';
|
|
}
|
|
|
|
function measureReaction() {
|
|
const endTime = Date.now();
|
|
const reactionTime = endTime - startTime;
|
|
state = 'result';
|
|
|
|
// Bewertung
|
|
let message = '';
|
|
let emoji = '';
|
|
if (reactionTime < 200) {
|
|
message = 'Unglaublich!';
|
|
emoji = '🚀';
|
|
} else if (reactionTime < 300) {
|
|
message = 'Super schnell!';
|
|
emoji = '⚡';
|
|
} else if (reactionTime < 400) {
|
|
message = 'Sehr gut!';
|
|
emoji = '👍';
|
|
} else if (reactionTime < 600) {
|
|
message = 'Gut!';
|
|
emoji = '👌';
|
|
} else {
|
|
message = 'Übe mehr!';
|
|
emoji = '💪';
|
|
}
|
|
|
|
gameArea.className = 'game-area wait';
|
|
gameText.innerHTML = reactionTime + ' ms<br>' + emoji + '<br><small>' + message + '</small>';
|
|
|
|
// Speichern
|
|
lastTime = reactionTime;
|
|
document.getElementById('lastTime').textContent = reactionTime + ' ms';
|
|
|
|
if (!bestTime || reactionTime < bestTime) {
|
|
bestTime = reactionTime;
|
|
localStorage.setItem('reaktion_bestzeit', bestTime);
|
|
document.getElementById('bestTime').textContent = bestTime + ' ms';
|
|
}
|
|
|
|
// Historie
|
|
reactionHistory.unshift({ time: reactionTime });
|
|
if (reactionHistory.length > 5) reactionHistory.pop();
|
|
updateHistory();
|
|
|
|
// TTS
|
|
if ('speechSynthesis' in window) {
|
|
const utterance = new SpeechSynthesisUtterance(reactionTime + ' Millisekunden. ' + message);
|
|
utterance.lang = 'de-DE';
|
|
utterance.rate = 0.9;
|
|
speechSynthesis.speak(utterance);
|
|
}
|
|
}
|
|
|
|
function resetToStart() {
|
|
state = 'start';
|
|
startTime = 0;
|
|
gameArea.className = 'game-area start';
|
|
gameText.innerHTML = 'Klicken zum<br>Starten';
|
|
}
|
|
|
|
function resetBest() {
|
|
localStorage.removeItem('reaktion_bestzeit');
|
|
bestTime = null;
|
|
document.getElementById('bestTime').textContent = '-';
|
|
}
|
|
|
|
function updateHistory() {
|
|
const list = document.getElementById('reactionHistory');
|
|
document.getElementById('reactionList').style.display = reactionHistory.length > 0 ? 'block' : 'none';
|
|
|
|
list.innerHTML = reactionHistory.map((r, i) => {
|
|
return '<div class="reaction-item"><span>' + (i+1) + '. Versuch</span><span>' + r.time + ' ms</span></div>';
|
|
}).join('');
|
|
}
|
|
|
|
// Touch für Mobile
|
|
gameArea.addEventListener('touchstart', function(e) {
|
|
e.preventDefault();
|
|
handleClick();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |