🎮ArcadeLab

Hochwertige Digitale Schachuhr

by StealthOtter57
518 lines16.5 KB
▶ Play
<!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.