library / 3d & webgl / envato-infinite-mirror-room
live - 60fps 1920 x 1080
envato-infinite-mirror-room.html - self-contained
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Infinite Mirror Room</title>
    <style>
        :root {
            --bg-dark: #050510;
            --neon: #00ffff;
            --neon-secondary: #ff00ff;
        }

        body {
            margin: 0;
            height: 100vh;
            background-color: var(--bg-dark);
            overflow: hidden;
            display: flex;
            justify-content: center;
            align-items: center;
            perspective: 800px;
            /* Crucial for the 3D depth illusion */
        }

        /* The container holding the infinite sequence */
        .mirror-tunnel {
            position: relative;
            width: 300px;
            height: 300px;
            transform-style: preserve-3d;
            animation: tunnelDrift 10s linear infinite alternate;
        }

        @keyframes tunnelDrift {
            0% {
                transform: rotateY(-10deg) rotateX(5deg);
            }

            100% {
                transform: rotateY(10deg) rotateX(-5deg);
            }
        }

        /* 
           Using a clever trick: we create multiple nested divs.
           Each frame is exactly the same, but pushed back in Z-space.
        */
        .frame {
            position: absolute;
            inset: 0;
            border: 2px solid rgba(0, 255, 255, 0.5);
            /* Creating the neon door frame look */
            box-shadow:
                0 0 10px var(--neon),
                inset 0 0 10px var(--neon);
            border-radius: 20px;

            /* Inner glowing lights */
            background: linear-gradient(45deg,
                    transparent 49%,
                    rgba(255, 0, 255, 0.2) 50%,
                    transparent 51%);
        }

        /* 
           Javascript will inject 30 of these frames, each translating further into 
           the Z-axis. To create motion, we'll animate them flowing forward. 
        */
    </style>
</head>

<body>

    <div class="mirror-tunnel" id="tunnel">
        <!-- Frames generated by JS -->
    </div>

    <script>
        const tunnel = document.getElementById('tunnel');
        const frameCount = 40;
        const depthStep = 50; // Distance between frames

        for (let i = 0; i < frameCount; i++) {
            const frame = document.createElement('div');
            frame.className = 'frame';

            // Initial positioning
            const zPosition = i * -depthStep;

            // To make it look "infinite", the ones furthest back are darkest
            const opacity = 1 - (i / frameCount);

            frame.style.transform = `translateZ(${zPosition}px)`;
            frame.style.opacity = opacity;

            // Optional: Alternate colors 
            if (i % 3 === 0) {
                frame.style.borderColor = 'rgba(255, 0, 255, 0.5)';
                frame.style.boxShadow = `0 0 15px var(--neon-secondary), inset 0 0 15px var(--neon-secondary)`;
            }

            tunnel.appendChild(frame);
        }

        // Animation Loop shifting all frames forward
        let offset = 0;
        function animateFrames() {
            offset += 0.5; // Speed of forward motion

            if (offset >= depthStep) {
                offset = 0; // Reset loop for continuous illusion
            }

            const frames = document.querySelectorAll('.frame');
            frames.forEach((frame, index) => {
                const zPosition = (index * -depthStep) + offset;
                frame.style.transform = `translateZ(${zPosition}px)`;
            });

            requestAnimationFrame(animateFrames);
        }

        animateFrames();

        // Mouse Parallax Effect
        window.addEventListener('mousemove', (e) => {
            const x = (e.clientX / window.innerWidth - 0.5) * 20; // -10 to +10 deg
            const y = (e.clientY / window.innerHeight - 0.5) * -20; // Inverted Y

            tunnel.style.transition = 'transform 0.1s ease-out';
            // Override CSS animation temporarily or run alongside it
            // tunnel.style.transform = `rotateY(${x}deg) rotateX(${y}deg)`;
        });
    </script>
</body>

</html>

About this animation

A recursive CSS 3D transformation that creates an optical illusion of a never-ending mirrored corridor.

Under the hood

Recursive Z-Axis Translation

A Javascript loop spawns 40 empty frames, spacing each one precisely 50px further back on the Z-axis via CSS translateZ(). To create motion, the script continuously loops an offset variable simulating the camera passing infinitely through these neon doorways.

Source Code
Source copied
Partner hosting options for the copied effect:
Vercel Netlify Hostinger