<!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>
<div class="mirror-tunnel" id="tunnel">
<!-- Frames generated by JS -->
</div>
: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.
*/
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)`;
});