Загрузка...

Анимированные 3D часы с эффектом перелистывания цифр. Отображают часы, минуты, секунды. Стиль ретро-панели управления. Для дашбордов, лендингов, hero-секций.
<div class="flex items-center justify-center min-h-screen overflow-hidden"
style="background-color: #0f1115; background-image: radial-gradient(circle at 50% 0%, #1f232b 0%, #0a0b0d 100%); font-family: 'Oswald', sans-serif; perspective: 2500px;">
<script src="https://cdn.tailwindcss.com/3.4.17"></script>
<link
href="https://fonts.googleapis.com/css2?family=Oswald:wght@500;700&family=JetBrains+Mono:wght@400;700&display=swap"
rel="stylesheet">
<style>
.flip-unit {
width: 100px;
height: 150px;
position: relative;
perspective: 800px;
}
.card-half {
position: absolute;
left: 0;
width: 100%;
height: 50%;
overflow: hidden;
backface-visibility: hidden;
}
.card-top {
top: 0;
border-radius: 4px 4px 0 0;
transform-origin: bottom;
background: #2c2f36;
border-bottom: 1px solid rgba(0, 0, 0, 0.9);
z-index: 1;
}
.card-bottom {
bottom: 0;
border-radius: 0 0 4px 4px;
transform-origin: top;
background: #23252b;
border-top: 1px solid rgba(255, 255, 255, 0.08);
z-index: 1;
display: flex;
align-items: flex-end;
justify-content: center;
}
.card-num {
position: absolute;
left: 0;
width: 100%;
height: 200%;
color: #e2e4e9;
font-size: 110px;
font-weight: 700;
text-align: center;
line-height: 150px;
letter-spacing: -2px;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.card-top .card-num {
top: 0;
}
.card-bottom .card-num {
bottom: 0;
}
.leaf {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 50%;
transform-style: preserve-3d;
transform-origin: bottom;
z-index: 10;
}
.leaf-front,
.leaf-back {
backface-visibility: hidden;
position: absolute;
inset: 0;
overflow: hidden;
}
.leaf-front {
border-radius: 4px 4px 0 0;
background: #2c2f36;
border-bottom: 1px solid rgba(0, 0, 0, 0.9);
z-index: 2;
transform: translateZ(0.1px);
}
.leaf-back {
border-radius: 0 0 4px 4px;
background: #23252b;
border-top: 1px solid rgba(255, 255, 255, 0.08);
z-index: 1;
transform: rotateX(180deg) translateZ(0.1px);
display: flex;
align-items: flex-end;
justify-content: center;
}
.flipping {
animation: flipDown 0.5s cubic-bezier(0.45, 0.05, 0.55, 0.95) forwards;
}
@keyframes flipDown {
0% {
transform: rotateX(0deg);
}
100% {
transform: rotateX(-180deg);
}
}
.status-light-active::after {
content: '';
position: absolute;
inset: 0;
background: currentColor;
box-shadow: 0 0 8px currentColor;
}
@media (max-width: 768px) {
.flip-unit {
width: 60px;
height: 90px;
}
.card-num {
font-size: 60px;
line-height: 90px;
}
}
</style>
<div class="relative flex gap-10 p-12 rounded-xl"
style="background: #16181d; box-shadow: 0 0 0 1px rgba(255,255,255,0.05), 0 40px 80px -20px rgba(0,0,0,0.8); transform: rotateX(10deg);">
<!-- Decorative Screws -->
<div class="absolute w-3 h-3 rounded-full bg-zinc-800 top-4 left-4 shadow-inner flex items-center justify-center">
<div class="w-2 h-0.5 bg-black rotate-45"></div>
</div>
<div class="absolute w-3 h-3 rounded-full bg-zinc-800 top-4 right-4 shadow-inner flex items-center justify-center">
<div class="w-2 h-0.5 bg-black -rotate-45"></div>
</div>
<div
class="absolute w-3 h-3 rounded-full bg-zinc-800 bottom-4 left-4 shadow-inner flex items-center justify-center">
<div class="w-2 h-0.5 bg-black -rotate-12"></div>
</div>
<div
class="absolute w-3 h-3 rounded-full bg-zinc-800 bottom-4 right-4 shadow-inner flex items-center justify-center">
<div class="w-2 h-0.5 bg-black rotate-12"></div>
</div>
<!-- Hours -->
<div class="flex flex-col items-center gap-4">
<div class="flex gap-1 p-2 bg-black rounded-md shadow-inner relative overflow-hidden"
style="border: 1px solid rgba(255,255,255,0.03);">
<div class="flip-unit" id="h0">
<div class="card-half card-top"><span class="card-num">0</span></div>
<div class="card-half card-bottom"><span class="card-num">0</span></div>
<div class="leaf">
<div class="leaf-front"><span class="card-num">0</span></div>
<div class="leaf-back"><span class="card-num">0</span></div>
</div>
</div>
<div class="flip-unit" id="h1">
<div class="card-half card-top"><span class="card-num">0</span></div>
<div class="card-half card-bottom"><span class="card-num">0</span></div>
<div class="leaf">
<div class="leaf-front"><span class="card-num">0</span></div>
<div class="leaf-back"><span class="card-num">0</span></div>
</div>
</div>
</div>
<div class="flex flex-col items-center gap-1">
<span class="text-[10px] tracking-[0.2em] text-zinc-500 font-mono">PRIMARY-H</span>
<div class="w-6 h-1 bg-zinc-800 rounded-full relative overflow-hidden text-red-600 status-light-active"></div>
</div>
</div>
<!-- Minutes -->
<div class="flex flex-col items-center gap-4">
<div class="flex gap-1 p-2 bg-black rounded-md shadow-inner relative overflow-hidden"
style="border: 1px solid rgba(255,255,255,0.03);">
<div class="flip-unit" id="m0">
<div class="card-half card-top"><span class="card-num">0</span></div>
<div class="card-half card-bottom"><span class="card-num">0</span></div>
<div class="leaf">
<div class="leaf-front"><span class="card-num">0</span></div>
<div class="leaf-back"><span class="card-num">0</span></div>
</div>
</div>
<div class="flip-unit" id="m1">
<div class="card-half card-top"><span class="card-num">0</span></div>
<div class="card-half card-bottom"><span class="card-num">0</span></div>
<div class="leaf">
<div class="leaf-front"><span class="card-num">0</span></div>
<div class="leaf-back"><span class="card-num">0</span></div>
</div>
</div>
</div>
<div class="flex flex-col items-center gap-1">
<span class="text-[10px] tracking-[0.2em] text-zinc-500 font-mono">SECTOR-M</span>
<div class="w-6 h-1 bg-zinc-800 rounded-full relative overflow-hidden text-red-600 status-light-active"></div>
</div>
</div>
<!-- Seconds -->
<div class="flex flex-col items-center gap-4">
<div class="flex gap-1 p-2 bg-black rounded-md shadow-inner relative overflow-hidden"
style="border: 1px solid rgba(255,255,255,0.03);">
<div class="flip-unit" id="s0">
<div class="card-half card-top"><span class="card-num">0</span></div>
<div class="card-half card-bottom"><span class="card-num">0</span></div>
<div class="leaf">
<div class="leaf-front"><span class="card-num">0</span></div>
<div class="leaf-back"><span class="card-num">0</span></div>
</div>
</div>
<div class="flip-unit" id="s1">
<div class="card-half card-top"><span class="card-num">0</span></div>
<div class="card-half card-bottom"><span class="card-num">0</span></div>
<div class="leaf">
<div class="leaf-front"><span class="card-num">0</span></div>
<div class="leaf-back"><span class="card-num">0</span></div>
</div>
</div>
</div>
<div class="flex flex-col items-center gap-1">
<span class="text-[10px] tracking-[0.2em] text-zinc-500 font-mono">ACTIVE-S</span>
<div class="w-6 h-1 bg-zinc-800 rounded-full relative overflow-hidden text-emerald-500 status-light-active">
</div>
</div>
</div>
<script>
class FlipDigit {
constructor(id) {
this.el = document.getElementById(id);
this.top = this.el.querySelector('.card-top .card-num');
this.bottom = this.el.querySelector('.card-bottom .card-num');
this.front = this.el.querySelector('.leaf-front .card-num');
this.back = this.el.querySelector('.leaf-back .card-num');
this.leaf = this.el.querySelector('.leaf');
this.val = '';
}
update(v) {
if (v === this.val) return;
const old = this.val;
this.val = v;
this.top.textContent = v;
this.bottom.textContent = old;
this.front.textContent = old;
this.back.textContent = v;
this.leaf.classList.remove('flipping');
void this.leaf.offsetWidth;
this.leaf.classList.add('flipping');
setTimeout(() => { this.bottom.textContent = v; this.front.textContent = v; }, 500);
}
}
const clock = {
h0: new FlipDigit('h0'), h1: new FlipDigit('h1'),
m0: new FlipDigit('m0'), m1: new FlipDigit('m1'),
s0: new FlipDigit('s0'), s1: new FlipDigit('s1')
};
function tick() {
const d = new Date();
const h = d.getHours().toString().padStart(2,'0'), m = d.getMinutes().toString().padStart(2,'0'), s = d.getSeconds().toString().padStart(2,'0');
clock.h0.update(h[0]); clock.h1.update(h[1]);
clock.m0.update(m[0]); clock.m1.update(m[1]);
clock.s0.update(s[0]); clock.s1.update(s[1]);
}
setInterval(tick, 1000); tick();
</script>
</div>
</div>