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
Made by
@levchenkod
@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; } :root { --transition-animation-duration: 0.25s; --bg-x: -25%; --bg-y: -25%; } html, body { height: 100%; background: #030507; display: flex; flex-direction: row; place-items: center; place-content: center; } templates { display: none; } .flex { display: flex; flex-direction: row; place-items: center; place-content: center; } .countdown { width: 500px; max-width: 90vw; } .digit, .divider { display: flex; margin: 0 -10px; svg { width: 100%; path:last-of-type { transform: scaleY(2.5) scaleX(0.4) !important; filter: blur(20px) !important; } } } .digit { transition: var(--transition-animation-duration) cubic-bezier(0, 0, 0, 0.97); &.animate-transition { transform: scale(1.1); mix-blend-mode: plus-lighter; filter: brightness(1.5) drop-shadow(2px 2px 14px rgb(209, 69, 14)); path { stroke: rgba(255, 106, 40, 0.95) !important; } } } .bg { position: absolute; top: 0; left: 0; bottom: 0; right: 0; background: url("https://images.unsplash.com/photo-1475738198235-4b30fc20cff4?q=80&w=2876&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"); background-size: cover; background-position: center; opacity: 0.1; // transition: 0.15s ease-out; transform: translateX(var(--bg-x)) translateY(var(--bg-y)) scale(1.5); animation: blink 1s ease-out infinite alternate; } .shadow { position: absolute; top: 0; left: 0; bottom: 0; right: 0; background: radial-gradient(ellipse, transparent 50%, #000); } @keyframes blink { 0% { opacity: 0.1; } 50% { opacity: 0.1; } 90% { opacity: 0.2; } 100% { opacity: 0.1; } } .credits { position: absolute; font-family: sans-serif; bottom: 36px; left: 50%; transform: translateX(-50%); color: #df6c1e; text-shadow: 0 0px 8px #ca3c05; font-size: 0.9rem; &:not(:hover) { opacity: 0.4; } a { color: #df6c1e; } }
console.log("Event Fired") class NoizyNumber { constructor( templateElement, { duplicatesCount = 20, fps = 24, noizeRadius = 30 } = {} ) { this.templateElement = templateElement; this.element = this.templateElement.cloneNode(true); this.pathElement = this.element.querySelector("path"); this.originalPath = this.pathElement.getAttribute("d"); this.originalPathList = this.originalPath.split(" "); this.element.id = this.element + Math.random(); this.pathElementsStore = [this.pathElement]; this.timeoutStore = null; this.duplicatesCount = duplicatesCount; this.fps = fps; this.delay = 1000 / this.fps; this.noizeRadius = noizeRadius; this.init(); return this; } createDuplicatePaths() { Array(this.duplicatesCount) .fill() .forEach(() => { const cloneElement = this.pathElement.cloneNode(); cloneElement.setAttribute("data-is-clone", true); this.element.appendChild(cloneElement); this.pathElementsStore.push(cloneElement); }); } noizePath(pathElement) { const result = this.originalPathList .map((position) => { const command = position.match(/[a-z]/i)?.[0] || ""; const radius = Math.random() * this.noizeRadius; const noize = Math.round(Math.random() * (radius * 2) - radius); const value = parseInt(position.slice(command ? 1 : 0)); return `${command}${value + noize}`; }) .join(" "); const scale = 0.7 + Math.random() * 0.5; const opacity = 0.5 + Math.random() * 0.5; const blur = Math.floor(Math.random() * 2); const color = [ "209, 69, 14", "253, 116, 39", "255, 149, 60", "255, 141, 0" ][Math.round(Math.random() * 4)]; pathElement.style.transform = `scale(${scale})`; pathElement.style.transformOrigin = `center`; pathElement.style.filter = `blur(${blur}px)`; pathElement.style.stroke = `rgba(${color}, ${opacity})`; pathElement.setAttribute("d", result); } handleTick() { this.pathElementsStore.forEach(this.noizePath.bind(this)); const scale = 1 + Math.random() * 0.2; this.element.style.transform = `scale(${scale})`; this.element.style.transformOrigin = `center`; } animate() { clearTimeout(this.timeoutStore); this.handleTick(); this.timeoutStore = setTimeout(this.animate.bind(this), this.delay); } init() { this.createDuplicatePaths(); this.animate(); } } class Countdown { constructor({ initialSeconds = 10, onTick, onDone } = {}) { this.date = new Date(); this.lastTick = Date.now(); this.time = { dd: 0, hh: 0, mm: 0, ss: initialSeconds }; this.onTick = onTick; this.onDone = onDone; } tick() { const now = Date.now(); if (now - this.lastTick < 1000) { return setTimeout(this.tick.bind(this), 50); } else { this.lastTick = now; } --this.time.ss; if (this.time.ss < 0) { --this.time.mm; this.time.ss = 0; } if (this.time.mm < 0) { --this.time.hh; this.time.mm = 0; } if (this.time.hh < 0) { --this.time.dd; this.time.hh = 0; } const isDone = this.time.dd === 0 && this.time.hh === 0 && this.time.mm === 0 && this.time.ss === 0; if (isDone) { this.onDone?.(this.time); } else { this.onTick?.(this.time); requestAnimationFrame(() => { this.tick(); }); } } start() { this.tick(); } } const normalizeDigits = (digits) => { digits.toString(); }; const countdownElement = document.querySelector(".countdown"); const countdownDDElement = countdownElement.querySelector(".dd"); const countdownHHElement = countdownElement.querySelector(".hh"); const countdownMMElement = countdownElement.querySelector(".mm"); const countdownSSElement = countdownElement.querySelector(".ss"); let previousTime; const timeToArray = (timeNumber = 0) => [...timeNumber.toString().split("").reverse(), "0"].splice(0, 2).reverse(); const dayDigitElements = document.querySelectorAll(".countdown .dd .digit"); const hourDigitElements = document.querySelectorAll(".countdown .hh .digit"); const minuteDigitElements = document.querySelectorAll(".countdown .mm .digit"); const secondDigitElements = document.querySelectorAll(".countdown .ss .digit"); const dividerElements = document.querySelectorAll(".countdown .divider"); const dividerTemplateElement = document.querySelector(`#number-divider`); const timeTypesList = ["dd", "hh", "mm", "ss"]; const digitElementsMap = { dd: dayDigitElements, hh: hourDigitElements, mm: minuteDigitElements, ss: secondDigitElements }; const setChildren = (parentElement, childrenElement) => { try { parentElement.innerHTML = ""; parentElement.appendChild(childrenElement); } catch (e) { console.error(e); } return parentElement; }; const setNoizyNumber = (parentElement, templateElement) => { const noizyNumber = new NoizyNumber(templateElement); setChildren(parentElement, noizyNumber.element); }; const renderCountdown = (time, isInit) => { timeTypesList.forEach((timeType) => { if (isInit || previousTime?.[timeType] !== time[timeType]) { const previousTimeArray = previousTime?.[timeType] ? timeToArray(previousTime?.[timeType]) : []; const timeArray = timeToArray(time[timeType]); if (!previousTime) { previousTime = {}; } previousTime[timeType] = time[timeType]; timeArray.forEach((timeValue, index) => { if (isInit || previousTimeArray[index] != parseInt(timeValue)) { const templateElement = document.querySelector( `#number-${timeValue}` ); digitElementsMap[timeType][index].classList.add("animate-transition"); setTimeout(() => { digitElementsMap[timeType][index].classList.remove( "animate-transition" ); }, 250); setNoizyNumber(digitElementsMap[timeType][index], templateElement); } }); } }); if (isInit) { dividerElements.forEach((dividerElement) => { setNoizyNumber(dividerElement, dividerTemplateElement); }); previousTime = time; } }; const countdown = new Countdown({ onDone: (time) => console.log(time), onTick: (time) => { renderCountdown(time); } }); renderCountdown({ dd: 0, hh: 0, mm: 0, ss: 10 }, true); countdown.start(); window.addEventListener("mousemove", (e) => { const deltaX = (1 / window.innerWidth) * e.pageX; const deltaY = (1 / window.innerHeight) * e.pageY; const range = 25; const x = range * deltaX - range; const y = range * deltaY - range; document.documentElement.style.setProperty("--bg-x", x + "%"); document.documentElement.style.setProperty("--bg-y", y + "%"); });