clock
TimerGitHub

TBD: Online Timer

Bookmarklets

Drag the following links to your bookmarks bar.

Normal(Alarm, Title)

javascript: (function (pattern) { const PATTERN = { NORMAL: "normal", NO_SOUND: "no-sound", FULL_SCREEN: "full-screen", FULL_SCREEN_NO_SOUND: "full-screen-no-sound", }; const isFullScreen = () => { return ( pattern === PATTERN.FULL_SCREEN || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; const isNoSound = () => { return ( pattern === PATTERN.NO_SOUND || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; class Alarm { constructor() { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.audioContext.resume(); } play() { const startTime = this.audioContext.currentTime; const beepFrequency = 800; /* Frequency in Hz */ Array.from({ length: 3 }).forEach((_, index) => { const beep = this.createBeep(beepFrequency, startTime + index * 0.2); beep.start(startTime + index * 0.2); beep.stop(startTime + index * 0.2 + 0.1); }); } createBeep(frequency, startTime) { const oscillator = this.audioContext.createOscillator(); const gainNode = this.audioContext.createGain(); oscillator.frequency.value = frequency; gainNode.gain.setValueAtTime(0, startTime); gainNode.gain.linearRampToValueAtTime(0.1, startTime + 0.01); gainNode.gain.linearRampToValueAtTime(0, startTime + 0.1); oscillator.connect(gainNode); gainNode.connect(this.audioContext.destination); return oscillator; } } class CountdownTimer { constructor() { this.intervalId = null; this.alarmIntervalId = null; this.pageTitle = document.title; if (isFullScreen()) this.timerBoard = this.createBoard(); } start(seconds = 0, interval = 1) { let remaining = seconds; this.updateTitle(remaining); if (isFullScreen()) { this.showBoard(); this.updateBoard(remaining); } if (!this.intervalId) { this.intervalId = setInterval(() => { remaining -= interval; this.updateTitle(remaining); if (isFullScreen()) this.updateBoard(remaining); if (remaining <= 0) { this.teardown(); if (isFullScreen()) this.timerBoard.innerText = "Time's up!"; if (!isNoSound()) this.playAlarm(); } }, interval * 1000); } } playAlarm() { const alarm = new Alarm(); const interval = 1200; /* in milliseconds */ this.alarmIntervalId = setInterval(() => alarm.play(), interval); const totalDuration = 5000; /* in milliseconds */ alarm.play(); setTimeout(() => { this.teardown(); }, totalDuration); } teardown() { this.resetTitle(); if (this.intervalId) clearInterval(this.intervalId); if (this.alarmIntervalId) clearInterval(this.alarmIntervalId); this.intervalId = null; this.alarmIntervalId = null; } createBoard() { const timerBoard = document.createElement("div"); timerBoard.style.position = "fixed"; timerBoard.style.top = "0"; timerBoard.style.left = "0"; timerBoard.style.width = "100%"; timerBoard.style.height = "100%"; timerBoard.style.backgroundColor = "rgba(0, 0, 0, 0.9)"; timerBoard.style.zIndex = "999999"; timerBoard.style.display = "none"; timerBoard.style.justifyContent = "center"; timerBoard.style.alignItems = "center"; timerBoard.style.color = "white"; timerBoard.style.fontSize = "10rem"; timerBoard.style.fontWeight = "bold"; timerBoard.style.textAlign = "center"; timerBoard.onclick = () => { this.teardown(); this.timerBoard.remove(); }; document.body.appendChild(timerBoard); return timerBoard; } showBoard() { console.log("showBoard"); this.timerBoard.style.display = "flex"; } updateBoard(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); this.timerBoard.innerText = `${minutesString}:${secondsString}`; } updateTitle(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); document.title = `${minutesString}:${secondsString}`; } resetTitle() { document.title = this.pageTitle; } } const timer = new CountdownTimer(); const seconds = Number( prompt("Enter timer seconds in seconds:", String(300)) ); if (seconds > 0) timer.start(seconds); })("normal");

No Sound(Title)

javascript: (function (pattern) { const PATTERN = { NORMAL: "normal", NO_SOUND: "no-sound", FULL_SCREEN: "full-screen", FULL_SCREEN_NO_SOUND: "full-screen-no-sound", }; const isFullScreen = () => { return ( pattern === PATTERN.FULL_SCREEN || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; const isNoSound = () => { return ( pattern === PATTERN.NO_SOUND || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; class Alarm { constructor() { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.audioContext.resume(); } play() { const startTime = this.audioContext.currentTime; const beepFrequency = 800; /* Frequency in Hz */ Array.from({ length: 3 }).forEach((_, index) => { const beep = this.createBeep(beepFrequency, startTime + index * 0.2); beep.start(startTime + index * 0.2); beep.stop(startTime + index * 0.2 + 0.1); }); } createBeep(frequency, startTime) { const oscillator = this.audioContext.createOscillator(); const gainNode = this.audioContext.createGain(); oscillator.frequency.value = frequency; gainNode.gain.setValueAtTime(0, startTime); gainNode.gain.linearRampToValueAtTime(0.1, startTime + 0.01); gainNode.gain.linearRampToValueAtTime(0, startTime + 0.1); oscillator.connect(gainNode); gainNode.connect(this.audioContext.destination); return oscillator; } } class CountdownTimer { constructor() { this.intervalId = null; this.alarmIntervalId = null; this.pageTitle = document.title; if (isFullScreen()) this.timerBoard = this.createBoard(); } start(seconds = 0, interval = 1) { let remaining = seconds; this.updateTitle(remaining); if (isFullScreen()) { this.showBoard(); this.updateBoard(remaining); } if (!this.intervalId) { this.intervalId = setInterval(() => { remaining -= interval; this.updateTitle(remaining); if (isFullScreen()) this.updateBoard(remaining); if (remaining <= 0) { this.teardown(); if (isFullScreen()) this.timerBoard.innerText = "Time's up!"; if (!isNoSound()) this.playAlarm(); } }, interval * 1000); } } playAlarm() { const alarm = new Alarm(); const interval = 1200; /* in milliseconds */ this.alarmIntervalId = setInterval(() => alarm.play(), interval); const totalDuration = 5000; /* in milliseconds */ alarm.play(); setTimeout(() => { this.teardown(); }, totalDuration); } teardown() { this.resetTitle(); if (this.intervalId) clearInterval(this.intervalId); if (this.alarmIntervalId) clearInterval(this.alarmIntervalId); this.intervalId = null; this.alarmIntervalId = null; } createBoard() { const timerBoard = document.createElement("div"); timerBoard.style.position = "fixed"; timerBoard.style.top = "0"; timerBoard.style.left = "0"; timerBoard.style.width = "100%"; timerBoard.style.height = "100%"; timerBoard.style.backgroundColor = "rgba(0, 0, 0, 0.9)"; timerBoard.style.zIndex = "999999"; timerBoard.style.display = "none"; timerBoard.style.justifyContent = "center"; timerBoard.style.alignItems = "center"; timerBoard.style.color = "white"; timerBoard.style.fontSize = "10rem"; timerBoard.style.fontWeight = "bold"; timerBoard.style.textAlign = "center"; timerBoard.onclick = () => { this.teardown(); this.timerBoard.remove(); }; document.body.appendChild(timerBoard); return timerBoard; } showBoard() { console.log("showBoard"); this.timerBoard.style.display = "flex"; } updateBoard(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); this.timerBoard.innerText = `${minutesString}:${secondsString}`; } updateTitle(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); document.title = `${minutesString}:${secondsString}`; } resetTitle() { document.title = this.pageTitle; } } const timer = new CountdownTimer(); const seconds = Number( prompt("Enter timer seconds in seconds:", String(300)) ); if (seconds > 0) timer.start(seconds); })("no-sound");

Full Screen(Alarm, Title, FullScreen)

javascript: (function (pattern) { const PATTERN = { NORMAL: "normal", NO_SOUND: "no-sound", FULL_SCREEN: "full-screen", FULL_SCREEN_NO_SOUND: "full-screen-no-sound", }; const isFullScreen = () => { return ( pattern === PATTERN.FULL_SCREEN || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; const isNoSound = () => { return ( pattern === PATTERN.NO_SOUND || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; class Alarm { constructor() { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.audioContext.resume(); } play() { const startTime = this.audioContext.currentTime; const beepFrequency = 800; /* Frequency in Hz */ Array.from({ length: 3 }).forEach((_, index) => { const beep = this.createBeep(beepFrequency, startTime + index * 0.2); beep.start(startTime + index * 0.2); beep.stop(startTime + index * 0.2 + 0.1); }); } createBeep(frequency, startTime) { const oscillator = this.audioContext.createOscillator(); const gainNode = this.audioContext.createGain(); oscillator.frequency.value = frequency; gainNode.gain.setValueAtTime(0, startTime); gainNode.gain.linearRampToValueAtTime(0.1, startTime + 0.01); gainNode.gain.linearRampToValueAtTime(0, startTime + 0.1); oscillator.connect(gainNode); gainNode.connect(this.audioContext.destination); return oscillator; } } class CountdownTimer { constructor() { this.intervalId = null; this.alarmIntervalId = null; this.pageTitle = document.title; if (isFullScreen()) this.timerBoard = this.createBoard(); } start(seconds = 0, interval = 1) { let remaining = seconds; this.updateTitle(remaining); if (isFullScreen()) { this.showBoard(); this.updateBoard(remaining); } if (!this.intervalId) { this.intervalId = setInterval(() => { remaining -= interval; this.updateTitle(remaining); if (isFullScreen()) this.updateBoard(remaining); if (remaining <= 0) { this.teardown(); if (isFullScreen()) this.timerBoard.innerText = "Time's up!"; if (!isNoSound()) this.playAlarm(); } }, interval * 1000); } } playAlarm() { const alarm = new Alarm(); const interval = 1200; /* in milliseconds */ this.alarmIntervalId = setInterval(() => alarm.play(), interval); const totalDuration = 5000; /* in milliseconds */ alarm.play(); setTimeout(() => { this.teardown(); }, totalDuration); } teardown() { this.resetTitle(); if (this.intervalId) clearInterval(this.intervalId); if (this.alarmIntervalId) clearInterval(this.alarmIntervalId); this.intervalId = null; this.alarmIntervalId = null; } createBoard() { const timerBoard = document.createElement("div"); timerBoard.style.position = "fixed"; timerBoard.style.top = "0"; timerBoard.style.left = "0"; timerBoard.style.width = "100%"; timerBoard.style.height = "100%"; timerBoard.style.backgroundColor = "rgba(0, 0, 0, 0.9)"; timerBoard.style.zIndex = "999999"; timerBoard.style.display = "none"; timerBoard.style.justifyContent = "center"; timerBoard.style.alignItems = "center"; timerBoard.style.color = "white"; timerBoard.style.fontSize = "10rem"; timerBoard.style.fontWeight = "bold"; timerBoard.style.textAlign = "center"; timerBoard.onclick = () => { this.teardown(); this.timerBoard.remove(); }; document.body.appendChild(timerBoard); return timerBoard; } showBoard() { console.log("showBoard"); this.timerBoard.style.display = "flex"; } updateBoard(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); this.timerBoard.innerText = `${minutesString}:${secondsString}`; } updateTitle(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); document.title = `${minutesString}:${secondsString}`; } resetTitle() { document.title = this.pageTitle; } } const timer = new CountdownTimer(); const seconds = Number( prompt("Enter timer seconds in seconds:", String(300)) ); if (seconds > 0) timer.start(seconds); })("full-screen");

Full Screen No Sound(Title, FullScreen)

javascript: (function (pattern) { const PATTERN = { NORMAL: "normal", NO_SOUND: "no-sound", FULL_SCREEN: "full-screen", FULL_SCREEN_NO_SOUND: "full-screen-no-sound", }; const isFullScreen = () => { return ( pattern === PATTERN.FULL_SCREEN || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; const isNoSound = () => { return ( pattern === PATTERN.NO_SOUND || pattern === PATTERN.FULL_SCREEN_NO_SOUND ); }; class Alarm { constructor() { this.audioContext = new (window.AudioContext || window.webkitAudioContext)(); this.audioContext.resume(); } play() { const startTime = this.audioContext.currentTime; const beepFrequency = 800; /* Frequency in Hz */ Array.from({ length: 3 }).forEach((_, index) => { const beep = this.createBeep(beepFrequency, startTime + index * 0.2); beep.start(startTime + index * 0.2); beep.stop(startTime + index * 0.2 + 0.1); }); } createBeep(frequency, startTime) { const oscillator = this.audioContext.createOscillator(); const gainNode = this.audioContext.createGain(); oscillator.frequency.value = frequency; gainNode.gain.setValueAtTime(0, startTime); gainNode.gain.linearRampToValueAtTime(0.1, startTime + 0.01); gainNode.gain.linearRampToValueAtTime(0, startTime + 0.1); oscillator.connect(gainNode); gainNode.connect(this.audioContext.destination); return oscillator; } } class CountdownTimer { constructor() { this.intervalId = null; this.alarmIntervalId = null; this.pageTitle = document.title; if (isFullScreen()) this.timerBoard = this.createBoard(); } start(seconds = 0, interval = 1) { let remaining = seconds; this.updateTitle(remaining); if (isFullScreen()) { this.showBoard(); this.updateBoard(remaining); } if (!this.intervalId) { this.intervalId = setInterval(() => { remaining -= interval; this.updateTitle(remaining); if (isFullScreen()) this.updateBoard(remaining); if (remaining <= 0) { this.teardown(); if (isFullScreen()) this.timerBoard.innerText = "Time's up!"; if (!isNoSound()) this.playAlarm(); } }, interval * 1000); } } playAlarm() { const alarm = new Alarm(); const interval = 1200; /* in milliseconds */ this.alarmIntervalId = setInterval(() => alarm.play(), interval); const totalDuration = 5000; /* in milliseconds */ alarm.play(); setTimeout(() => { this.teardown(); }, totalDuration); } teardown() { this.resetTitle(); if (this.intervalId) clearInterval(this.intervalId); if (this.alarmIntervalId) clearInterval(this.alarmIntervalId); this.intervalId = null; this.alarmIntervalId = null; } createBoard() { const timerBoard = document.createElement("div"); timerBoard.style.position = "fixed"; timerBoard.style.top = "0"; timerBoard.style.left = "0"; timerBoard.style.width = "100%"; timerBoard.style.height = "100%"; timerBoard.style.backgroundColor = "rgba(0, 0, 0, 0.9)"; timerBoard.style.zIndex = "999999"; timerBoard.style.display = "none"; timerBoard.style.justifyContent = "center"; timerBoard.style.alignItems = "center"; timerBoard.style.color = "white"; timerBoard.style.fontSize = "10rem"; timerBoard.style.fontWeight = "bold"; timerBoard.style.textAlign = "center"; timerBoard.onclick = () => { this.teardown(); this.timerBoard.remove(); }; document.body.appendChild(timerBoard); return timerBoard; } showBoard() { console.log("showBoard"); this.timerBoard.style.display = "flex"; } updateBoard(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); this.timerBoard.innerText = `${minutesString}:${secondsString}`; } updateTitle(seconds) { const minutesString = String(Math.floor(seconds / 60)).padStart(2, "0"); const secondsString = String(seconds % 60).padStart(2, "0"); document.title = `${minutesString}:${secondsString}`; } resetTitle() { document.title = this.pageTitle; } } const timer = new CountdownTimer(); const seconds = Number( prompt("Enter timer seconds in seconds:", String(300)) ); if (seconds > 0) timer.start(seconds); })("full-screen-no-sound");