Hochwertige Digitale Schachuhr
by StealthOtter57518 lines16.5 KB
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hochwertige Digitale Schachuhr</title>
<style>
:root {
--bg-color: #0b0f19;
--card-bg: #111827;
--card-hover: #1f2937;
--border-color: #1e293b;
--text-color: #f8fafc;
--text-muted: #94a3b8;
--accent-player1: #38bdf8;
--accent-player2: #fb7185;
--active-glow: rgba(56, 189, 248, 0.15);
--active-border: #38bdf8;
}
* {
box-sizing: border-box;
}
body {
font-family: 'Inter', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #030712 0%, var(--bg-color) 100%);
color: var(--text-color);
margin: 0;
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
user-select: none;
}
header {
text-align: center;
padding: 10px;
background-color: rgba(17, 24, 39, 0.8);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border-color);
z-index: 10;
}
header h1 {
margin: 0;
font-size: 1.1rem;
letter-spacing: 0.5px;
font-weight: 600;
color: var(--text-color);
}
.settings {
display: flex;
justify-content: center;
align-items: center;
gap: 8px;
padding: 8px 12px;
background-color: rgba(17, 24, 39, 0.6);
border-bottom: 1px solid var(--border-color);
flex-wrap: wrap;
font-size: 0.8rem;
}
.settings label {
color: var(--text-muted);
font-weight: 500;
}
.settings select, .settings input, .settings button {
padding: 4px 8px;
border-radius: 6px;
border: 1px solid #334155;
background-color: #1e293b;
color: white;
font-size: 0.8rem;
outline: none;
transition: all 0.2s ease;
}
.settings input[type="number"] {
width: 50px;
text-align: center;
}
.settings select:focus, .settings input:focus {
border-color: var(--accent-player1);
box-shadow: 0 0 0 2px rgba(56, 189, 248, 0.2);
}
.settings button {
background: #2563eb;
border: none;
font-weight: 600;
cursor: pointer;
}
.settings button:hover {
background: #1d4ed8;
}
.clock-container {
display: flex;
flex: 1;
flex-direction: column;
gap: 8px;
padding: 8px;
min-height: 0; /* Wichtig damit Flexbox Inhalte verkleinern kann */
}
@media (min-width: 768px) {
.clock-container {
flex-direction: row;
gap: 12px;
padding: 12px;
}
}
.player-clock {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
padding: 16px;
border-radius: 16px;
background: var(--card-bg);
border: 1px solid var(--border-color);
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
min-height: 0;
}
.player-clock:hover {
background: var(--card-hover);
}
#player1-side {
border-top: 4px solid var(--accent-player1);
}
#player2-side {
border-top: 4px solid var(--accent-player2);
transform: rotate(180deg);
}
.player-clock.active {
background: linear-gradient(145deg, #111827, #1e293b);
box-shadow: 0 0 25px var(--active-glow);
border-color: var(--active-border);
}
.player-clock.inactive {
opacity: 0.45;
filter: grayscale(30%);
}
.player-info {
display: flex;
justify-content: space-between;
width: 100%;
max-width: 400px;
margin-bottom: 8px;
align-items: center;
}
.player-name {
font-size: 0.9rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
}
#player1-side .player-name { color: var(--accent-player1); }
#player2-side .player-name { color: var(--accent-player2); }
.move-counter {
font-size: 0.75rem;
color: var(--text-muted);
background: rgba(255, 255, 255, 0.05);
padding: 2px 8px;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.05);
}
.time-display {
font-size: 3.5rem;
font-weight: 800;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
letter-spacing: -2px;
}
@media (min-width: 768px) {
.time-display {
font-size: 5.5rem;
}
}
.controls-bar {
display: flex;
justify-content: center;
gap: 12px;
padding: 10px;
background-color: rgba(17, 24, 39, 0.9);
backdrop-filter: blur(10px);
border-top: 1px solid var(--border-color);
z-index: 10;
flex-shrink: 0; /* Verhindert das Schrumpfen der Buttons */
}
.btn-control {
padding: 10px 24px;
font-size: 0.9rem;
font-weight: 600;
border: none;
border-radius: 10px;
cursor: pointer;
color: white;
transition: all 0.2s ease;
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
.btn-control:active {
transform: scale(0.97);
}
#btn-start-pause { background: #16a34a; }
#btn-start-pause:hover { background: #15803d; }
#btn-reset { background: #334155; }
#btn-reset:hover { background: #475569; }
.flag-fallen {
color: #ef4444 !important;
animation: pulse-blink 0.8s infinite alternate;
}
@keyframes pulse-blink {
0% { opacity: 1; transform: scale(1); }
100% { opacity: 0.4; transform: scale(0.98); }
}
</style>
</head>
<body>
<header>
<h1>Schachuhr Pro</h1>
</header>
<div class="settings">
<label for="time-select">Modus:</label>
<select id="time-select">
<option value="1">1 Min (Bullet)</option>
<option value="3">3 Min (Blitz)</option>
<option value="5" selected>5 Min (Blitz)</option>
<option value="10">10 Min (Schnell)</option>
<option value="15">15 Min (Schnell)</option>
<option value="30">30 Min</option>
</select>
<label for="custom-minutes">Min:</label>
<input type="number" id="custom-minutes" min="1" max="180" placeholder="Min" value="5">
<label for="increment-select">+ Sek/Zug:</label>
<select id="increment-select">
<option value="0">0 Sek</option>
<option value="2">2 Sek</option>
<option value="3" selected>3 Sek (Fischer)</option>
<option value="5">5 Sek</option>
</select>
<button id="btn-apply">Übernehmen</button>
</div>
<div class="clock-container">
<div id="player2-side" class="player-clock inactive" onclick="switchTurn(2)">
<div class="player-info">
<span class="player-name">Spieler 2</span>
<span id="moves-player2" class="move-counter">Züge: 0</span>
</div>
<div id="time-player2" class="time-display">05:00</div>
</div>
<div id="player1-side" class="player-clock inactive" onclick="switchTurn(1)">
<div class="player-info">
<span class="player-name">Spieler 1</span>
<span id="moves-player1" class="move-counter">Züge: 0</span>
</div>
<div id="time-player1" class="time-display">05:00</div>
</div>
</div>
<div class="controls-bar">
<button id="btn-start-pause" class="btn-control">Start</button>
<button id="btn-reset" class="btn-control">Zurücksetzen</button>
</div>
<script>
let initialTimeSeconds = 300;
let incrementSeconds = 3;
let timePlayer1 = initialTimeSeconds;
let timePlayer2 = initialTimeSeconds;
let movesPlayer1 = 0;
let movesPlayer2 = 0;
let activePlayer = null;
let timerInterval = null;
let gameRunning = false;
let gamePaused = false;
const timeDisplay1 = document.getElementById('time-player1');
const timeDisplay2 = document.getElementById('time-player2');
const movesDisplay1 = document.getElementById('moves-player1');
const movesDisplay2 = document.getElementById('moves-player2');
const player1Side = document.getElementById('player1-side');
const player2Side = document.getElementById('player2-side');
const btnStartPause = document.getElementById('btn-start-pause');
const btnReset = document.getElementById('btn-reset');
const timeSelect = document.getElementById('time-select');
const customMinutesInput = document.getElementById('custom-minutes');
const incrementSelect = document.getElementById('increment-select');
const btnApply = document.getElementById('btn-apply');
function playAlertSound() {
try {
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const oscillator = audioCtx.createOscillator();
const gainNode = audioCtx.createGain();
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(440, audioCtx.currentTime);
oscillator.connect(gainNode);
gainNode.connect(audioCtx.destination);
oscillator.start();
oscillator.stop(audioCtx.currentTime + 0.5);
} catch (e) {
console.log("Audio nicht unterstützt");
}
}
function formatTime(totalSeconds) {
if (totalSeconds < 0) totalSeconds = 0;
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
}
function updateDisplay() {
timeDisplay1.textContent = formatTime(timePlayer1);
timeDisplay2.textContent = formatTime(timePlayer2);
movesDisplay1.textContent = `Züge: ${movesPlayer1}`;
movesDisplay2.textContent = `Züge: ${movesPlayer2}`;
}
function switchTurn(playerNum) {
if (!gameRunning || gamePaused) return;
if (activePlayer === null) {
activePlayer = (playerNum === 1) ? 2 : 1;
updateVisuals();
return;
}
if (playerNum === 1 && activePlayer === 1) {
timePlayer1 += incrementSeconds;
movesPlayer1++;
activePlayer = 2;
updateVisuals();
updateDisplay();
}
else if (playerNum === 2 && activePlayer === 2) {
timePlayer2 += incrementSeconds;
movesPlayer2++;
activePlayer = 1;
updateVisuals();
updateDisplay();
}
}
function updateVisuals() {
if (activePlayer === 1) {
player1Side.classList.add('active');
player1Side.classList.remove('inactive');
player2Side.classList.remove('active');
player2Side.classList.add('inactive');
} else if (activePlayer === 2) {
player2Side.classList.add('active');
player2Side.classList.remove('inactive');
player1Side.classList.remove('active');
player1Side.classList.add('inactive');
} else {
player1Side.classList.remove('active', 'inactive');
player2Side.classList.remove('active', 'inactive');
}
}
function startTimer() {
if (timerInterval) clearInterval(timerInterval);
timerInterval = setInterval(() => {
if (!gameRunning || gamePaused) return;
if (activePlayer === 1) {
if (timePlayer1 > 0) {
timePlayer1--;
if (timePlayer1 === 0) endGame(1);
}
} else if (activePlayer === 2) {
if (timePlayer2 > 0) {
timePlayer2--;
if (timePlayer2 === 0) endGame(2);
}
}
updateDisplay();
}, 1000);
}
function endGame(loserPlayer) {
gameRunning = false;
clearInterval(timerInterval);
activePlayer = null;
updateVisuals();
playAlertSound();
if (loserPlayer === 1) {
timeDisplay1.classList.add('flag-fallen');
alert("Zeit abgelaufen! Spieler 2 gewinnt.");
} else {
timeDisplay2.classList.add('flag-fallen');
alert("Zeit abgelaufen! Spieler 1 gewinnt.");
}
btnStartPause.textContent = "Start";
}
btnStartPause.addEventListener('click', () => {
if (!gameRunning) {
gameRunning = true;
gamePaused = false;
btnStartPause.textContent = "Pause";
if (activePlayer === null) {
activePlayer = 1;
}
updateVisuals();
startTimer();
} else {
gamePaused = !gamePaused;
if (gamePaused) {
btnStartPause.textContent = "Weiter";
player1Side.classList.remove('active', 'inactive');
player2Side.classList.remove('active', 'inactive');
} else {
btnStartPause.textContent = "Pause";
updateVisuals();
}
}
});
btnReset.addEventListener('click', () => {
gameRunning = false;
gamePaused = false;
clearInterval(timerInterval);
activePlayer = null;
timePlayer1 = initialTimeSeconds;
timePlayer2 = initialTimeSeconds;
movesPlayer1 = 0;
movesPlayer2 = 0;
timeDisplay1.classList.remove('flag-fallen');
timeDisplay2.classList.remove('flag-fallen');
updateDisplay();
updateVisuals();
btnStartPause.textContent = "Start";
});
btnApply.addEventListener('click', () => {
let minutes = parseInt(customMinutesInput.value);
if (isNaN(minutes) || minutes <= 0) {
minutes = parseInt(timeSelect.value);
customMinutesInput.value = minutes;
}
initialTimeSeconds = minutes * 60;
incrementSeconds = parseInt(incrementSelect.value);
gameRunning = false;
gamePaused = false;
clearInterval(timerInterval);
activePlayer = null;
timePlayer1 = initialTimeSeconds;
timePlayer2 = initialTimeSeconds;
movesPlayer1 = 0;
movesPlayer2 = 0;
timeDisplay1.classList.remove('flag-fallen');
timeDisplay2.classList.remove('flag-fallen');
updateDisplay();
updateVisuals();
btnStartPause.textContent = "Start";
});
timeSelect.addEventListener('change', () => {
customMinutesInput.value = timeSelect.value;
});
updateDisplay();
</script>
</body>
</html>Game Source: Hochwertige Digitale Schachuhr
Creator: StealthOtter57
Libraries: none
Complexity: complex (518 lines, 16.5 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: digitale-schachuhr-stealthotter57" to link back to the original. Then publish at arcadelab.ai/publish.