From dda693d0e5ec2714ea7e1ff7a171ed827f3d9098 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 12:58:32 +0800 Subject: [PATCH 01/14] Add animated sky theme with sunrise and rooster alarm --- index.css | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++- index.html | 36 ++++++++++++++++- index.js | 83 +++++++++++++++++++++++++++++++++---- index.pug | 7 +++- index.styl | 81 ++++++++++++++++++++++++++++++++++++- 5 files changed, 311 insertions(+), 13 deletions(-) diff --git a/index.css b/index.css index 8952c56..cbd413d 100644 --- a/index.css +++ b/index.css @@ -10,17 +10,112 @@ body { -moz-user-select: moz-none; -ms-user-select: none; user-select: none; + overflow: hidden; } + +#sky { + position: relative; + width: 100%; + height: 100%; + background: linear-gradient(180deg, #8fd3ff 0%, #cfefff 60%, #f7fbff 100%); + overflow: hidden; +} + +#sun { + position: absolute; + left: 50%; + bottom: -25vh; + width: 140px; + height: 140px; + margin-left: -70px; + border-radius: 50%; + background: radial-gradient(circle at 30% 30%, #fff7c7, #ffd25a 60%, #ffba29 100%); + box-shadow: 0 0 40px rgba(255, 188, 38, 0.7), 0 0 80px rgba(255, 188, 38, 0.35); + transition: bottom 0.4s linear; +} + +.cloud { + position: absolute; + top: 15%; + width: 180px; + height: 60px; + background: #fff; + border-radius: 50px; + box-shadow: 40px 10px 0 10px #fff, 90px 15px 0 5px #fff, 130px 5px 0 0 #fff; + opacity: 0.85; + animation: drift 48s linear infinite; +} + +.cloud:before, +.cloud:after { + content: ""; + position: absolute; + background: #fff; + border-radius: 50%; +} + +.cloud:before { + width: 60px; + height: 60px; + top: -25px; + left: 20px; +} + +.cloud:after { + width: 80px; + height: 80px; + top: -35px; + left: 70px; +} + +.cloud.c1 { + top: 20%; + left: -200px; + animation-duration: 52s; +} + +.cloud.c2 { + top: 35%; + left: -320px; + animation-duration: 60s; + animation-delay: -10s; + transform: scale(1.2); +} + +.cloud.c3 { + top: 55%; + left: -260px; + animation-duration: 56s; + animation-delay: -20s; + transform: scale(0.9); +} + +@keyframes drift { + 0% { + transform: translateX(0); + } + 100% { + transform: translateX(140%); + } +} + #timer { + position: absolute; + top: 0; + left: 0; width: 100%; height: 100%; line-height: 100%; - background: #000; color: #fff; text-align: center; font-weight: 700; - font-family: century gothic; + font-family: century gothic, "Helvetica Neue", Arial, sans-serif; + text-shadow: 0 0 10px rgba(0, 0, 0, 0.35); + display: flex; + align-items: center; + justify-content: center; } + #hide, #toggle, #reset, @@ -44,19 +139,23 @@ body { height: 44px; line-height: 30px; } + #reset { margin-left: 50px; } + #hide { margin-left: -30px; width: 70px; } + #min10, #min60, #add10, #add60 { width: 50px; } + #def10, #def30, #def60, @@ -69,48 +168,62 @@ body { top: auto; width: 70px; } + #min10 { margin-left: -270px; } + #min60 { margin-left: -330px; } + #add10 { margin-left: 230px; } + #add60 { margin-left: 290px; } + #def10 { margin-left: -285px; } + #def30 { margin-left: -205px; } + #def60 { margin-left: -125px; } + #def180 { margin-left: -45px; } + #def300 { margin-left: 35px; } + #def600 { margin-left: 115px; } + #def900 { margin-left: 195px; } + #def1800 { margin-left: 275px; } + #audio { position: absolute; bottom: 30px; right: 10px; z-index: 10; } + #xxx { position: absolute; top: 10px; diff --git a/index.html b/index.html index fbd0173..003867d 100644 --- a/index.html +++ b/index.html @@ -1 +1,35 @@ -
????
-60-10RUNRESET+10+6010 sec30 sec1 min3 min5 min10 min15 min30 min \ No newline at end of file + + + + + + + + + + + +
+
+
+
+
+
????
+
+ -60 + -10 + RUN + RESET + + +10 + +60 + 10 sec + 30 sec + 1 min + 3 min + 5 min + 10 min + 15 min + 30 min + + diff --git a/index.js b/index.js index dd7b28e..1e8215f 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, audioEnd, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sun, sunDuration, roosterContext, roosterTimers, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, triggerRoosterCrow, stopRoosterCrow; start = null; isBlink = false; isLight = true; @@ -11,7 +11,10 @@ latency = 0; stopBy = null; delay = 60000; audioRemind = null; -audioEnd = null; +sun = null; +sunDuration = 0; +roosterContext = null; +roosterTimers = []; newAudio = function(file){ var x$, node; x$ = node = new Audio(); @@ -48,6 +51,10 @@ adjust = function(it, v){ delay = 0; } $('#timer').text(delay); + if (!isRun) { + sunDuration = delay; + updateSunPosition(delay); + } return resize(); }; toggle = function(){ @@ -57,7 +64,7 @@ toggle = function(){ stopBy = new Date(); clearInterval(handler); handler = null; - soundToggle(audioEnd, false); + stopRoosterCrow(); soundToggle(audioRemind, false); } if (stopBy) { @@ -72,7 +79,7 @@ reset = function(){ delay = 1000; } soundToggle(audioRemind, false); - soundToggle(audioEnd, false); + stopRoosterCrow(); stopBy = 0; isWarned = false; isBlink = false; @@ -86,6 +93,8 @@ reset = function(){ handler = null; $('#timer').text(delay); $('#timer').css('color', '#fff'); + sunDuration = delay; + updateSunPosition(delay); return resize(); }; blink = function(){ @@ -97,6 +106,7 @@ count = function(){ var tm, diff; tm = $('#timer'); diff = start.getTime() - new Date().getTime() + delay + latency; + updateSunPosition(Math.max(0, diff)); if (diff > 60000) { isWarned = false; } @@ -108,7 +118,8 @@ count = function(){ soundToggle(audioRemind, false); } if (diff < 0 && !isBlink) { - soundToggle(audioEnd, true); + triggerRoosterCrow(); + updateSunPosition(0); isBlink = true; diff = 0; clearInterval(handler); @@ -124,6 +135,8 @@ run = function(){ start = new Date(); latency = 0; isBlink = false; + sunDuration = delay; + updateSunPosition(delay); } if (handler) { clearInterval(handler); @@ -148,11 +161,67 @@ resize = function(){ tm.css('font-size', 1.5 * w / len + "px"); return tm.css('line-height', h + "px"); }; +updateSunPosition = function(remaining){ + var progress, target; + if (!sun || sunDuration <= 0) { + return; + } + progress = 1 - remaining / sunDuration; + if (progress < 0) { + progress = 0; + } + if (progress > 1) { + progress = 1; + } + target = -25 + progress * 95; + return sun.style.bottom = target + "vh"; +}; +triggerRoosterCrow = function(){ + var ctx, base, i$; + stopRoosterCrow(); + ctx = roosterContext || (roosterContext = new (window.AudioContext || window.webkitAudioContext)()); + ctx.resume(); + base = ctx.currentTime + 0.05; + for (i$ = 0; i$ < 3; ++i$) { + (fn$.call(this, i$)); + } + function fn$(idx){ + var startTime, osc, gain; + startTime = base + idx * 1.1; + osc = ctx.createOscillator(); + gain = ctx.createGain(); + osc.type = 'square'; + osc.frequency.setValueAtTime(520, startTime); + osc.frequency.exponentialRampToValueAtTime(420, startTime + 0.18); + osc.frequency.exponentialRampToValueAtTime(540, startTime + 0.35); + osc.frequency.exponentialRampToValueAtTime(360, startTime + 0.55); + gain.gain.setValueAtTime(0.0001, startTime); + gain.gain.exponentialRampToValueAtTime(0.45, startTime + 0.05); + gain.gain.exponentialRampToValueAtTime(0.0001, startTime + 0.75); + osc.connect(gain); + gain.connect(ctx.destination); + osc.start(startTime); + osc.stop(startTime + 0.9); + return roosterTimers.push(setTimeout(function(){ + osc.disconnect(); + return gain.disconnect(); + }, (startTime - ctx.currentTime + 1) * 1000)); + } +}; +stopRoosterCrow = function(){ + var i$; + for (i$ = 0; i$ < roosterTimers.length; ++i$) { + clearTimeout(roosterTimers[i$]); + } + return roosterTimers = []; +}; window.onload = function(){ $('#timer').text(delay); + sun = document.getElementById('sun'); + sunDuration = delay; + updateSunPosition(delay); resize(); - audioRemind = newAudio('audio/smb_warning.mp3'); - return audioEnd = newAudio('audio/smb_mariodie.mp3'); + return audioRemind = newAudio('audio/smb_warning.mp3'); }; window.onresize = function(){ return resize(); diff --git a/index.pug b/index.pug index 7d258aa..522bbdb 100644 --- a/index.pug +++ b/index.pug @@ -8,7 +8,12 @@ html script(type="text/javascript",src="bootstrap3.min.js") script(type="text/javascript",src="index.js") body - #timer ???? + #sky + #sun + .cloud.c1 + .cloud.c2 + .cloud.c3 + #timer ???? a#min60.btn.btn-info.fbtn(onclick="adjust(-60)") -60 a#min10.btn.btn-info.fbtn(onclick="adjust(-10)") -10 a#toggle.btn.btn-primary(onclick="toggle()") RUN diff --git a/index.styl b/index.styl index bdf0e21..5bb3997 100644 --- a/index.styl +++ b/index.styl @@ -9,16 +9,93 @@ html, body -moz-user-select: moz-none -ms-user-select: none user-select: none + overflow: hidden + +#sky + position: relative + width: 100% + height: 100% + background: linear-gradient(180deg, #8fd3ff 0%, #cfefff 60%, #f7fbff 100%) + overflow: hidden + +#sun + position: absolute + left: 50% + bottom: -25vh + width: 140px + height: 140px + margin-left: -70px + border-radius: 50% + background: radial-gradient(circle at 30% 30%, #fff7c7, #ffd25a 60%, #ffba29 100%) + box-shadow: 0 0 40px rgba(255, 188, 38, 0.7), 0 0 80px rgba(255, 188, 38, 0.35) + transition: bottom 0.4s linear + +.cloud + position: absolute + top: 15% + width: 180px + height: 60px + background: #fff + border-radius: 50px + box-shadow: 40px 10px 0 10px #fff, 90px 15px 0 5px #fff, 130px 5px 0 0 #fff + opacity: 0.85 + animation: drift 48s linear infinite + &:before, &:after + content: "" + position: absolute + background: #fff + border-radius: 50% + &:before + width: 60px + height: 60px + top: -25px + left: 20px + &:after + width: 80px + height: 80px + top: -35px + left: 70px + +.cloud.c1 + top: 20% + left: -200px + animation-duration: 52s + +.cloud.c2 + top: 35% + left: -320px + animation-duration: 60s + animation-delay: -10s + transform: scale(1.2) + +.cloud.c3 + top: 55% + left: -260px + animation-duration: 56s + animation-delay: -20s + transform: scale(0.9) + +@keyframes drift + 0% + transform: translateX(0) + 100% + transform: translateX(140%) #timer + position: absolute + top: 0 + left: 0 width: 100% height: 100% line-height: 100% - background: #000 color: #fff text-align: center font-weight: 700 - font-family: century gothic + font-family: century gothic, "Helvetica Neue", Arial, sans-serif + text-shadow: 0 0 10px rgba(0, 0, 0, 0.35) + display: flex + align-items: center + justify-content: center #hide, #toggle, #reset, #min10, #min60, #add10, #add60, #def10, #def30, #def60, #def180, #def300, #def600, #def900, #def1800 position: absolute From 055d6289f9ae8ad1e9a3b28bf8cc380470655677 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 13:25:59 +0800 Subject: [PATCH 02/14] Animate sun and add rooster countdown cue --- index.css | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- index.html | 6 ++++- index.js | 50 ++++++++++++++++++++++++++++++++--- 3 files changed, 126 insertions(+), 7 deletions(-) diff --git a/index.css b/index.css index cbd413d..80b269c 100644 --- a/index.css +++ b/index.css @@ -21,17 +21,90 @@ body { overflow: hidden; } -#sun { +#sun-wrap { position: absolute; left: 50%; bottom: -25vh; + transform: translateX(-50%); + transition: bottom 0.4s linear; + pointer-events: none; +} + +#sun { + position: absolute; + left: 50%; + bottom: 0; width: 140px; height: 140px; margin-left: -70px; border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff7c7, #ffd25a 60%, #ffba29 100%); box-shadow: 0 0 40px rgba(255, 188, 38, 0.7), 0 0 80px rgba(255, 188, 38, 0.35); - transition: bottom 0.4s linear; + transition: transform 0.4s ease-out, box-shadow 0.4s ease-out; +} + +#sun-rays { + position: absolute; + left: 50%; + bottom: 0; + width: 260px; + height: 260px; + margin-left: -130px; + border-radius: 50%; + overflow: hidden; + filter: blur(2px); + opacity: 0; + transform: scale(0.8); + transition: opacity 0.4s ease-out, transform 0.4s ease-out; +} + +#sun-rays::before { + content: ""; + position: absolute; + top: -10%; + left: -10%; + width: 120%; + height: 120%; + border-radius: 50%; + background: repeating-conic-gradient(rgba(255, 220, 120, 0.35) 0deg, rgba(255, 220, 120, 0.35) 12deg, rgba(255, 220, 120, 0) 28deg, rgba(255, 220, 120, 0) 40deg); + animation: spin 16s linear infinite; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +#rooster { + position: absolute; + left: 50%; + bottom: 8vh; + transform: translateX(-50%) scale(0.6); + font-size: 110px; + opacity: 0; + transition: opacity 0.4s ease-out, transform 0.4s ease-out; + filter: drop-shadow(0 8px 4px rgba(0, 0, 0, 0.2)); + pointer-events: none; + z-index: 8; +} + +#rooster.show { + opacity: 1; + transform: translateX(-50%) scale(1); + animation: bob 0.8s ease-in-out infinite alternate; +} + +@keyframes bob { + from { + transform: translateX(-50%) translateY(0) scale(1); + } + to { + transform: translateX(-50%) translateY(-10px) scale(1.05); + } } .cloud { diff --git a/index.html b/index.html index 003867d..9444ce7 100644 --- a/index.html +++ b/index.html @@ -10,7 +10,11 @@
-
+
+
+
+
+
diff --git a/index.js b/index.js index 1e8215f..e48cf2c 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sun, sunDuration, roosterContext, roosterTimers, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, triggerRoosterCrow, stopRoosterCrow; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterContext, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -11,10 +11,14 @@ latency = 0; stopBy = null; delay = 60000; audioRemind = null; +sunWrap = null; sun = null; +sunRays = null; sunDuration = 0; roosterContext = null; roosterTimers = []; +rooster = null; +roosterShown = false; newAudio = function(file){ var x$, node; x$ = node = new Audio(); @@ -65,6 +69,7 @@ toggle = function(){ clearInterval(handler); handler = null; stopRoosterCrow(); + hideRooster(); soundToggle(audioRemind, false); } if (stopBy) { @@ -80,6 +85,7 @@ reset = function(){ } soundToggle(audioRemind, false); stopRoosterCrow(); + hideRooster(); stopBy = 0; isWarned = false; isBlink = false; @@ -117,8 +123,10 @@ count = function(){ if (diff < 55000) { soundToggle(audioRemind, false); } + if (diff <= 3000 && diff > 0 && !roosterShown) { + startRoosterCountdown(); + } if (diff < 0 && !isBlink) { - triggerRoosterCrow(); updateSunPosition(0); isBlink = true; diff = 0; @@ -163,7 +171,7 @@ resize = function(){ }; updateSunPosition = function(remaining){ var progress, target; - if (!sun || sunDuration <= 0) { + if (!sunWrap || !sun || sunDuration <= 0) { return; } progress = 1 - remaining / sunDuration; @@ -174,7 +182,31 @@ updateSunPosition = function(remaining){ progress = 1; } target = -25 + progress * 95; - return sun.style.bottom = target + "vh"; + sunWrap.style.bottom = target + "vh"; + return updateSunAppearance(progress); +}; +updateSunAppearance = function(progress){ + var scale, rayScale, glowStrength; + if (!sun || !sunRays) { + return; + } + scale = 1 + progress * 0.6; + rayScale = 0.9 + progress * 0.8; + glowStrength = 40 + progress * 60; + sun.style.transform = "scale(" + scale + ")"; + sun.style.boxShadow = "0 0 " + glowStrength + "px rgba(255, 188, 38, 0.8), 0 0 " + glowStrength * 1.6 + "px rgba(255, 188, 38, 0.4)"; + sunRays.style.opacity = 0.15 + progress * 0.7 + ""; + return sunRays.style.transform = "scale(" + rayScale + ")"; +}; +startRoosterCountdown = function(){ + if (roosterShown) { + return; + } + roosterShown = true; + if (rooster) { + rooster.classList.add('show'); + } + return triggerRoosterCrow(); }; triggerRoosterCrow = function(){ var ctx, base, i$; @@ -215,9 +247,19 @@ stopRoosterCrow = function(){ } return roosterTimers = []; }; +hideRooster = function(){ + roosterShown = false; + stopRoosterCrow(); + if (rooster) { + return rooster.classList.remove('show'); + } +}; window.onload = function(){ $('#timer').text(delay); + sunWrap = document.getElementById('sun-wrap'); sun = document.getElementById('sun'); + sunRays = document.getElementById('sun-rays'); + rooster = document.getElementById('rooster'); sunDuration = delay; updateSunPosition(delay); resize(); From d32fb503f1facb1f801a5200ac23cf0ca91fd8a9 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 13:35:31 +0800 Subject: [PATCH 03/14] Adjust sun and rooster behavior at countdown end --- index.css | 15 +++++++++------ index.js | 27 +++++++++++++++++++++------ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/index.css b/index.css index 80b269c..3bd1165 100644 --- a/index.css +++ b/index.css @@ -28,28 +28,30 @@ body { transform: translateX(-50%); transition: bottom 0.4s linear; pointer-events: none; + z-index: 7; } #sun { position: absolute; left: 50%; bottom: 0; - width: 140px; - height: 140px; - margin-left: -70px; + width: var(--sun-size, 140px); + height: var(--sun-size, 140px); + margin-left: calc(var(--sun-size, 140px) / -2); border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fff7c7, #ffd25a 60%, #ffba29 100%); box-shadow: 0 0 40px rgba(255, 188, 38, 0.7), 0 0 80px rgba(255, 188, 38, 0.35); transition: transform 0.4s ease-out, box-shadow 0.4s ease-out; + opacity: 0.6; } #sun-rays { position: absolute; left: 50%; bottom: 0; - width: 260px; - height: 260px; - margin-left: -130px; + width: var(--sun-ray-size, 260px); + height: var(--sun-ray-size, 260px); + margin-left: calc(var(--sun-ray-size, 260px) / -2); border-radius: 50%; overflow: hidden; filter: blur(2px); @@ -187,6 +189,7 @@ body { display: flex; align-items: center; justify-content: center; + z-index: 5; } #hide, diff --git a/index.js b/index.js index e48cf2c..f600746 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterContext, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterContext, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -123,10 +123,10 @@ count = function(){ if (diff < 55000) { soundToggle(audioRemind, false); } - if (diff <= 3000 && diff > 0 && !roosterShown) { - startRoosterCountdown(); - } if (diff < 0 && !isBlink) { + if (!roosterShown) { + startRoosterCountdown(); + } updateSunPosition(0); isBlink = true; diff = 0; @@ -134,6 +134,8 @@ count = function(){ handler = setInterval(function(){ return blink(); }, 500); + } else if (diff <= 0 && !roosterShown) { + startRoosterCountdown(); } tm.text(diff + ""); return resize(); @@ -160,14 +162,16 @@ run = function(){ } }; resize = function(){ - var tm, w, h, len; + var tm, w, h, len, fontSize; tm = $('#timer'); w = tm.width(); h = $(window).height(); len = tm.text().length; len >= 3 || (len = 3); tm.css('font-size', 1.5 * w / len + "px"); - return tm.css('line-height', h + "px"); + tm.css('line-height', h + "px"); + fontSize = parseFloat(tm.css('font-size')) || 0; + return updateSunSize(fontSize); }; updateSunPosition = function(remaining){ var progress, target; @@ -198,6 +202,17 @@ updateSunAppearance = function(progress){ sunRays.style.opacity = 0.15 + progress * 0.7 + ""; return sunRays.style.transform = "scale(" + rayScale + ")"; }; +updateSunSize = function(fontSize){ + var root, sunSize, raySize; + if (!fontSize) { + return; + } + root = document.documentElement.style; + sunSize = Math.max(80, Math.min(fontSize * 0.5, 260)); + raySize = sunSize * 1.8; + root.setProperty('--sun-size', sunSize + "px"); + return root.setProperty('--sun-ray-size', raySize + "px"); +}; startRoosterCountdown = function(){ if (roosterShown) { return; From 26c38c5246e50675330778485d98656569fcfdc4 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 14:43:19 +0800 Subject: [PATCH 04/14] Enhance sun animation and end-of-timer bird --- index.css | 34 +++++++++++++++++----------------- index.html | 2 +- index.js | 14 +++++++------- index.pug | 5 ++++- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/index.css b/index.css index 3bd1165..88db403 100644 --- a/index.css +++ b/index.css @@ -24,39 +24,39 @@ body { #sun-wrap { position: absolute; left: 50%; - bottom: -25vh; + bottom: -35vh; transform: translateX(-50%); transition: bottom 0.4s linear; pointer-events: none; - z-index: 7; + z-index: 9; } #sun { position: absolute; left: 50%; bottom: 0; - width: var(--sun-size, 140px); - height: var(--sun-size, 140px); - margin-left: calc(var(--sun-size, 140px) / -2); + width: var(--sun-size, 420px); + height: var(--sun-size, 420px); + margin-left: calc(var(--sun-size, 420px) / -2); border-radius: 50%; - background: radial-gradient(circle at 30% 30%, #fff7c7, #ffd25a 60%, #ffba29 100%); - box-shadow: 0 0 40px rgba(255, 188, 38, 0.7), 0 0 80px rgba(255, 188, 38, 0.35); + background: radial-gradient(circle at 30% 30%, #fffbe0, #ffd972 60%, #ffb52a 100%); + box-shadow: 0 0 70px rgba(255, 193, 55, 0.9), 0 0 140px rgba(255, 193, 55, 0.55); transition: transform 0.4s ease-out, box-shadow 0.4s ease-out; - opacity: 0.6; + opacity: 0.85; } #sun-rays { position: absolute; left: 50%; bottom: 0; - width: var(--sun-ray-size, 260px); - height: var(--sun-ray-size, 260px); - margin-left: calc(var(--sun-ray-size, 260px) / -2); + width: var(--sun-ray-size, 756px); + height: var(--sun-ray-size, 756px); + margin-left: calc(var(--sun-ray-size, 756px) / -2); border-radius: 50%; overflow: hidden; - filter: blur(2px); - opacity: 0; - transform: scale(0.8); + filter: blur(1px); + opacity: 0.25; + transform: scale(0.9); transition: opacity 0.4s ease-out, transform 0.4s ease-out; } @@ -68,7 +68,7 @@ body { width: 120%; height: 120%; border-radius: 50%; - background: repeating-conic-gradient(rgba(255, 220, 120, 0.35) 0deg, rgba(255, 220, 120, 0.35) 12deg, rgba(255, 220, 120, 0) 28deg, rgba(255, 220, 120, 0) 40deg); + background: repeating-conic-gradient(rgba(255, 225, 120, 0.55) 0deg, rgba(255, 225, 120, 0.55) 12deg, rgba(255, 225, 120, 0) 28deg, rgba(255, 225, 120, 0) 40deg); animation: spin 16s linear infinite; } @@ -85,8 +85,8 @@ body { position: absolute; left: 50%; bottom: 8vh; - transform: translateX(-50%) scale(0.6); - font-size: 110px; + transform: translateX(-50%) scale(0.7); + font-size: 90px; opacity: 0; transition: opacity 0.4s ease-out, transform 0.4s ease-out; filter: drop-shadow(0 8px 4px rgba(0, 0, 0, 0.2)); diff --git a/index.html b/index.html index 9444ce7..c7110a5 100644 --- a/index.html +++ b/index.html @@ -14,7 +14,7 @@
- +
diff --git a/index.js b/index.js index f600746..c125a73 100644 --- a/index.js +++ b/index.js @@ -194,12 +194,12 @@ updateSunAppearance = function(progress){ if (!sun || !sunRays) { return; } - scale = 1 + progress * 0.6; - rayScale = 0.9 + progress * 0.8; - glowStrength = 40 + progress * 60; + scale = 1.1 + progress * 0.9; + rayScale = 1 + progress * 0.8; + glowStrength = 70 + progress * 90; sun.style.transform = "scale(" + scale + ")"; - sun.style.boxShadow = "0 0 " + glowStrength + "px rgba(255, 188, 38, 0.8), 0 0 " + glowStrength * 1.6 + "px rgba(255, 188, 38, 0.4)"; - sunRays.style.opacity = 0.15 + progress * 0.7 + ""; + sun.style.boxShadow = "0 0 " + glowStrength + "px rgba(255, 193, 55, 0.9), 0 0 " + glowStrength * 1.8 + "px rgba(255, 193, 55, 0.5)"; + sunRays.style.opacity = 0.25 + progress * 0.7 + ""; return sunRays.style.transform = "scale(" + rayScale + ")"; }; updateSunSize = function(fontSize){ @@ -208,8 +208,8 @@ updateSunSize = function(fontSize){ return; } root = document.documentElement.style; - sunSize = Math.max(80, Math.min(fontSize * 0.5, 260)); - raySize = sunSize * 1.8; + sunSize = Math.max(180, Math.min(fontSize * 1.5, 780)); + raySize = sunSize * 1.9; root.setProperty('--sun-size', sunSize + "px"); return root.setProperty('--sun-ray-size', raySize + "px"); }; diff --git a/index.pug b/index.pug index 522bbdb..5394a75 100644 --- a/index.pug +++ b/index.pug @@ -9,7 +9,10 @@ html script(type="text/javascript",src="index.js") body #sky - #sun + #sun-wrap + #sun-rays + #sun + #rooster(aria-hidden="true") 🐦 .cloud.c1 .cloud.c2 .cloud.c3 From cc8d3804330e699531d874a14ae9d7c97ee11464 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 14:58:49 +0800 Subject: [PATCH 05/14] Shrink sun and show flapping bird at countdown end --- index.css | 43 ++++++++++++++++++++++++------------------- index.html | 2 +- index.js | 54 ++++++++++++++++++------------------------------------ 3 files changed, 43 insertions(+), 56 deletions(-) diff --git a/index.css b/index.css index 88db403..3060b3f 100644 --- a/index.css +++ b/index.css @@ -35,9 +35,9 @@ body { position: absolute; left: 50%; bottom: 0; - width: var(--sun-size, 420px); - height: var(--sun-size, 420px); - margin-left: calc(var(--sun-size, 420px) / -2); + width: var(--sun-size, 210px); + height: var(--sun-size, 210px); + margin-left: calc(var(--sun-size, 210px) / -2); border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fffbe0, #ffd972 60%, #ffb52a 100%); box-shadow: 0 0 70px rgba(255, 193, 55, 0.9), 0 0 140px rgba(255, 193, 55, 0.55); @@ -49,9 +49,9 @@ body { position: absolute; left: 50%; bottom: 0; - width: var(--sun-ray-size, 756px); - height: var(--sun-ray-size, 756px); - margin-left: calc(var(--sun-ray-size, 756px) / -2); + width: var(--sun-ray-size, 378px); + height: var(--sun-ray-size, 378px); + margin-left: calc(var(--sun-ray-size, 378px) / -2); border-radius: 50%; overflow: hidden; filter: blur(1px); @@ -84,28 +84,33 @@ body { #rooster { position: absolute; left: 50%; - bottom: 8vh; - transform: translateX(-50%) scale(0.7); - font-size: 90px; + bottom: calc(var(--sun-size, 210px) + 10px); + transform: translateX(-50%); + font-size: 68px; opacity: 0; - transition: opacity 0.4s ease-out, transform 0.4s ease-out; - filter: drop-shadow(0 8px 4px rgba(0, 0, 0, 0.2)); + transition: opacity 0.25s ease-out; + filter: drop-shadow(0 6px 4px rgba(0, 0, 0, 0.15)); pointer-events: none; - z-index: 8; + z-index: 11; } #rooster.show { opacity: 1; - transform: translateX(-50%) scale(1); - animation: bob 0.8s ease-in-out infinite alternate; } -@keyframes bob { - from { - transform: translateX(-50%) translateY(0) scale(1); +#rooster.flap { + animation: flap 0.55s ease-in-out 3 forwards; +} + +@keyframes flap { + 0% { + transform: translateX(-50%) translateY(0) rotate(0deg); } - to { - transform: translateX(-50%) translateY(-10px) scale(1.05); + 50% { + transform: translateX(-50%) translateY(8px) rotate(-10deg); + } + 100% { + transform: translateX(-50%) translateY(0) rotate(10deg); } } diff --git a/index.html b/index.html index c7110a5..57bd405 100644 --- a/index.html +++ b/index.html @@ -13,8 +13,8 @@
+
-
diff --git a/index.js b/index.js index c125a73..46bb503 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterContext, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -15,7 +15,6 @@ sunWrap = null; sun = null; sunRays = null; sunDuration = 0; -roosterContext = null; roosterTimers = []; rooster = null; roosterShown = false; @@ -208,58 +207,34 @@ updateSunSize = function(fontSize){ return; } root = document.documentElement.style; - sunSize = Math.max(180, Math.min(fontSize * 1.5, 780)); + sunSize = Math.max(90, Math.min(fontSize * 0.75, 390)); raySize = sunSize * 1.9; root.setProperty('--sun-size', sunSize + "px"); return root.setProperty('--sun-ray-size', raySize + "px"); }; startRoosterCountdown = function(){ - if (roosterShown) { + if (roosterShown || !rooster) { return; } roosterShown = true; - if (rooster) { - rooster.classList.add('show'); - } + rooster.classList.add('show'); return triggerRoosterCrow(); }; triggerRoosterCrow = function(){ - var ctx, base, i$; stopRoosterCrow(); - ctx = roosterContext || (roosterContext = new (window.AudioContext || window.webkitAudioContext)()); - ctx.resume(); - base = ctx.currentTime + 0.05; - for (i$ = 0; i$ < 3; ++i$) { - (fn$.call(this, i$)); - } - function fn$(idx){ - var startTime, osc, gain; - startTime = base + idx * 1.1; - osc = ctx.createOscillator(); - gain = ctx.createGain(); - osc.type = 'square'; - osc.frequency.setValueAtTime(520, startTime); - osc.frequency.exponentialRampToValueAtTime(420, startTime + 0.18); - osc.frequency.exponentialRampToValueAtTime(540, startTime + 0.35); - osc.frequency.exponentialRampToValueAtTime(360, startTime + 0.55); - gain.gain.setValueAtTime(0.0001, startTime); - gain.gain.exponentialRampToValueAtTime(0.45, startTime + 0.05); - gain.gain.exponentialRampToValueAtTime(0.0001, startTime + 0.75); - osc.connect(gain); - gain.connect(ctx.destination); - osc.start(startTime); - osc.stop(startTime + 0.9); - return roosterTimers.push(setTimeout(function(){ - osc.disconnect(); - return gain.disconnect(); - }, (startTime - ctx.currentTime + 1) * 1000)); - } + rooster.classList.add('flap'); + return roosterTimers.push(setTimeout(function(){ + return hideRooster(); + }, 1700)); }; stopRoosterCrow = function(){ var i$; for (i$ = 0; i$ < roosterTimers.length; ++i$) { clearTimeout(roosterTimers[i$]); } + if (rooster) { + rooster.classList.remove('flap'); + } return roosterTimers = []; }; hideRooster = function(){ @@ -275,6 +250,13 @@ window.onload = function(){ sun = document.getElementById('sun'); sunRays = document.getElementById('sun-rays'); rooster = document.getElementById('rooster'); + if (rooster) { + rooster.addEventListener('animationend', function(e){ + if (e.animationName === 'flap') { + return hideRooster(); + } + }); + } sunDuration = delay; updateSunPosition(delay); resize(); From 0df63923227d44da50ecdcf558e934c31942fbee Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 15:09:01 +0800 Subject: [PATCH 06/14] Shrink sun and make countdown configurable --- index.css | 15 ++++++----- index.js | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 80 insertions(+), 12 deletions(-) diff --git a/index.css b/index.css index 3060b3f..63fc388 100644 --- a/index.css +++ b/index.css @@ -24,7 +24,7 @@ body { #sun-wrap { position: absolute; left: 50%; - bottom: -35vh; + bottom: -60vh; transform: translateX(-50%); transition: bottom 0.4s linear; pointer-events: none; @@ -35,9 +35,9 @@ body { position: absolute; left: 50%; bottom: 0; - width: var(--sun-size, 210px); - height: var(--sun-size, 210px); - margin-left: calc(var(--sun-size, 210px) / -2); + width: var(--sun-size, 105px); + height: var(--sun-size, 105px); + margin-left: calc(var(--sun-size, 105px) / -2); border-radius: 50%; background: radial-gradient(circle at 30% 30%, #fffbe0, #ffd972 60%, #ffb52a 100%); box-shadow: 0 0 70px rgba(255, 193, 55, 0.9), 0 0 140px rgba(255, 193, 55, 0.55); @@ -49,9 +49,9 @@ body { position: absolute; left: 50%; bottom: 0; - width: var(--sun-ray-size, 378px); - height: var(--sun-ray-size, 378px); - margin-left: calc(var(--sun-ray-size, 378px) / -2); + width: var(--sun-ray-size, 189px); + height: var(--sun-ray-size, 189px); + margin-left: calc(var(--sun-ray-size, 189px) / -2); border-radius: 50%; overflow: hidden; filter: blur(1px); @@ -194,6 +194,7 @@ body { display: flex; align-items: center; justify-content: center; + cursor: pointer; z-index: 5; } diff --git a/index.js b/index.js index 46bb503..926a46a 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, parseTimeInput, promptSetCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -44,7 +44,19 @@ show = function(){ }; adjust = function(it, v){ if (isBlink) { - return; + if (handler) { + clearInterval(handler); + } + handler = null; + isBlink = false; + isLight = true; + $('#timer').css('color', '#fff'); + isRun = false; + $('#toggle').text("RUN"); + isWarned = false; + stopRoosterCrow(); + hideRooster(); + soundToggle(audioRemind, false); } delay = delay + it * 1000; if (it === 0) { @@ -60,6 +72,56 @@ adjust = function(it, v){ } return resize(); }; +parseTimeInput = function(input){ + var parts, sec, min, hour; + input = input != null ? input.trim() : ''; + if (!input) { + return null; + } + if (input.indexOf(':') !== -1) { + parts = input.split(':'); + if (parts.length === 2) { + min = parseInt(parts[0], 10); + sec = parseInt(parts[1], 10); + if (isNaN(min) || isNaN(sec)) { + return null; + } + return min * 60 + sec; + } else if (parts.length === 3) { + hour = parseInt(parts[0], 10); + min = parseInt(parts[1], 10); + sec = parseInt(parts[2], 10); + if (isNaN(hour) || isNaN(min) || isNaN(sec)) { + return null; + } + return hour * 3600 + min * 60 + sec; + } else { + return null; + } + } + sec = parseFloat(input); + if (isNaN(sec)) { + return null; + } + return sec; +}; +promptSetCountdown = function(){ + var suggestion, input, seconds; + suggestion = Math.max(1, Math.round(delay / 1000)); + input = window.prompt('Set countdown (seconds or mm:ss)', suggestion + ''); + if (input == null) { + return; + } + seconds = parseTimeInput(input); + if (seconds == null || seconds < 0) { + window.alert('Invalid time format'); + return; + } + if (isRun) { + toggle(); + } + return adjust(0, seconds); +}; toggle = function(){ isRun = !isRun; $('#toggle').text(isRun ? "STOP" : "RUN"); @@ -184,7 +246,7 @@ updateSunPosition = function(remaining){ if (progress > 1) { progress = 1; } - target = -25 + progress * 95; + target = -60 + progress * 40; sunWrap.style.bottom = target + "vh"; return updateSunAppearance(progress); }; @@ -207,8 +269,8 @@ updateSunSize = function(fontSize){ return; } root = document.documentElement.style; - sunSize = Math.max(90, Math.min(fontSize * 0.75, 390)); - raySize = sunSize * 1.9; + sunSize = Math.max(70, Math.min(fontSize * 0.4, 220)); + raySize = sunSize * 1.8; root.setProperty('--sun-size', sunSize + "px"); return root.setProperty('--sun-ray-size', raySize + "px"); }; @@ -260,6 +322,11 @@ window.onload = function(){ sunDuration = delay; updateSunPosition(delay); resize(); + $('#timer').attr('title', 'Click to set the countdown').attr('tabindex', '0').on('click keypress', function(e){ + if (e.type === 'click' || e.key === 'Enter') { + return promptSetCountdown(); + } + }); return audioRemind = newAudio('audio/smb_warning.mp3'); }; window.onresize = function(){ From dffaf8cf2806b923e7f18550639cb03d83fe9075 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 15:15:35 +0800 Subject: [PATCH 07/14] Remove sun visuals and fix countdown reset --- index.css | 93 ---------------------------------------- index.html | 5 --- index.js | 121 +++-------------------------------------------------- 3 files changed, 6 insertions(+), 213 deletions(-) diff --git a/index.css b/index.css index 63fc388..dfa08f2 100644 --- a/index.css +++ b/index.css @@ -21,99 +21,6 @@ body { overflow: hidden; } -#sun-wrap { - position: absolute; - left: 50%; - bottom: -60vh; - transform: translateX(-50%); - transition: bottom 0.4s linear; - pointer-events: none; - z-index: 9; -} - -#sun { - position: absolute; - left: 50%; - bottom: 0; - width: var(--sun-size, 105px); - height: var(--sun-size, 105px); - margin-left: calc(var(--sun-size, 105px) / -2); - border-radius: 50%; - background: radial-gradient(circle at 30% 30%, #fffbe0, #ffd972 60%, #ffb52a 100%); - box-shadow: 0 0 70px rgba(255, 193, 55, 0.9), 0 0 140px rgba(255, 193, 55, 0.55); - transition: transform 0.4s ease-out, box-shadow 0.4s ease-out; - opacity: 0.85; -} - -#sun-rays { - position: absolute; - left: 50%; - bottom: 0; - width: var(--sun-ray-size, 189px); - height: var(--sun-ray-size, 189px); - margin-left: calc(var(--sun-ray-size, 189px) / -2); - border-radius: 50%; - overflow: hidden; - filter: blur(1px); - opacity: 0.25; - transform: scale(0.9); - transition: opacity 0.4s ease-out, transform 0.4s ease-out; -} - -#sun-rays::before { - content: ""; - position: absolute; - top: -10%; - left: -10%; - width: 120%; - height: 120%; - border-radius: 50%; - background: repeating-conic-gradient(rgba(255, 225, 120, 0.55) 0deg, rgba(255, 225, 120, 0.55) 12deg, rgba(255, 225, 120, 0) 28deg, rgba(255, 225, 120, 0) 40deg); - animation: spin 16s linear infinite; -} - -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -#rooster { - position: absolute; - left: 50%; - bottom: calc(var(--sun-size, 210px) + 10px); - transform: translateX(-50%); - font-size: 68px; - opacity: 0; - transition: opacity 0.25s ease-out; - filter: drop-shadow(0 6px 4px rgba(0, 0, 0, 0.15)); - pointer-events: none; - z-index: 11; -} - -#rooster.show { - opacity: 1; -} - -#rooster.flap { - animation: flap 0.55s ease-in-out 3 forwards; -} - -@keyframes flap { - 0% { - transform: translateX(-50%) translateY(0) rotate(0deg); - } - 50% { - transform: translateX(-50%) translateY(8px) rotate(-10deg); - } - 100% { - transform: translateX(-50%) translateY(0) rotate(10deg); - } -} - .cloud { position: absolute; top: 15%; diff --git a/index.html b/index.html index 57bd405..f270764 100644 --- a/index.html +++ b/index.html @@ -10,11 +10,6 @@
-
-
-
- -
diff --git a/index.js b/index.js index 926a46a..2a1fd12 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, parseTimeInput, promptSetCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, newAudio, soundToggle, show, adjust, parseTimeInput, promptSetCountdown, toggle, reset, blink, count, run, resize; start = null; isBlink = false; isLight = true; @@ -11,13 +11,6 @@ latency = 0; stopBy = null; delay = 60000; audioRemind = null; -sunWrap = null; -sun = null; -sunRays = null; -sunDuration = 0; -roosterTimers = []; -rooster = null; -roosterShown = false; newAudio = function(file){ var x$, node; x$ = node = new Audio(); @@ -54,8 +47,9 @@ adjust = function(it, v){ isRun = false; $('#toggle').text("RUN"); isWarned = false; - stopRoosterCrow(); - hideRooster(); + start = null; + latency = 0; + stopBy = null; soundToggle(audioRemind, false); } delay = delay + it * 1000; @@ -66,10 +60,6 @@ adjust = function(it, v){ delay = 0; } $('#timer').text(delay); - if (!isRun) { - sunDuration = delay; - updateSunPosition(delay); - } return resize(); }; parseTimeInput = function(input){ @@ -129,8 +119,6 @@ toggle = function(){ stopBy = new Date(); clearInterval(handler); handler = null; - stopRoosterCrow(); - hideRooster(); soundToggle(audioRemind, false); } if (stopBy) { @@ -145,8 +133,6 @@ reset = function(){ delay = 1000; } soundToggle(audioRemind, false); - stopRoosterCrow(); - hideRooster(); stopBy = 0; isWarned = false; isBlink = false; @@ -160,8 +146,6 @@ reset = function(){ handler = null; $('#timer').text(delay); $('#timer').css('color', '#fff'); - sunDuration = delay; - updateSunPosition(delay); return resize(); }; blink = function(){ @@ -173,7 +157,6 @@ count = function(){ var tm, diff; tm = $('#timer'); diff = start.getTime() - new Date().getTime() + delay + latency; - updateSunPosition(Math.max(0, diff)); if (diff > 60000) { isWarned = false; } @@ -185,18 +168,13 @@ count = function(){ soundToggle(audioRemind, false); } if (diff < 0 && !isBlink) { - if (!roosterShown) { - startRoosterCountdown(); - } - updateSunPosition(0); + start = null; isBlink = true; diff = 0; clearInterval(handler); handler = setInterval(function(){ return blink(); }, 500); - } else if (diff <= 0 && !roosterShown) { - startRoosterCountdown(); } tm.text(diff + ""); return resize(); @@ -206,8 +184,6 @@ run = function(){ start = new Date(); latency = 0; isBlink = false; - sunDuration = delay; - updateSunPosition(delay); } if (handler) { clearInterval(handler); @@ -232,95 +208,10 @@ resize = function(){ tm.css('font-size', 1.5 * w / len + "px"); tm.css('line-height', h + "px"); fontSize = parseFloat(tm.css('font-size')) || 0; - return updateSunSize(fontSize); -}; -updateSunPosition = function(remaining){ - var progress, target; - if (!sunWrap || !sun || sunDuration <= 0) { - return; - } - progress = 1 - remaining / sunDuration; - if (progress < 0) { - progress = 0; - } - if (progress > 1) { - progress = 1; - } - target = -60 + progress * 40; - sunWrap.style.bottom = target + "vh"; - return updateSunAppearance(progress); -}; -updateSunAppearance = function(progress){ - var scale, rayScale, glowStrength; - if (!sun || !sunRays) { - return; - } - scale = 1.1 + progress * 0.9; - rayScale = 1 + progress * 0.8; - glowStrength = 70 + progress * 90; - sun.style.transform = "scale(" + scale + ")"; - sun.style.boxShadow = "0 0 " + glowStrength + "px rgba(255, 193, 55, 0.9), 0 0 " + glowStrength * 1.8 + "px rgba(255, 193, 55, 0.5)"; - sunRays.style.opacity = 0.25 + progress * 0.7 + ""; - return sunRays.style.transform = "scale(" + rayScale + ")"; -}; -updateSunSize = function(fontSize){ - var root, sunSize, raySize; - if (!fontSize) { - return; - } - root = document.documentElement.style; - sunSize = Math.max(70, Math.min(fontSize * 0.4, 220)); - raySize = sunSize * 1.8; - root.setProperty('--sun-size', sunSize + "px"); - return root.setProperty('--sun-ray-size', raySize + "px"); -}; -startRoosterCountdown = function(){ - if (roosterShown || !rooster) { - return; - } - roosterShown = true; - rooster.classList.add('show'); - return triggerRoosterCrow(); -}; -triggerRoosterCrow = function(){ - stopRoosterCrow(); - rooster.classList.add('flap'); - return roosterTimers.push(setTimeout(function(){ - return hideRooster(); - }, 1700)); -}; -stopRoosterCrow = function(){ - var i$; - for (i$ = 0; i$ < roosterTimers.length; ++i$) { - clearTimeout(roosterTimers[i$]); - } - if (rooster) { - rooster.classList.remove('flap'); - } - return roosterTimers = []; -}; -hideRooster = function(){ - roosterShown = false; - stopRoosterCrow(); - if (rooster) { - return rooster.classList.remove('show'); - } + return fontSize; }; window.onload = function(){ $('#timer').text(delay); - sunWrap = document.getElementById('sun-wrap'); - sun = document.getElementById('sun'); - sunRays = document.getElementById('sun-rays'); - rooster = document.getElementById('rooster'); - if (rooster) { - rooster.addEventListener('animationend', function(e){ - if (e.animationName === 'flap') { - return hideRooster(); - } - }); - } - sunDuration = delay; - updateSunPosition(delay); resize(); $('#timer').attr('title', 'Click to set the countdown').attr('tabindex', '0').on('click keypress', function(e){ if (e.type === 'click' || e.key === 'Enter') { From 1c0ea2642eaf1dc0dac66ef89b37ef55bfa856bc Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 15:24:18 +0800 Subject: [PATCH 08/14] Revert "Remove sun visuals and fix countdown reset" --- index.css | 93 ++++++++++++++++++++++++++++++++++++++++ index.html | 5 +++ index.js | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 213 insertions(+), 6 deletions(-) diff --git a/index.css b/index.css index dfa08f2..63fc388 100644 --- a/index.css +++ b/index.css @@ -21,6 +21,99 @@ body { overflow: hidden; } +#sun-wrap { + position: absolute; + left: 50%; + bottom: -60vh; + transform: translateX(-50%); + transition: bottom 0.4s linear; + pointer-events: none; + z-index: 9; +} + +#sun { + position: absolute; + left: 50%; + bottom: 0; + width: var(--sun-size, 105px); + height: var(--sun-size, 105px); + margin-left: calc(var(--sun-size, 105px) / -2); + border-radius: 50%; + background: radial-gradient(circle at 30% 30%, #fffbe0, #ffd972 60%, #ffb52a 100%); + box-shadow: 0 0 70px rgba(255, 193, 55, 0.9), 0 0 140px rgba(255, 193, 55, 0.55); + transition: transform 0.4s ease-out, box-shadow 0.4s ease-out; + opacity: 0.85; +} + +#sun-rays { + position: absolute; + left: 50%; + bottom: 0; + width: var(--sun-ray-size, 189px); + height: var(--sun-ray-size, 189px); + margin-left: calc(var(--sun-ray-size, 189px) / -2); + border-radius: 50%; + overflow: hidden; + filter: blur(1px); + opacity: 0.25; + transform: scale(0.9); + transition: opacity 0.4s ease-out, transform 0.4s ease-out; +} + +#sun-rays::before { + content: ""; + position: absolute; + top: -10%; + left: -10%; + width: 120%; + height: 120%; + border-radius: 50%; + background: repeating-conic-gradient(rgba(255, 225, 120, 0.55) 0deg, rgba(255, 225, 120, 0.55) 12deg, rgba(255, 225, 120, 0) 28deg, rgba(255, 225, 120, 0) 40deg); + animation: spin 16s linear infinite; +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +#rooster { + position: absolute; + left: 50%; + bottom: calc(var(--sun-size, 210px) + 10px); + transform: translateX(-50%); + font-size: 68px; + opacity: 0; + transition: opacity 0.25s ease-out; + filter: drop-shadow(0 6px 4px rgba(0, 0, 0, 0.15)); + pointer-events: none; + z-index: 11; +} + +#rooster.show { + opacity: 1; +} + +#rooster.flap { + animation: flap 0.55s ease-in-out 3 forwards; +} + +@keyframes flap { + 0% { + transform: translateX(-50%) translateY(0) rotate(0deg); + } + 50% { + transform: translateX(-50%) translateY(8px) rotate(-10deg); + } + 100% { + transform: translateX(-50%) translateY(0) rotate(10deg); + } +} + .cloud { position: absolute; top: 15%; diff --git a/index.html b/index.html index f270764..57bd405 100644 --- a/index.html +++ b/index.html @@ -10,6 +10,11 @@
+
+
+
+ +
diff --git a/index.js b/index.js index 2a1fd12..926a46a 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, newAudio, soundToggle, show, adjust, parseTimeInput, promptSetCountdown, toggle, reset, blink, count, run, resize; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, parseTimeInput, promptSetCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -11,6 +11,13 @@ latency = 0; stopBy = null; delay = 60000; audioRemind = null; +sunWrap = null; +sun = null; +sunRays = null; +sunDuration = 0; +roosterTimers = []; +rooster = null; +roosterShown = false; newAudio = function(file){ var x$, node; x$ = node = new Audio(); @@ -47,9 +54,8 @@ adjust = function(it, v){ isRun = false; $('#toggle').text("RUN"); isWarned = false; - start = null; - latency = 0; - stopBy = null; + stopRoosterCrow(); + hideRooster(); soundToggle(audioRemind, false); } delay = delay + it * 1000; @@ -60,6 +66,10 @@ adjust = function(it, v){ delay = 0; } $('#timer').text(delay); + if (!isRun) { + sunDuration = delay; + updateSunPosition(delay); + } return resize(); }; parseTimeInput = function(input){ @@ -119,6 +129,8 @@ toggle = function(){ stopBy = new Date(); clearInterval(handler); handler = null; + stopRoosterCrow(); + hideRooster(); soundToggle(audioRemind, false); } if (stopBy) { @@ -133,6 +145,8 @@ reset = function(){ delay = 1000; } soundToggle(audioRemind, false); + stopRoosterCrow(); + hideRooster(); stopBy = 0; isWarned = false; isBlink = false; @@ -146,6 +160,8 @@ reset = function(){ handler = null; $('#timer').text(delay); $('#timer').css('color', '#fff'); + sunDuration = delay; + updateSunPosition(delay); return resize(); }; blink = function(){ @@ -157,6 +173,7 @@ count = function(){ var tm, diff; tm = $('#timer'); diff = start.getTime() - new Date().getTime() + delay + latency; + updateSunPosition(Math.max(0, diff)); if (diff > 60000) { isWarned = false; } @@ -168,13 +185,18 @@ count = function(){ soundToggle(audioRemind, false); } if (diff < 0 && !isBlink) { - start = null; + if (!roosterShown) { + startRoosterCountdown(); + } + updateSunPosition(0); isBlink = true; diff = 0; clearInterval(handler); handler = setInterval(function(){ return blink(); }, 500); + } else if (diff <= 0 && !roosterShown) { + startRoosterCountdown(); } tm.text(diff + ""); return resize(); @@ -184,6 +206,8 @@ run = function(){ start = new Date(); latency = 0; isBlink = false; + sunDuration = delay; + updateSunPosition(delay); } if (handler) { clearInterval(handler); @@ -208,10 +232,95 @@ resize = function(){ tm.css('font-size', 1.5 * w / len + "px"); tm.css('line-height', h + "px"); fontSize = parseFloat(tm.css('font-size')) || 0; - return fontSize; + return updateSunSize(fontSize); +}; +updateSunPosition = function(remaining){ + var progress, target; + if (!sunWrap || !sun || sunDuration <= 0) { + return; + } + progress = 1 - remaining / sunDuration; + if (progress < 0) { + progress = 0; + } + if (progress > 1) { + progress = 1; + } + target = -60 + progress * 40; + sunWrap.style.bottom = target + "vh"; + return updateSunAppearance(progress); +}; +updateSunAppearance = function(progress){ + var scale, rayScale, glowStrength; + if (!sun || !sunRays) { + return; + } + scale = 1.1 + progress * 0.9; + rayScale = 1 + progress * 0.8; + glowStrength = 70 + progress * 90; + sun.style.transform = "scale(" + scale + ")"; + sun.style.boxShadow = "0 0 " + glowStrength + "px rgba(255, 193, 55, 0.9), 0 0 " + glowStrength * 1.8 + "px rgba(255, 193, 55, 0.5)"; + sunRays.style.opacity = 0.25 + progress * 0.7 + ""; + return sunRays.style.transform = "scale(" + rayScale + ")"; +}; +updateSunSize = function(fontSize){ + var root, sunSize, raySize; + if (!fontSize) { + return; + } + root = document.documentElement.style; + sunSize = Math.max(70, Math.min(fontSize * 0.4, 220)); + raySize = sunSize * 1.8; + root.setProperty('--sun-size', sunSize + "px"); + return root.setProperty('--sun-ray-size', raySize + "px"); +}; +startRoosterCountdown = function(){ + if (roosterShown || !rooster) { + return; + } + roosterShown = true; + rooster.classList.add('show'); + return triggerRoosterCrow(); +}; +triggerRoosterCrow = function(){ + stopRoosterCrow(); + rooster.classList.add('flap'); + return roosterTimers.push(setTimeout(function(){ + return hideRooster(); + }, 1700)); +}; +stopRoosterCrow = function(){ + var i$; + for (i$ = 0; i$ < roosterTimers.length; ++i$) { + clearTimeout(roosterTimers[i$]); + } + if (rooster) { + rooster.classList.remove('flap'); + } + return roosterTimers = []; +}; +hideRooster = function(){ + roosterShown = false; + stopRoosterCrow(); + if (rooster) { + return rooster.classList.remove('show'); + } }; window.onload = function(){ $('#timer').text(delay); + sunWrap = document.getElementById('sun-wrap'); + sun = document.getElementById('sun'); + sunRays = document.getElementById('sun-rays'); + rooster = document.getElementById('rooster'); + if (rooster) { + rooster.addEventListener('animationend', function(e){ + if (e.animationName === 'flap') { + return hideRooster(); + } + }); + } + sunDuration = delay; + updateSunPosition(delay); resize(); $('#timer').attr('title', 'Click to set the countdown').attr('tabindex', '0').on('click keypress', function(e){ if (e.type === 'click' || e.key === 'Enter') { From d6a020c8d2a619d98d76460d6555f8e7e1e29abe Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 16:25:47 +0800 Subject: [PATCH 09/14] Reset countdown state after finishing --- index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/index.js b/index.js index 926a46a..55c1faf 100644 --- a/index.js +++ b/index.js @@ -48,6 +48,9 @@ adjust = function(it, v){ clearInterval(handler); } handler = null; + start = null; + latency = 0; + stopBy = null; isBlink = false; isLight = true; $('#timer').css('color', '#fff'); From e49ce0523ae6de87585dda8ac903f2873a1c82e4 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Wed, 10 Dec 2025 16:32:16 +0800 Subject: [PATCH 10/14] Add inline custom countdown controls --- index.css | 36 ++++++++++++++++++++++++++++++++++++ index.html | 5 +++++ index.js | 34 ++++++++++++++++++++++------------ 3 files changed, 63 insertions(+), 12 deletions(-) diff --git a/index.css b/index.css index 63fc388..a8d701b 100644 --- a/index.css +++ b/index.css @@ -251,6 +251,42 @@ body { width: 70px; } +#custom-countdown-form { + position: absolute; + bottom: 55px; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + gap: 10px; + padding: 6px 10px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.85); + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.18); + z-index: 12; +} + +#custom-countdown { + width: 150px; + border: 1px solid #b1c5d6; + border-radius: 4px; + padding: 6px 8px; + font-size: 14px; +} + +#apply-countdown { + height: 32px; + line-height: 18px; + padding: 6px 12px; +} + +#countdown-status { + min-width: 120px; + font-size: 13px; + color: #2b6e3f; + font-weight: 600; +} + #min10 { margin-left: -270px; } diff --git a/index.html b/index.html index 57bd405..00b61fe 100644 --- a/index.html +++ b/index.html @@ -31,6 +31,11 @@ 30 sec 1 min 3 min +
+ + +
+
5 min 10 min 15 min diff --git a/index.js b/index.js index 55c1faf..d4d55df 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, parseTimeInput, promptSetCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, parseTimeInput, setStatusMessage, setCustomCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -108,22 +108,32 @@ parseTimeInput = function(input){ } return sec; }; -promptSetCountdown = function(){ - var suggestion, input, seconds; - suggestion = Math.max(1, Math.round(delay / 1000)); - input = window.prompt('Set countdown (seconds or mm:ss)', suggestion + ''); - if (input == null) { +setStatusMessage = function(message, isError){ + var status; + status = $('#countdown-status'); + if (!status.length) { return; } - seconds = parseTimeInput(input); + status.text(message || ''); + status.css('color', isError ? '#b00020' : '#2b6e3f'); +}; +setCustomCountdown = function(){ + var input, seconds; + input = $('#custom-countdown'); + if (!input.length) { + return; + } + seconds = parseTimeInput(input.val()); if (seconds == null || seconds < 0) { - window.alert('Invalid time format'); + setStatusMessage('請輸入正確時間', true); return; } if (isRun) { toggle(); } - return adjust(0, seconds); + adjust(0, seconds); + setStatusMessage('已設定 ' + seconds + ' 秒'); + return input.select(); }; toggle = function(){ isRun = !isRun; @@ -325,9 +335,9 @@ window.onload = function(){ sunDuration = delay; updateSunPosition(delay); resize(); - $('#timer').attr('title', 'Click to set the countdown').attr('tabindex', '0').on('click keypress', function(e){ - if (e.type === 'click' || e.key === 'Enter') { - return promptSetCountdown(); + $('#custom-countdown').on('keypress', function(e){ + if (e.key === 'Enter') { + return setCustomCountdown(); } }); return audioRemind = newAudio('audio/smb_warning.mp3'); From d92801754a4591512a6a5b6207d332d64d22d2cc Mon Sep 17 00:00:00 2001 From: Twelvia Date: Thu, 11 Dec 2025 12:19:53 +0800 Subject: [PATCH 11/14] Format timer display for countdown --- index.js | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index d4d55df..e4e95de 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, adjust, parseTimeInput, setStatusMessage, setCustomCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, formatTime, adjust, parseTimeInput, setStatusMessage, setCustomCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -42,6 +42,20 @@ show = function(){ isShow = !isShow; return $('.fbtn').css('opacity', isShow ? '1.0' : '0.1'); }; +formatTime = function(ms){ + var totalSeconds, hours, minutes, seconds, parts; + totalSeconds = Math.max(0, Math.ceil(ms / 1000)); + hours = Math.floor(totalSeconds / 3600); + minutes = Math.floor(totalSeconds % 3600 / 60); + seconds = totalSeconds % 60; + parts = []; + if (hours > 0) { + parts.push(hours); + } + parts.push((hours > 0 ? ('0' + minutes).slice(-2) : minutes)); + parts.push(('0' + seconds).slice(-2)); + return parts.join(':'); +}; adjust = function(it, v){ if (isBlink) { if (handler) { @@ -68,7 +82,7 @@ adjust = function(it, v){ if (delay <= 0) { delay = 0; } - $('#timer').text(delay); + $('#timer').text(formatTime(delay)); if (!isRun) { sunDuration = delay; updateSunPosition(delay); @@ -171,7 +185,7 @@ reset = function(){ clearInterval(handler); } handler = null; - $('#timer').text(delay); + $('#timer').text(formatTime(delay)); $('#timer').css('color', '#fff'); sunDuration = delay; updateSunPosition(delay); @@ -211,7 +225,7 @@ count = function(){ } else if (diff <= 0 && !roosterShown) { startRoosterCountdown(); } - tm.text(diff + ""); + tm.text(formatTime(diff)); return resize(); }; run = function(){ @@ -320,7 +334,7 @@ hideRooster = function(){ } }; window.onload = function(){ - $('#timer').text(delay); + $('#timer').text(formatTime(delay)); sunWrap = document.getElementById('sun-wrap'); sun = document.getElementById('sun'); sunRays = document.getElementById('sun-rays'); From f9c82876dcf6fbb5ad0c2a0f85762fd1e9bc1aaf Mon Sep 17 00:00:00 2001 From: Twelvia Date: Thu, 11 Dec 2025 12:34:05 +0800 Subject: [PATCH 12/14] Ensure timer overlay does not block controls --- index.css | 2 ++ index.styl | 2 ++ 2 files changed, 4 insertions(+) diff --git a/index.css b/index.css index a8d701b..449707f 100644 --- a/index.css +++ b/index.css @@ -194,6 +194,7 @@ body { display: flex; align-items: center; justify-content: center; + pointer-events: none; cursor: pointer; z-index: 5; } @@ -220,6 +221,7 @@ body { width: 170px; height: 44px; line-height: 30px; + z-index: 10; } #reset { diff --git a/index.styl b/index.styl index 5bb3997..be835be 100644 --- a/index.styl +++ b/index.styl @@ -96,6 +96,7 @@ html, body display: flex align-items: center justify-content: center + pointer-events: none #hide, #toggle, #reset, #min10, #min60, #add10, #add60, #def10, #def30, #def60, #def180, #def300, #def600, #def900, #def1800 position: absolute @@ -105,6 +106,7 @@ html, body width: 170px height: 44px line-height: 30px + z-index: 10 #reset margin-left: 50px #hide From 4cdbcc3fe9916eb53925da60898a90f9fdab2948 Mon Sep 17 00:00:00 2001 From: Twelvia Date: Thu, 11 Dec 2025 12:56:35 +0800 Subject: [PATCH 13/14] Raise sun to center when countdown completes --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index e4e95de..c35ead6 100644 --- a/index.js +++ b/index.js @@ -273,7 +273,7 @@ updateSunPosition = function(remaining){ if (progress > 1) { progress = 1; } - target = -60 + progress * 40; + target = -60 + progress * 110; sunWrap.style.bottom = target + "vh"; return updateSunAppearance(progress); }; From eb873d2f6018596b6747d5a4927687641f4c982a Mon Sep 17 00:00:00 2001 From: Twelvia Date: Thu, 11 Dec 2025 14:33:35 +0800 Subject: [PATCH 14/14] Enable quick preset panel to start countdown --- index.html | 16 ++++++++-------- index.js | 17 ++++++++++++++++- index.pug | 16 ++++++++-------- 3 files changed, 32 insertions(+), 17 deletions(-) diff --git a/index.html b/index.html index 00b61fe..9d93cee 100644 --- a/index.html +++ b/index.html @@ -27,18 +27,18 @@ +10 +60 - 10 sec - 30 sec - 1 min - 3 min + 10 sec + 30 sec + 1 min + 3 min
- 5 min - 10 min - 15 min - 30 min + 5 min + 10 min + 15 min + 30 min diff --git a/index.js b/index.js index c35ead6..993466c 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ // Generated by LiveScript 1.3.1 -var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, formatTime, adjust, parseTimeInput, setStatusMessage, setCustomCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; +var start, isBlink, isLight, isRun, isShow, isWarned, handler, latency, stopBy, delay, audioRemind, sunWrap, sun, sunRays, sunDuration, roosterTimers, rooster, roosterShown, newAudio, soundToggle, show, formatTime, adjust, parseTimeInput, setStatusMessage, setCustomCountdown, setPresetCountdown, toggle, reset, blink, count, run, resize, updateSunPosition, updateSunAppearance, updateSunSize, startRoosterCountdown, triggerRoosterCrow, stopRoosterCrow, hideRooster; start = null; isBlink = false; isLight = true; @@ -149,6 +149,21 @@ setCustomCountdown = function(){ setStatusMessage('已設定 ' + seconds + ' 秒'); return input.select(); }; +setPresetCountdown = function(seconds){ + if (seconds == null || seconds < 0) { + return; + } + adjust(0, seconds); + sunDuration = delay; + updateSunPosition(delay); + if (!isRun) { + return toggle(); + } + start = new Date(); + latency = 0; + stopBy = null; + return resize(); +}; toggle = function(){ isRun = !isRun; $('#toggle').text(isRun ? "STOP" : "RUN"); diff --git a/index.pug b/index.pug index 5394a75..3e934c1 100644 --- a/index.pug +++ b/index.pug @@ -24,11 +24,11 @@ html a#hide.btn.btn-default(onclick="show()") ൠ a#add10.btn.btn-info.fbtn(onclick="adjust(10)") +10 a#add60.btn.btn-info.fbtn(onclick="adjust(60)") +60 - a#def10.btn.btn-success.fbtn(onclick="adjust(0,10)") 10 sec - a#def30.btn.btn-success.fbtn(onclick="adjust(0,30)") 30 sec - a#def60.btn.btn-success.fbtn(onclick="adjust(0,60)") 1 min - a#def180.btn.btn-success.fbtn(onclick="adjust(0,180)") 3 min - a#def300.btn.btn-success.fbtn(onclick="adjust(0,300)") 5 min - a#def600.btn.btn-success.fbtn(onclick="adjust(0,600)") 10 min - a#def900.btn.btn-success.fbtn(onclick="adjust(0,900)") 15 min - a#def1800.btn.btn-success.fbtn(onclick="adjust(0,1800)") 30 min + a#def10.btn.btn-success.fbtn(onclick="setPresetCountdown(10)") 10 sec + a#def30.btn.btn-success.fbtn(onclick="setPresetCountdown(30)") 30 sec + a#def60.btn.btn-success.fbtn(onclick="setPresetCountdown(60)") 1 min + a#def180.btn.btn-success.fbtn(onclick="setPresetCountdown(180)") 3 min + a#def300.btn.btn-success.fbtn(onclick="setPresetCountdown(300)") 5 min + a#def600.btn.btn-success.fbtn(onclick="setPresetCountdown(600)") 10 min + a#def900.btn.btn-success.fbtn(onclick="setPresetCountdown(900)") 15 min + a#def1800.btn.btn-success.fbtn(onclick="setPresetCountdown(1800)") 30 min