DEV Community

Sithuni Nudara
Sithuni Nudara

Posted on

3D Cyber Clock


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CRYSTAL CYBER · 3D ROUND CLOCK</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            user-select: none;
        }

        body {
            min-height: 100vh;
            background: radial-gradient(circle at 30% 30%, #0b0f1c, #03050a);
            display: flex;
            align-items: center;
            justify-content: center;
            font-family: 'Segoe UI', 'Avenir', 'Inter', system-ui, sans-serif;
            overflow: hidden;
            position: relative;
        }

        /* animated cyber background (time animation) */
        .cyber-bg {
            position: absolute;
            inset: 0;
            z-index: 0;
            opacity: 0.5;
            background: repeating-linear-gradient(0deg, 
                rgba0,255,255,0.02 0px, 
                rgba0,255,255,0.05 2px, 
                transparent 2px, 
                transparent 8px),
                repeating-linear-gradient(90deg, 
                rgba170, 0, 255, 0.02 0px, 
                rgba0, 255, 255, 0.03 3px, 
                transparent 3px, 
                transparent 12px);
            animation: bg-scroll 20s linear infinite;
            pointer-events: none;
        }

        @keyframes bg-scroll {
            0% { background-position: 0 0, 0 0; }
            100% { background-position: 40px 60px, -60px 40px; }
        }

        /* floating particles (extra magic) */
        .bg-particles {
            position: absolute;
            width: 100%;
            height: 100%;
            z-index: 0;
        }

        .bg-particles span {
            position: absolute;
            width: 4px;
            height: 4px;
            background: rgba0, 255, 255, 0.25;
            box-shadow: 0 0 12px #0ff, 0 0 20px #2ca0ff;
            border-radius: 50%;
            animation: float-particle 18s infinite alternate ease-in-out;
        }

        @keyframes float-particle {
            0% { transform: translate(0, 0) scale(1); opacity: 0.3; }
            100% { transform: translate(40px, -60px) scale(1.8); opacity: 0; }
        }

        /* main container – movable 3d effect */
        .clock-container {
            position: relative;
            z-index: 30;
            transform-style: preserve-3d;
            transform: perspective(1200px) rotateX(4deg) rotateY(6deg) translateZ(20px);
            transition: transform 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.2);
            cursor: default;
            filter: drop-shadow(0 20px 30px #00000070);
        }

        .clock-container:hover {
            transform: perspective(1000px) rotateX(2deg) rotateY(12deg) translateZ(30px);
        }

        /* 3D glass ring + numbers */
        .round-clock {
            --glow: 0 0 30px #00ffff88, 0 0 70px #00a3ff66;
            --dark-cyan: #0e4b5e;
            --crystal-light: #b5f0ff;
            width: 360px;
            height: 360px;
            border-radius: 50%;
            background: radial-gradient(circle at 28% 30%, 
                rgba(20, 80, 100, 0.7) 5%, 
                #131f2b 60%,
                #0b141c 95%);
            box-shadow: 
                inset -6px -10px 20px rgba0,0,0,0.9,
                inset 15px 15px 30px rgba(170, 240, 255, 0.4),
                0 0 0 2px rgba(0, 255, 255, 0.3) inset,
                0 0 0 4px rgba(20, 40, 50, 0.8),
                0 20px 35px #000000cc,
                var(--glow);
            position: relative;
            backdrop-filter: blur(2px);
            display: flex;
            align-items: center;
            justify-content: center;
            transition: box-shadow 0.4s, background 0.3s;
        }

        /* hover = light mode / cyan explosion */
        .round-clock:hover {
            --glow: 0 0 40px cyan, 0 0 100px #7ff0ff, 0 0 150px #2ad4ff;
            background: radial-gradient(circle at 30% 30%, 
                rgba(150, 250, 255, 0.4) 5%, 
                #1e3b48 50%,
                #0b1a24 95%);
            box-shadow: 
                inset -6px -10px 20px #000000aa,
                inset 20px 20px 40px #d0f4ff,
                0 0 0 3px #4ff5ff inset,
                0 0 0 5px #0099aa33,
                0 25px 45px #000,
                var(--glow);
        }

        /* crystal 3D facets (glass layers) */
        .clock-facet {
            position: absolute;
            inset: 8px;
            border-radius: 50%;
            background: repeating-conic-gradient(
                from 45deg,
                rgba(170, 240, 255, 0.05) 0deg 10deg,
                rgba(10, 30, 40, 0.3) 10deg 20deg,
                transparent 20deg 30deg
            );
            pointer-events: none;
            border: 1px solid rgba(0, 255, 255, 0.2);
            box-shadow: 0 0 20px rgba(0, 200, 210, 0.3) inset;
        }

        .clock-facet::after {
            content: '';
            position: absolute;
            inset: 20px;
            border-radius: 50%;
            background: radial-gradient(circle at 40% 40%, rgba(255,255,255,0.2) 2px, transparent 30%);
            opacity: 0.6;
        }

        /* digital numbers (cyan, mixed with gray/black crystal) */
        .digital-display {
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            width: 220px;
            height: 220px;
            background: rgba(8, 18, 28, 0.5);
            backdrop-filter: blur(4px);
            border-radius: 50%;
            border: 2px solid rgba(0, 255, 255, 0.25);
            box-shadow: 0 0 40px #0ff3, 0 0 20px #2e5f6b inset;
            transform: translateZ(12px);
            transition: all 0.2s;
        }

        .round-clock:hover .digital-display {
            background: rgba(20, 40, 50, 0.4);
            border: 2px solid #aaffff;
            box-shadow: 0 0 70px cyan, 0 0 30px #3ff inset;
        }

        .time {
            font-size: 3.6rem;
            font-weight: 400;
            letter-spacing: 6px;
            color: #00ffff;
            text-shadow: 0 0 12px cyan, 0 0 30px #0077ff, 0 0 45px #004466;
            font-family: 'Orbitron', 'Courier New', monospace;
            background: linear-gradient(135deg, #a0f0ff 20%, #38858f 70%);
            -webkit-background-clip: text;
            background-clip: text;
            -webkit-text-fill-color: transparent;
            transition: text-shadow 0.3s;
            line-height: 1.2;
        }

        .round-clock:hover .time {
            text-shadow: 0 0 20px #f0fdff, 0 0 50px #3cc, 0 0 80px #0ff;
            background: linear-gradient(135deg, #efff ff 10%, #6ff0ff 90%);
            -webkit-background-clip: text;
            background-clip: text;
        }

        .date {
            font-size: 1.1rem;
            letter-spacing: 3px;
            color: #6baeb6;
            text-shadow: 0 0 10px #0ff;
            background: #121e24b3;
            padding: 4px 16px;
            border-radius: 40px;
            margin-top: 8px;
            backdrop-filter: blur(2px);
            border: 1px solid #2a8a9a;
            font-weight: 300;
            transition: 0.3s;
        }

        .round-clock:hover .date {
            background: #16363f;
            color: #e0ffff;
            border-color: cyan;
            box-shadow: 0 0 20px cyan;
        }

        /* seconds弧形指示 (extra cyber) */
        .second-ring {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 50%;
            transform: rotate(-90deg);
        }

        .second-ring circle {
            fill: none;
            stroke-width: 5;
            stroke: #0ff;
            filter: drop-shadow(0 0 15px cyan);
            stroke-linecap: round;
            stroke-dasharray: 879.2; /* circumference for r=140 ~ 879.2 */
            stroke-dashoffset: 879.2;
            transition: stroke-dashoffset 0.1s linear;
        }

        .second-ring-bg {
            stroke: rgba0, 180, 200, 0.25;
            stroke-width: 5;
            fill: none;
        }

        /* 3D movable base reflection */
        .glass-reflection {
            position: absolute;
            top: 10%;
            left: 15%;
            width: 40%;
            height: 20%;
            background: radial-gradient(ellipse at 30% 30%, rgba(255,255,255,0.3) 0%, transparent 70%);
            border-radius: 50%;
            filter: blur(8px);
            mix-blend-mode: overlay;
            pointer-events: none;
        }

        .glass-reflection2 {
            bottom: 15%;
            right: 10%;
            width: 30%;
            height: 15%;
            background: radial-gradient(ellipse, #6fffff40, transparent 80%);
            position: absolute;
            filter: blur(12px);
            border-radius: 50%;
        }

        /* movable control: subtle rotate on mousemove */
        .clock-container.movable {
            transition: transform 0.08s;
        }

        footer {
            position: absolute;
            bottom: 16px;
            color: #1d7c84;
            font-size: 0.8rem;
            text-shadow: 0 0 4px cyan;
            z-index: 40;
            letter-spacing: 2px;
        }
    </style>
</head>
<body>
    <div class="cyber-bg"></div>
    <div class="bg-particles" id="particles"></div>

    <div class="clock-container" id="clockContainer">
        <div class="round-clock" id="roundClock">
            <!-- 3d crystal facets -->
            <div class="clock-facet"></div>
            <!-- seconds progress ring (svg) -->
            <svg class="second-ring" viewBox="0 0 360 360" width="360" height="360">
                <circle class="second-ring-bg" cx="180" cy="180" r="160" stroke="#097a8f55" stroke-width="6" fill="none"/>
                <circle id="secCircle" cx="180" cy="180" r="160" stroke="#0ff" stroke-width="8" fill="none" 
                    stroke-dasharray="1005.3" stroke-dashoffset="1005.3" style="filter: drop-shadow(0 0 25px cyan);" />
            </svg>
            <!-- digital core -->
            <div class="digital-display">
                <div class="time" id="timeDisplay">23:15</div>
                <div class="date" id="dateDisplay">2025-04-07</div>
            </div>
            <!-- extra glass glitter -->
            <div class="glass-reflection"></div>
            <div class="glass-reflection2"></div>
        </div>
    </div>

    <footer>❖ C R Y S T A L   C Y B E R   3 D ❖</footer>

    <script>
        (function() {
            // particles background magic
            const particleContainer = document.getElementById('particles');
            for (let i = 0; i < 36; i++) {
                let span = document.createElement('span');
                let size = Math.random() * 6 + 2;
                span.style.width = size + 'px';
                span.style.height = size + 'px';
                span.style.left = Math.random() * 100 + '%';
                span.style.top = Math.random() * 100 + '%';
                span.style.animationDelay = Math.random() * 15 + 's';
                span.style.animationDuration = 10 + Math.random() * 20 + 's';
                span.style.background = i % 3 === 0 ? '#7ff5ff' : '#3ea0cc';
                span.style.boxShadow = `0 0 30px #0ff, 0 0 50px #1fa0ff`;
                particleContainer.appendChild(span);
            }

            // time update + animation
            const timeEl = document.getElementById('timeDisplay');
            const dateEl = document.getElementById('dateDisplay');
            const secCircle = document.getElementById('secCircle');

            function updateClock() {
                const now = new Date();
                const hours = now.getHours().toString().padStart(2, '0');
                const minutes = now.getMinutes().toString().padStart(2, '0');
                const seconds = now.getSeconds();
                timeEl.textContent = `${hours}:${minutes}`;

                const year = now.getFullYear();
                const month = (now.getMonth() + 1).toString().padStart(2, '0');
                const day = now.getDate().toString().padStart(2, '0');
                dateEl.textContent = `${year}-${month}-${day}`;

                // update second ring (circumference for r=160 = 2*pi*160 ≈ 1005.3)
                const radius = 160;
                const circumference = 2 * Math.PI * radius; // ~1005.3
                const offset = circumference - (seconds / 60) * circumference;
                secCircle.style.strokeDasharray = `${circumference}`;
                secCircle.style.strokeDashoffset = offset;
            }
            updateClock();
            setInterval(updateClock, 500);

            // 3D movable effect: follow cursor
            const container = document.getElementById('clockContainer');
            const roundClock = document.getElementById('roundClock');
            let bounds = container.getBoundingClientRect();
            let mouseX = 0, mouseY = 0;
            let currentRotateX = 4, currentRotateY = 6; // initial values
            const factor = 0.04; // sensitivity

            window.addEventListener('resize', () => {
                bounds = container.getBoundingClientRect();
            });

            document.addEventListener('mousemove', (e) => {
                // relative position to window
                const centerX = window.innerWidth / 2;
                const centerY = window.innerHeight / 2;

                // offset from center (-1..1)
                const normX = (e.clientX - centerX) / centerX;
                const normY = (e.clientY - centerY) / centerY;

                // target rotation angles (max ±12°)
                const targetRotateY = 6 + normX * 8;   // horizontal tilt
                const targetRotateX = 4 - normY * 6;   // vertical tilt

                // smooth-ish update
                currentRotateX += (targetRotateX - currentRotateX) * 0.1;
                currentRotateY += (targetRotateY - currentRotateY) * 0.1;

                container.style.transform = `perspective(1200px) rotateX(${currentRotateX}deg) rotateY(${currentRotateY}deg) translateZ(20px)`;
            });

            // extra hover light effect: but we keep hover in css, fine.
            // also add dynamic shadow enhancement on hover
            roundClock.addEventListener('mouseenter', () => {
                // optional: we could add class, but css handles it.
            });

            // add magic floating animation on digits randomly (extra spark)
            setInterval(() => {
                if (Math.random() > 0.7) {
                    timeEl.style.transform = `scale(${1 + Math.random() * 0.1})`;
                    timeEl.style.transition = 'transform 0.15s cubic-bezier(0.2,1,0.5,1)';
                    setTimeout(() => {
                        timeEl.style.transform = 'scale(1)';
                    }, 150);
                }
            }, 800);

            // also change the color of date for micro interaction
            setInterval(() => {
                if (Math.random() > 0.85) {
                    dateEl.style.textShadow = '0 0 18px #f0f, 0 0 30px #0ff';
                    dateEl.style.transition = '0.1s';
                    setTimeout(() => {
                        dateEl.style.textShadow = '0 0 10px #0ff';
                    }, 120);
                }
            }, 1300);
        })();
    </script>
    <!-- optional font for better digits -->
    <link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500&display=swap" rel="stylesheet">
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)