Frontend Forever App
We have a mobile app for you to download and use. And you can unlock many features in the app.
Get it now
Intall Later
Run
HTML
CSS
Javascript
Output
Document
@charset "UTF-8"; @import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800); *, :after, :before { box-sizing: border-box; padding: 0; margin: 0; } body { margin: 0; background: linear-gradient(#001 70%, darkblue 85%, #fff 86%); overflow: hidden; height: 100vh; } #backgroundSnow, #foregroundSnow { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); height: 100%; width: 100%; } #backgroundSnow { z-index: 1; } #foregroundSnow { z-index: 100; } #clock { position: absolute; top: 33%; left: 50%; transform: translate(-50%, 50%); width: 90vw; height: auto; max-width: 400px; min-height: 30px; z-index: 50; }
console.log("Event Fired") function secondsUntilHoliday(month = 12, day = 25) { // Get the current date and time const now = new Date(); // Get the current year const currentYear = now.getFullYear(); // Set the date for Holiday this year const holidayDate = new Date(currentYear, month - 1, day, 0, 0, 0, 0); // If holiday has already passed this year, set it for next year // Calculate the difference in milliseconds between now and holidayDate const timeDiff = now.getTime() - holidayDate.getTime(); // Convert the time difference to hours const hoursDifference = timeDiff / (1000 * 60 * 60); // milliseconds to hours // Check if more than 24 hours have passed if (hoursDifference >= 24) { holidayDate.setFullYear(holidayDate.getFullYear() + 1); } // Calculate the difference in seconds const timeDifference = Math.floor((holidayDate - now) / 1000); return timeDifference; } function initCountdown(elt, opt_properties) { if (!elt) { console.error("Must have element to populate the clock!"); return; } /** * Returns the number of seconds until a given target date. * @param {string} dateString - The target date in string format (e.g., "12-25-2023" or "12/25/2023"). * @returns {number} The number of seconds until the target date. */ const secondsUntil = (dateString) => { // Split the dateString based on '-' or '/' const [monthStr, dayStr, yearStr] = dateString.split(/[-/]/); // Convert the string parts to integers const month = parseInt(monthStr, 10) - 1; // Month is zero-based in JavaScript const day = parseInt(dayStr, 10); const year = parseInt(yearStr, 10); // Create a Date object from the parsed components (and assume it's at midnight on said date) const targetDate = new Date(year, month, day, 0, 0, 0, 0); // Get the current date and time const now = new Date(); // Calculate the difference in seconds const timeDifference = Math.floor((targetDate - now) / 1000); return timeDifference; }; const getUUID = () => { let d = new Date().getTime(); let uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) { let r = (d + Math.random() * 16) % 16 | 0; d = Math.floor(d / 16); return (c == "x" ? r : (r & 0x3) | 0x8).toString(16); } ); return uuid; }; const defaultProperties = { day: 0, hour: 0, min: 0, sec: 0, color: "#0ff", showMs: false, glow: true, font: "Roboto, sans-serif", fontWeight: 600, showAllNumbers: false, // show even the waiting numbers freezeTime: false, // set the original positions but don't animate onlyShowTime: false, // accepts 'hr', 'min', 'sec', or 'ms' holidayText: "Merry Christmas!" }; // properties passed in from user onto the defaults const c = Object.assign(defaultProperties, opt_properties); // what are the total seconds we dealing with c.totalSeconds = Math.floor(c.day * 86400 + c.hour * 3600 + c.min * 60 + c.sec); if ((c.date && c.totalSeconds <= 0) || (c.date && c.totalSeconds == undefined)) { c.totalSeconds = secondsUntil(c.date); } if (c.totalSeconds <= 0) { // console.error("What are you some kind of wiseguy?"); c.totalSeconds = 1; } c.day = Math.floor(c.totalSeconds / 86400); // set dotColor equal to color by default !c.dotColor ? (c.dotColor = defaultProperties.color) : false; // calculate the number of seconds passed for each column let td = {}; let id = getUUID(); let vxEnd = c.showMs ? 240 : 200; let vyEnd = c.showAllNumbers ? 300 : 30; let showGlow = c.glow ? `
` : ""; let showGlowBlur = c.glow ? `
` : ""; let numsOffsets = `0 -270; 0 -240; 0 -210; 0 -180; 0 -150; 0 -120; 0 -90; 0 -60; 0 -30; 0 0`; let numsOffsets6 = `0 -150; 0 -120; 0 -90; 0 -60; 0 -30; 0 0`; let numsOffsets24 = `0 -150; 0 -120; 0 -90; 0 -60; 0 -30; 0 0`; let msDots = c.showMs ? `M 197.5 10 v0 m0 10 v0` : ""; let milliseconds = c.showMs ? `
` : ""; c.sec1Passed = Math.floor(c.totalSeconds % 10); c.sec10Passed = Math.floor(c.totalSeconds % 60); // Corrected calculation for 10-second column c.min1Passed = Math.floor((c.totalSeconds / 60) % 10); // Corrected calculation for 1-minute column c.min10Passed = Math.floor((((c.totalSeconds / 60) % 60) % 100) / 10); // Corrected calculation for 10-minute column c.hr1Passed = Math.floor((c.totalSeconds / 3600) % 10); // Calculating for 1-hour column c.hr10Passed = Math.floor(((c.totalSeconds / 3600) % 24) / 10); // Calculating for 10-hour column c.day1Passed = Math.floor((c.totalSeconds / 86400) % 10); // Calculating for 1-day column c.day10Passed = Math.floor((((c.totalSeconds / 86400) % 100) % 100) / 10); // Calculating for 1-day column c.day100Passed = Math.floor((((c.totalSeconds / 86400) % 1000) % 1000) / 100); // Calculating for 1-day column let animateDay100 = c.totalSeconds >= 8640000 ? `
` : ""; let animateDay10 = c.totalSeconds >= 864000 ? `
` : ""; let animateDay1 = c.totalSeconds >= 86400 ? `
` : ""; let animateHr10 = c.totalSeconds >= 36000 ? `
` : ""; let animateHr1 = c.totalSeconds >= 3600 ? `
` : ""; let animateMin10 = c.totalSeconds >= 600 ? `
` : ""; let animateMin1 = c.totalSeconds >= 60 ? `
` : ""; let animateSec10 = c.totalSeconds >= 10 ? `
` : ""; // make svg let svg = `
${showGlowBlur}
0
1
2
3
4
5
6
7
8
9
${showGlow}
${animateDay100}
${animateDay10}
${animateDay1}
${animateHr10}
${animateHr1}
${animateMin10}
${animateMin1}
${animateSec10}
${milliseconds}
${c.holidayText}
${c.holidayText}
${c.holidayText}
`; const wrapper = document.createElement("div"); wrapper.innerHTML = svg; const doc = wrapper.firstChild; elt.appendChild(doc); // give us back the id return id; } let clock = document.querySelector("#clock"); let seconds2Christmas = secondsUntilHoliday(12, 25); let clockId = initCountdown(clock, { color: "#55bf13", dotColor: "#b01b2e", showMs: false, // date: "12-25-2023" sec: seconds2Christmas }); const randInt = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }; function addListener(clockId) { const placeholder = document.querySelector(`#placeholderAnimation${clockId}`); // Check if the listener is already added if (!placeholder._hasListener) { placeholder._hasListener = true; // Add the animationend event listener placeholder.addEventListener("endEvent", (event) => { // console.log('SVG animation ended!', event); // document.querySelector(`#holiday${clockId}`).setAttribute("opacity", 1); confetti(document.querySelector(`#clockItToMe${clockId}`), { speed: 6000, type: ["🎅", "🤶", "🦌", "🌟", "⛄", "☃", "🎄", "🎁", "✝", "❄", "👼"], spread: 400, drop: 600, addBlur: false }); setInterval(() => { confetti(document.querySelector(`#clockItToMe${clockId}`), { speed: 6000, type: ["🎅", "🤶", "🦌", "🌟", "⛄", "☃", "🎄", "🎁", "✝", "❄", "👼"], spread: 400, drop: 600, addBlur: false }); }, 3000); }); } } addListener(clockId); function snowfetti(el = document.body, opt_properties) { if (!el) { console.error("Must have element to populate the confetti!"); return; } const defaultProperties = { addBlur: true, angle: 0, beginStart: false, drop: 400, fadeout: true, fixedSize: false, flakes: 100, scale: 0.5, speed: 5000, spread: 400, spin: true, zSpin: true }; const c = {...defaultProperties, ...opt_properties}; const randInt = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }; const baseEncode = (vall = document.querySelector("#usrInput").value) => { let usrVal = vall.replace(/\s\s+/g, ` `); let btoa = window.btoa(usrVal); let res = encodeURI(vall); if (res.indexOf("xmlns=") == -1) res = res.replace(`%3Csvg`, `%3Csvg xmlns=%22http://www.w3.org/2000/svg%22`); res = res.replaceAll(`#`, `%23`).replaceAll(`%22`, `'`).replaceAll(`%0A`, ``).replaceAll(`%09`, ``).replaceAll(`%20`, ` `).replace(/\s\s+/g, ` `); let baseEncodedSVG = `data:image/svg+xml,${res}`; let bgIm = `background-image: url("${baseEncodedSVG}");`; return [`data:image/svg+xml;base64,${btoa}`, baseEncodedSVG]; } const hh = c.drop; const ww = c.spread; const randomBlur = () => { if (c.addBlur) return randInt(1, 2); else return 1; }; const overlayId = `conf${randInt(0, 1000)}etti${randInt(0, 1000)}ver${randInt(0, 1000)}lay`; let animatedConfetti = ``; // make sure number of flakes is a number if (!c.flakes || Number.isNaN(c.flakes * 1)) { c.flakes = 100; } for (let i = 0; i < c.flakes; i++) { const conId = `con${randInt(0, 1000)}fet${randInt(0, 1000)}ti${randInt(0, 1000)}`; const confettiDur = `${randInt(c.speed / 2, c.speed)}`; let confettiSpin = ``; let confettiType = ``; if (c.spin) { confettiSpin = `
`; } if (c.zSpin) { let xySpin = `-1 1`; if (randInt(0, 1) == 0) xySpin = `1 -1`; confettiSpin += `
`; } let confettiColor = ``; let fixedScale = 1; if (!c.fixedSize) { fixedScale = randInt(5, 20) / 10; } let midpoints = randInt(3, 12); let snowFlakePath = `M 50 50 v-35`; for (let i = 0; i < midpoints; i++) { let linelength = randInt(20, 120) / 10; let yPos = 50 - randInt(50, 350) / 10; let path = `M50 ${yPos}l-${linelength} -${linelength}M50 ${yPos}l${linelength} -${linelength}`; snowFlakePath += path; } let arms = randInt(6, 12); let angle = 360 / arms; let armCopies = ``; let sw = randInt(10, 40) / 10; for (let i = 1; i < arms; i++) { armCopies += `
`; } let snowflake = `
${armCopies}
`; confettiType = `
${confettiSpin}
`; let topY = (hh * randInt(5, 25)) / 100; let startX = (ww * randInt(0, 100)) / 100; animatedConfetti += `
${confettiType}
`; } const elemRect = el.getBoundingClientRect(); const centerY = elemRect.top + (elemRect.bottom - elemRect.top) / 2; const centerX = elemRect.left - (elemRect.left - elemRect.right) / 2; let fadeAnim = ``; if (c.fadeout) fadeAnim = `
`; const svg = `
${animatedConfetti}${fadeAnim}
`; const wrapper = document.createElement("div"); wrapper.innerHTML = svg; const svgChild = wrapper.firstChild; el.appendChild(svgChild); } function letItSnow(beginStart=false) { const randInt = (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }; snowfetti(document.querySelector('#backgroundSnow'), { spread: window.innerWidth, flakes: randInt(20, 40), speed: randInt(25000, 40000), fadeout: false, drop: window.innerHeight, spin: true, beginStart: beginStart }); snowfetti(document.querySelector('#foregroundSnow'), { spread: window.innerWidth, flakes: randInt(20, 40), speed: randInt(25000, 40000), fadeout: false, drop: window.innerHeight, spin: true, beginStart: beginStart }); } document.querySelector("#foregroundSnow").addEventListener("click", (el) => { snowfetti(el.target, { spread: window.innerWidth, beginStart: true, flakes: 40, speed: 20000, fadeout: false, drop: window.innerHeight, spin: true }); }); letItSnow(); // refresh it if we leave the page window.addEventListener("visibilitychange", () => { if (!document.hidden) { document.getElementById('clock').replaceChildren(); let seconds2Christmas = secondsUntilHoliday(12, 25); let clockId = initCountdown(clock, { color: "#55bf13", dotColor: "#b01b2e", showMs: false, // date: "12-25-2023" sec: seconds2Christmas }); addListener(clockId); } }); // refresh it if we resize window.addEventListener("resize", () => { document.getElementById('clock').replaceChildren(); document.getElementById('backgroundSnow').replaceChildren(); document.getElementById('foregroundSnow').replaceChildren(); letItSnow(); let seconds2Christmas = secondsUntilHoliday(12, 25); let clockId = initCountdown(clock, { color: "#55bf13", dotColor: "#b01b2e", showMs: false, // date: "12-25-2023" sec: seconds2Christmas }); addListener(clockId); });