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; } html { font-size: 0.75vmin; } body { background-image: linear-gradient(to bottom, #131313, #000); perspective: 45rem; transform-style: preserve-3d; } .wrapper { animation: camera-rotate 40s ease-in-out forwards infinite; width: 100%; height: 100%; transform-style: preserve-3d; } main { --s: 100%; --l: 50%; display: flex; color: hsl(210deg, var(--s), var(--l)); gap: 1rem; width: 100%; height: 100%; position: relative; align-items: center; justify-content: center; animation-composition: add; /* for hue rotate(laggy thou) */ // animation: camera-rotate 40s ease-in-out forwards infinite, // hue-rotate 70s linear -40s forwards infinite; animation: camera-pan 30s linear forwards infinite; translate: 0rem 1rem 10rem; transform-style: preserve-3d; .digits { transform-style: preserve-3d; .group { display: flex; gap: 2rem; .digit { position: relative; height: 16rem; aspect-ratio: 1/2; filter: drop-shadow(0px 0px 4px currentColor) drop-shadow(0px 0px 10px currentColor); span { --act: 0; --signX: 1; --signY: 1; position: absolute; background-color: white; transition: all .3s cubic-bezier(.17,.67,.5,1.15); opacity: calc(0.03 + 0.97 * var(--act)); animation-composition: add; transform: scale(var(--signX), var(--signY)); &.end { clip-path: polygon(15% 0%, 7.5% 20%, 25% 100%, 75% 100%, 92.5% 20%, 85% 0%); width: 100%; height: 10%; &.top { top: 0; } &.bottom { top: initial; bottom: 0; --signY: -1; } } &.side { clip-path: polygon(0% 15%, 20% 7.5%, 100% 22.5%, 100% 85%, 20% 95%, 0% 90%); height: 50%; width: 20%; &.left { top: 0; left: 0; &.bottom { top: initial; bottom: 0; --signY: -1; } } &.right { top: 0; left: initial; right: 0; --signX: -1; &.bottom { top: initial; --signY: -1; bottom: 0; } } } &.middle { clip-path: polygon(22.5% 0%, 6.5% 50%, 22.5% 100%, 77.5% 100%, 93.5% 50%, 77.5% 0%); top: 45%; height: 10%; width: 100%; } } &[data-digit="0"] { :not(.middle) { --act: 1; } } &[data-digit="1"] { .right { --act: 1; } } &[data-digit="2"] { :not(.top.left, .bottom.right) { --act: 1; } } &[data-digit="3"] { :not(.left) { --act: 1; } } &[data-digit="4"] { :not(.end, .bottom.left) { --act: 1; } } &[data-digit="5"] { :not(.top.right, .bottom.left) { --act: 1; } } &[data-digit="6"] { :not(.top.right) { --act: 1; } } &[data-digit="7"] { .top, .right { --act: 1; } } &[data-digit="8"] { > * { --act: 1; } } &[data-digit="9"] { :not(.bottom.left) { --act: 1; } } } } } .colon-group { transform-style: preserve-3d; .colon { span { display: flex; height: 16rem; flex-direction: column; justify-content: space-evenly; width: 4rem; align-items: center; filter: drop-shadow(0px 0px 4px currentColor) drop-shadow(0px 0px 10px currentColor); &::before, &::after { content: ''; display: block; width: 2rem; aspect-ratio: 1/1; background-color: white; border-radius: 2rem; } } } } .shadow { top: 0; position: absolute; transform-origin: bottom center; transform: translateY(1rem) translateZ(2rem) rotateX(-90.1deg); // 90deg won't be visible on safari .digit { span { opacity: var(--act); } } &.shadow1 { opacity: 0.5; filter: drop-shadow(0px 0px 4px currentColor) drop-shadow(0px 0px 10px currentColor) blur(4rem); > span, .digit { mask-image: linear-gradient(to bottom, white, rgba(0,0,0,0.5)); } } &.shadow2 { opacity: 0.4; filter: drop-shadow(0px 0px 4px currentColor) drop-shadow(0px 0px 10px currentColor) blur(4px); > span, .digit { opacity: var(--act); mask-image: linear-gradient(to top, black, rgba(0,0,0,0.1) 60%, rgba(0,0,0,0)); } } } } @keyframes camera-rotate { 0% { transform: rotateY(-10deg); } 50% { transform: rotateY(10deg); } 100% { transform: rotateY(-10deg); } } @keyframes camera-pan { 0% { transform: translate(0rem, 0rem); } 20% { transform: translate(1rem, 2rem); } 40% { transform: translate(-2rem, 2.5rem); } 50% { transform: translate(-1.5rem, 1.5rem); } 70% { transform: translate(-0.5rem, -0.5rem); } 90% { transform: translate(1.5rem, -1rem); } 100% { transform: translate(0rem, 0rem); } } @keyframes hue-rotate { 0% { color: hsl(0deg, var(--s), var(--l)); } 8.33% { color: hsl(30deg, var(--s), var(--l)); } 16.67% { color: hsl(60deg, var(--s), var(--l)); } 25% { color: hsl(90deg, var(--s), var(--l)); } 33.33% { color: hsl(120deg, var(--s), var(--l)); } 41.67% { color: hsl(150deg, var(--s), var(--l)); } 50% { color: hsl(180deg, var(--s), var(--l)); } 58.33% { color: hsl(210deg, var(--s), var(--l)); } 66.67% { color: hsl(240deg, var(--s), var(--l)); } 75% { color: hsl(270deg, var(--s), var(--l)); } 83.33% { color: hsl(300deg, var(--s), var(--l)); } 91.67% { color: hsl(330deg, var(--s), var(--l)); } 100% { color: hsl(360deg, var(--s), var(--l)); } } .safari { .digit span { // 3d transform with opacity animation breaks filters transition: none !important; &::before { content: ''; position: absolute; display: block; // prevent the bounding box to be cut off during content change width: 400%; height: 400%; top: 0; left: 0; transform: translate(-50%, -50%); } } }
console.log("Event Fired") const bars = [ ['end', 'top'], ['side', 'top', 'left'], ['side', 'top', 'right'], ['middle'], ['side', 'bottom', 'left'], ['side', 'bottom', 'right'], ['end', 'bottom'] ]; const $main = document.querySelector('main'); const addDigits = number => { const initGroup = (number, padding = 2) => { const $group = document.createElement('div'); $group.classList.add('group'); const digits = [...`${number}`.padStart(padding, 0)].map(digit => { const $digit = document.createElement('figure'); $digit.classList.add('digit'); $digit.setAttribute('data-digit', digit); bars.forEach(classes => { const $span = document.createElement('span'); $span.classList.add(...classes); $digit.append($span); }); return $digit; }); $group.append(...digits); return { element: $group, set number(val) { number = val; [...`${number}`.padStart(padding, 0).substring(`${number}`.length - 2)].forEach((digit, i) => { digits[i].setAttribute('data-digit', digit); }); }, get number() { return number; } } } const $digits = document.createElement('div'); $digits.classList.add('digits'); const group = initGroup(number); const groupShadow1 = initGroup(number); const groupShadow2 = initGroup(number); groupShadow1.element.classList.add('shadow'); groupShadow1.element.classList.add('shadow1'); groupShadow2.element.classList.add('shadow'); groupShadow2.element.classList.add('shadow2'); $digits.append(group.element); $digits.append(groupShadow1.element); $digits.append(groupShadow2.element); $main.append($digits); return { set number(val) { number = val; group.number = val; groupShadow1.number = val; groupShadow2.number = val; }, get number() { return number; } } } const addColon = () => { const $colonGroup = document.createElement('div'); $colonGroup.classList.add('colon-group'); const $colon = document.createElement('figure'); $colon.append(document.createElement('span')); const $colonShadow1 = document.createElement('figure'); $colonShadow1.append(document.createElement('span')); const $colonShadow2 = document.createElement('figure'); $colonShadow2.append(document.createElement('span')); $colon.classList.add('colon'); $colonShadow1.classList.add('colon', 'shadow', 'shadow1'); $colonShadow2.classList.add('colon', 'shadow', 'shadow2'); $colonGroup.append($colon); $colonGroup.append($colonShadow1); $colonGroup.append($colonShadow2); $main.append($colonGroup); } const init = () => { let now = new Date(); let hours = now.getHours(); let minutes = now.getMinutes(); let seconds = now.getSeconds(); const numberHour = addDigits(hours); addColon(); const numberMinute = addDigits(minutes); addColon(); const numberSecond = addDigits(seconds); const update = () => { now = new Date(); let newSeconds = now.getSeconds(); if (seconds !== newSeconds) { hours = now.getHours(); minutes = now.getMinutes(); seconds = newSeconds; numberHour.number = hours; numberMinute.number = minutes; numberSecond.number = seconds; } requestAnimationFrame(update); } update(); } if (/^(?:(?!chrome|android)[\s\S])*(?:safari|iPad|iPhone|iPod)/i.test(navigator.userAgent)) { document.body.classList.add('safari'); } init();