
Complete video lectures, notes, and source code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Modern Digital Clock & Alarms</title>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&family=Roboto:wght@300;400;500&family=VT323&display=swap" rel="stylesheet">
<style>
:root {
--primary-color: #00f2ff;
--bg-color: #121212;
--card-bg: #1e1e1e;
--text-color: #ffffff;
--danger-color: #ff4757;
}
body {
font-family: 'Roboto', sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: var(--bg-color);
color: var(--text-color);
margin: 0;
}
.container {
background-color: var(--card-bg);
padding: 40px;
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
text-align: center;
width: 350px;
position: relative;
z-index: 1;
}
#clock {
font-family: 'VT323', monospace;
font-size: 80px;
color: var(--primary-color);
margin-bottom: 30px;
text-shadow: 0 0 10px rgba(0, 242, 255, 0.5);
}
.input-group {
display: flex;
justify-content: center;
gap: 10px;
margin-bottom: 20px;
}
input {
width: 50px;
padding: 10px;
background: #2c2c2c;
border: 1px solid #333;
border-radius: 8px;
color: white;
font-size: 18px;
text-align: center;
font-family: 'VT323', monospace;
font-size: 24px;
}
input:focus {
outline: none;
border-color: var(--primary-color);
}
button {
padding: 12px 24px;
font-size: 16px;
cursor: pointer;
border: none;
border-radius: 8px;
font-weight: 500;
transition: transform 0.1s, opacity 0.2s;
}
button:active {
transform: scale(0.98);
}
#addAlarmBtn {
background-color: var(--primary-color);
color: #000;
width: 100%;
margin-bottom: 20px;
}
#stopAlarmBtn {
background-color: var(--danger-color);
color: white;
width: 100%;
display: none;
animation: pulse 1s infinite;
}
.alarm-list {
list-style: none;
padding: 0;
margin: 0;
max-height: 200px;
overflow-y: auto;
text-align: left;
}
.alarm-item {
background: #2c2c2c;
padding: 10px 15px;
border-radius: 8px;
margin-bottom: 8px;
display: flex;
justify-content: space-between;
align-items: center;
font-family: 'VT323', monospace;
font-size: 22px;
}
.delete-btn {
background: transparent;
color: var(--danger-color);
padding: 5px;
font-size: 18px;
}
.delete-btn:hover {
color: #ff6b81;
}
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(255, 71, 87, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(255, 71, 87, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 71, 87, 0); }
}
/* Scrollbar styling */
.alarm-list::-webkit-scrollbar {
width: 5px;
}
.alarm-list::-webkit-scrollbar-thumb {
background: #444;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<div id="clock">00:00:00</div>
<div class="input-group">
<input type="number" id="hour" placeholder="HH" min="0" max="23" value="00">
<input type="number" id="minute" placeholder="MM" min="0" max="59" value="00">
<input type="number" id="second" placeholder="SS" min="0" max="59" value="00">
</div>
<button id="addAlarmBtn" onclick="addAlarm()">Add Alarm</button>
<button id="stopAlarmBtn" onclick="stopAlarm()">STOP ALARM</button>
<ul class="alarm-list" id="alarmList">
<!-- Alarms will appear here -->
</ul>
</div>
<!-- Ensure you have an 'alarm.mp3' file in the same directory -->
<audio id="alarmSound" src="mixkit-classic-alarm-995.wav" loop></audio>
<script>
let alarms = [];
let isRinging = false;
const audio = document.getElementById('alarmSound');
const alarmListEl = document.getElementById('alarmList');
function updateTime() {
const now = new Date();
const h = String(now.getHours()).padStart(2, '0');
const m = String(now.getMinutes()).padStart(2, '0');
const s = String(now.getSeconds()).padStart(2, '0');
const currentTime = `${h}:${m}:${s}`;
document.getElementById('clock').innerText = currentTime;
// Check alarms
const alarmsTriggered = alarms.filter(a => a.time === currentTime);
if (alarmsTriggered.length > 0 && !isRinging) {
startAlarm();
// Remove triggered alarms from the list
alarms = alarms.filter(a => a.time !== currentTime);
renderAlarms();
}
}
function startAlarm() {
isRinging = true;
audio.play().catch(e => console.error("Audio play failed:", e));
document.getElementById('addAlarmBtn').style.display = 'none';
document.getElementById('stopAlarmBtn').style.display = 'block';
}
function stopAlarm() {
isRinging = false;
audio.pause();
audio.currentTime = 0;
document.getElementById('addAlarmBtn').style.display = 'block';
document.getElementById('stopAlarmBtn').style.display = 'none';
}
function addAlarm() {
const h = String(document.getElementById('hour').value).padStart(2, '0');
const m = String(document.getElementById('minute').value).padStart(2, '0');
const s = String(document.getElementById('second').value).padStart(2, '0');
const timeString = `${h}:${m}:${s}`;
// Prevent duplicates
if (alarms.some(a => a.time === timeString)) {
alert("Alarm already set for this time!");
return;
}
alarms.push({ time: timeString });
alarms.sort((a, b) => a.time.localeCompare(b.time)); // Sort by time
renderAlarms();
// Unlock audio on user interaction (for browsers that block autoplay)
if (audio.paused) {
audio.play().then(() => {
audio.pause();
audio.currentTime = 0;
}).catch(e => {});
}
}
function removeAlarm(index) {
alarms.splice(index, 1);
renderAlarms();
}
function renderAlarms() {
alarmListEl.innerHTML = '';
alarms.forEach((alarm, index) => {
const li = document.createElement('li');
li.className = 'alarm-item';
li.innerHTML = `
<span>${alarm.time}</span>
<button class="delete-btn" onclick="removeAlarm(${index})">×</button>
`;
alarmListEl.appendChild(li);
});
}
setInterval(updateTime, 1000);
updateTime(); // Initial call to avoid 1s delay
</script>
<script src="script.js"></script>
</body>
</html>
body { background-color: #f4f4f4; } h1 { color: #333; }
document.addEventListener('DOMContentLoaded', function() {
var div = document.createElement('div'),
canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
w,
h,
msTimer = 0.0,
lightningTimer,
lightningAlpha,
rainArr = [50],
rainSpeed = 4;
// initialize
function init() {
document.body.appendChild(div);
div.style.position = "fixed";
div.appendChild(canvas);
UpdatePosition();
create_rain();
lightningTimer = 8000.0;
lightningAlpha = 0.0;
// 1 frame every 30ms
if (typeof game_loop != "undefined") clearInterval(game_loop);
game_loop = setInterval(mainLoop, 30);
}
init();
function create_rain() {
var length = 500;
rainArr = []; //Empty array to start with
for (var i = length - 1; i >= 0; i--) {
rainArr.push({
x: 1,
y: 0,
z: 0
});
}
for (var j = 0; j < 500; j++) {
rainArr[j].x = Math.floor((Math.random() * 820) - 9);
rainArr[j].y = Math.floor((Math.random() * 520) - 9);
rainArr[j].z = Math.floor((Math.random() * 2) + 1);
rainArr[j].w = Math.floor((Math.random() * 3) + 2);
}
}
function mainLoop() {
UpdatePosition();
msTimer += 30;
if (lightningTimer < 0.0) {
lightningTimer = 8000.0;
}
else {
lightningTimer -= 30.0;
}
ctx.fillStyle = "#202426";
ctx.fillRect(0,0,w,h);
sidewalk();
road();
lamp();
rain();
if (lightningTimer < 500.0) {
weather(lightningTimer);
}
ctx.fillStyle = 'rgba(255, 255, 255, .1)';
ctx.font = '30px Sans-Serif';
ctx.fillText("Ashish", w - 150, 492);
}
// canvas positioning and sizing
function UpdatePosition () {
var bodyWidth = document.documentElement.clientWidth,
bodyHeight = document.documentElement.clientHeight;
w = canvas.width = Math.max(500,bodyWidth);
h = canvas.height = Math.max(320,bodyHeight);
div.style.left=div.style.right=
div.style.top=div.style.bottom="0";
}
// lamp visuals
function lamp() {
var grd = ctx.createLinearGradient(150, 210, 150, 500);
grd.addColorStop(0.000, 'rgba(60, 60, 60, 1.000)');
grd.addColorStop(0.2, 'rgba(80, 80, 80, 1.000)');
grd.addColorStop(1, 'rgba(45, 45, 45, 1.000)');
ctx.fillStyle = grd;
ctx.fillRect(247, 210, 6, 290);
var grdOuterHigh = ctx.createLinearGradient(150, 210, 150, 500);
grdOuterHigh.addColorStop(0.000, 'rgba(65, 65, 65, 1.000)');
grdOuterHigh.addColorStop(0.2, 'rgba(95, 95, 95, 1.000)');
grdOuterHigh.addColorStop(1, 'rgba(47, 47, 47, 1.000)');
ctx.fillStyle = grdOuterHigh;
ctx.fillRect(246, 210, 1, 290);
var grdOuterLow = ctx.createLinearGradient(150, 210, 150, 500);
grdOuterLow.addColorStop(0.000, 'rgba(45, 45, 45, 1.000)');
grdOuterLow.addColorStop(0.2, 'rgba(60, 60, 60, 1.000)');
grdOuterLow.addColorStop(1, 'rgba(43, 43, 43, 1.000)');
ctx.fillStyle = grdOuterLow;
ctx.fillRect(253, 210, 1, 290);
// glow modified by time passed
var sinGlowMod = 5 * Math.sin(msTimer / 200);
var cosGlowMod = 5 * Math.cos((msTimer + 0.5 * sinGlowMod) / 200);
var grdGlow = ctx.createRadialGradient(250, 200, 0, 247 + sinGlowMod,
400, 206 + cosGlowMod);
grdGlow.addColorStop(0.000, 'rgba(220, 240, 160, 1)');
grdGlow.addColorStop(0.2, 'rgba(180, 240, 160, 0.4)');
grdGlow.addColorStop(0.4, 'rgba(140, 240, 160, 0.2)');
grdGlow.addColorStop(1, 'rgba(140, 240, 160, 0)');
ctx.fillStyle = grdGlow;
ctx.fillRect(0, 0, 500, 500);
}
// function to position and color each rain drop
// TODO: optimize - group raindrops together
function rain() {
for (var i = 0; i < 500; i++) {
if (rainArr[i].y >= 482) {
rainArr[i].y-=500;
}
if (rainArr[i].x < -10) {
rainArr[i].x+=w;
}
else {
rainArr[i].y += rainArr[i].w * rainSpeed;
rainArr[i].x -= 5 + Math.floor(rainArr[i].y / 250) - rainArr[i].w;
}
var grd = ctx.createRadialGradient(250, 450, 140, 250, 300, 600);
grd.addColorStop(0.000, 'rgba(100, 170, 160, 0.2)');
grd.addColorStop(0.1, 'rgba(100, 160, 160, 0.12)');
grd.addColorStop(0.2, 'rgba(100, 150, 150, 0.1)');
grd.addColorStop(1, 'rgba(100, 140, 140, .08)');
ctx.fillStyle = grd;
ctx.fillRect(rainArr[i].x, rainArr[i].y, rainArr[i].z, 4);
}
}
// sidewalk visuals
function sidewalk()
{
ctx.fillStyle = '#343A34';
ctx.fillRect(0,500,w,10);
var grd = ctx.createRadialGradient(250, 500, 0,
250, 500, 150);
grd.addColorStop(0.0, 'rgba(32, 36, 38, .0)');
grd.addColorStop(0.2, 'rgba(32, 36, 38, 0.1)');
grd.addColorStop(0.6, 'rgba(32, 36, 38, 0.2)');
grd.addColorStop(0.8, 'rgba(32, 36, 38, 0.6)');
grd.addColorStop(1, 'rgba(32, 34, 38, .8)');
ctx.fillStyle = grd;
ctx.fillRect(0,500,w,10);
ctx.fillStyle = '#343A34';
ctx.fillRect(0,510,w,10);
grd = ctx.createRadialGradient(250, 500, 0,
250, 500, 150);
grd.addColorStop(0.0, 'rgba(32, 36, 38, 0.7)');
grd.addColorStop(0.2, 'rgba(32, 36, 38, 0.8)');
grd.addColorStop(0.4, 'rgba(32, 36, 38, 0.85)');
grd.addColorStop(1, 'rgba(32, 34, 38, .9)');
ctx.fillStyle = grd;
ctx.fillRect(0,510,w,10);
}
// road visuals
function road() {
ctx.fillStyle = '#202224';
ctx.fillRect(0,520,w,h-520);
}
// function to create a lightning effect on a timer
function weather(_lTimer) {
lightningAlpha = 0.0;
if ( _lTimer > 350.0) {
lightningAlpha = (500.0 - _lTimer) * 0.004;
}
else if (_lTimer < 350.0 && _lTimer > 250.0) {
lightningAlpha = (_lTimer - 250.0) * 0.006;
}
else if (_lTimer < 250.0 && _lTimer >= 100.0) {
lightningAlpha = (250.0 - _lTimer) * 0.004;
}
else if (_lTimer < 100.0 && _lTimer >= 0.0) {
lightningAlpha = _lTimer * 0.006;
}
if (lightningAlpha > 0.0) {
ctx.fillStyle = 'rgba(250, 250, 245, ' + lightningAlpha + ')';
ctx.fillRect(0,0,w,h);
}
}
});