Double doors

Two panelled doors swing open towards you to reveal the room behind them.

How it works

The doors are the two halves of the stage, hinged on the outer edges with transform-origin. Scroll progress rotates the left door to −110° and the right to +110° around the Y axis, and the scene behind scales down slightly to feel deeper.

Full file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Double doors</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; -webkit-font-smoothing: antialiased; }

body { background: #1e1b18; color: #fff; }
.track { height: 260vh; }
.stage { position: sticky; top: 0; height: 100vh; display: grid; place-items: center; perspective: 1200px; }
.frame { position: relative; width: min(80vw, 560px); aspect-ratio: .78; border: 14px solid #5c4033; border-bottom: 0; transform-style: preserve-3d; }
.room { position: absolute; inset: 0; display: grid; place-content: center; text-align: center;
  background: radial-gradient(circle at 50% 30%, #ffe8a3, #f4a259 50%, #8c4a2f); color: #3b1f12; }
.room h2 { font: 900 clamp(2.4rem, 8vw, 4rem)/1 system-ui, sans-serif; margin: 0 0 .3em; }
.door { position: absolute; top: 0; bottom: 0; width: 50%; background: #7b4b2a; padding: 10% 9%; display: grid; gap: 8%; grid-template-rows: 1fr 1.6fr; will-change: transform; }
.door i { border: 4px solid #5e3720; box-shadow: inset 0 0 0 6px #8d5a35; }
.door b { position: absolute; top: 52%; width: 12px; height: 12px; border-radius: 50%; background: #e7c66b; }
.l { left: 0; transform-origin: 0 50%; box-shadow: inset -2px 0 0 #3d2414; }
.l b { right: 10%; }
.r { right: 0; transform-origin: 100% 50%; }
.r b { left: 10%; }
</style>
</head>
<body>
<section class="track">
  <div class="stage">
    <div class="frame">
      <div class="room" id="room"><h2>Come in.</h2><p>The next page starts here.</p></div>
      <div class="door l" id="dl"><i></i><i></i><b></b></div>
      <div class="door r" id="dr"><i></i><i></i><b></b></div>
    </div>
  </div>
</section>
<script>
const dl = document.getElementById('dl'), dr = document.getElementById('dr'), room = document.getElementById('room');
const track = document.querySelector('.track');
const ease = t => 1 - Math.pow(1 - t, 2);
function update() {
  const r = track.getBoundingClientRect();
  const p = ease(Math.min(1, Math.max(0, -r.top / (r.height - innerHeight))));
  dl.style.transform = 'rotateY(' + (-110 * p) + 'deg)';
  dr.style.transform = 'rotateY(' + (110 * p) + 'deg)';
  dl.style.filter = dr.style.filter = 'brightness(' + (1 - p * 0.5) + ')';
  room.style.transform = 'scale(' + (0.9 + p * 0.1) + ')';
}
addEventListener('scroll', update, { passive: true });
update();
</script>
</body>
</html>

More page turn effects