Classroom Countdown Timer
A high-contrast timer with visual and audio alerts perfect for classroom activities.
00:00
Embed This Tool
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Classroom Timer</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: #f3f4f6; min-height: 100vh; display: flex; flex-direction: column; align-items: center; padding: 20px; transition: background-color 0.3s; }
.container { max-width: 500px; width: 100%; background: white; border-radius: 16px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); padding: 32px; }
h1 { color: #1f2937; text-align: center; margin-bottom: 24px; font-size: 2rem; }
.timer-wrapper { display: flex; justify-content: center; margin: 32px 0; }
.timer-display { font-family: 'Courier New', monospace; font-size: 4rem; font-weight: bold; color: #1f2937; }
.quick-set { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; margin-bottom: 24px; }
.quick-set button { padding: 12px 20px; border: none; border-radius: 8px; background: #e5e7eb; color: #374151; font-weight: 600; cursor: pointer; transition: all 0.2s; }
.quick-set button:hover { background: #d1d5db; }
.manual-input { display: flex; justify-content: center; gap: 16px; margin-bottom: 24px; }
.manual-input label { font-weight: 600; color: #374151; }
.manual-input input { width: 80px; padding: 8px; border: 2px solid #e5e7eb; border-radius: 8px; text-align: center; font-size: 1.2rem; }
.manual-input input:focus { outline: none; border-color: #dc2626; }
.controls { display: flex; justify-content: center; gap: 16px; }
.controls button { padding: 16px 32px; border: none; border-radius: 8px; font-size: 1.2rem; font-weight: bold; cursor: pointer; transition: all 0.2s; }
#startPauseBtn { background: #dc2626; color: white; }
#startPauseBtn:hover { background: #b91c1c; }
#resetBtn { background: #e5e7eb; color: #374151; }
#resetBtn:hover { background: #d1d5db; }
.flash-warning { animation: flashRed 0.5s ease-in-out infinite; }
@keyframes flashRed { 0%, 100% { background-color: #fef2f2; } 50% { background-color: #fee2e2; } }
</style>
</head>
<body id="timerBody">
<div class="container">
<h1>Classroom Timer</h1>
<div class="timer-wrapper">
<div id="timerDisplay" class="timer-display">00:00</div>
</div>
<div class="quick-set">
<button data-time="60">1 min</button>
<button data-time="120">2 min</button>
<button data-time="300">5 min</button>
<button data-time="600">10 min</button>
<button data-time="900">15 min</button>
</div>
<div class="manual-input">
<label>Min:</label>
<input type="number" id="minutesInput" min="0" max="99" value="5">
<label>Sec:</label>
<input type="number" id="secondsInput" min="0" max="59" value="0">
</div>
<div class="controls">
<button id="startPauseBtn">Start</button>
<button id="resetBtn">Reset</button>
</div>
</div>
<script>
let totalTime = 300;
let timeRemaining = 300;
let isRunning = false;
let intervalId = null;
const timerDisplay = document.getElementById('timerDisplay');
const startPauseBtn = document.getElementById('startPauseBtn');
const resetBtn = document.getElementById('resetBtn');
const minutesInput = document.getElementById('minutesInput');
const secondsInput = document.getElementById('secondsInput');
const timerBody = document.getElementById('timerBody');
// Load saved time from localStorage
const savedTime = localStorage.getItem('classroomTimerTime');
if (savedTime) {
totalTime = parseInt(savedTime);
timeRemaining = totalTime;
const mins = Math.floor(totalTime / 60);
const secs = totalTime % 60;
minutesInput.value = mins;
secondsInput.value = secs;
}
function formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
function updateDisplay() {
timerDisplay.textContent = formatTime(timeRemaining);
}
function playAlarm() {
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const playDing = (time) => {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = 800;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, time);
gainNode.gain.exponentialRampToValueAtTime(0.01, time + 0.5);
oscillator.start(time);
oscillator.stop(time + 0.5);
};
playDing(audioContext.currentTime);
playDing(audioContext.currentTime + 0.6);
}
function startTimer() {
isRunning = true;
startPauseBtn.textContent = 'Pause';
intervalId = setInterval(() => {
timeRemaining--;
updateDisplay();
if (timeRemaining <= 10) {
timerBody.classList.add('flash-warning');
}
if (timeRemaining <= 0) {
clearInterval(intervalId);
isRunning = false;
startPauseBtn.textContent = 'Start';
timerBody.classList.remove('flash-warning');
playAlarm();
}
}, 1000);
}
function pauseTimer() {
isRunning = false;
startPauseBtn.textContent = 'Start';
clearInterval(intervalId);
}
function resetTimer() {
pauseTimer();
timerBody.classList.remove('flash-warning');
totalTime = parseInt(minutesInput.value) * 60 + parseInt(secondsInput.value);
timeRemaining = totalTime;
localStorage.setItem('classroomTimerTime', totalTime);
updateDisplay();
}
startPauseBtn.addEventListener('click', () => {
if (isRunning) {
pauseTimer();
} else {
if (timeRemaining === 0) {
resetTimer();
}
startTimer();
}
});
resetBtn.addEventListener('click', resetTimer);
document.querySelectorAll('.quick-set').forEach(btn => {
btn.addEventListener('click', (e) => {
if (e.target.dataset.time) {
pauseTimer();
timerBody.classList.remove('flash-warning');
totalTime = parseInt(e.target.dataset.time);
timeRemaining = totalTime;
minutesInput.value = Math.floor(totalTime / 60);
secondsInput.value = totalTime % 60;
localStorage.setItem('classroomTimerTime', totalTime);
updateDisplay();
}
});
});
minutesInput.addEventListener('input', () => {
if (!isRunning) {
totalTime = parseInt(minutesInput.value) * 60 + parseInt(secondsInput.value);
timeRemaining = totalTime;
localStorage.setItem('classroomTimerTime', totalTime);
updateDisplay();
}
});
secondsInput.addEventListener('input', () => {
if (!isRunning) {
totalTime = parseInt(minutesInput.value) * 60 + parseInt(secondsInput.value);
timeRemaining = totalTime;
localStorage.setItem('classroomTimerTime', totalTime);
updateDisplay();
}
});
updateDisplay();
</script>
</body>
</html>