n.    \<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dimensional Rift</title>
</head>

<body>
  <div class="dimension-container">
    <div class="dimension ps1-world" id="ps1World">
      <div class="ps1-character"></div>
      <div class="ps1-environment">
        <div class="low-poly-object wall wall-left"></div>
        <div class="low-poly-object wall wall-right"></div>
        <div class="low-poly-object wall wall-back"></div>
        <div class="low-poly-object floor"></div>
        <div class="low-poly-object ceiling"></div>
      </div>
      <div class="ps1-fog"></div>
    </div>

    <div class="dimension vhs-world" id="vhsWorld">
      <div class="vhs-static"></div>
      <div class="vhs-overlay"></div>
      <div class="vhs-tracking"></div>
      <div class="vhs-content">
        <div class="vhs-text">PLAY ME</div>
      </div>
    </div>

    <div class="rift-tear" id="riftTear"></div>

    <div class="interface">
      <div class="instruction-overlay">
        <div class="instruction-text">
          <p class="instruction-title">HOW TO INTERACT WITH THE RIFT</p>
          <p class="instruction-body">They say if you tear at reality long enough, something tears back.</p>
          <p class="instruction-body">The entities have been waiting, trapped between frames of static and forgotten recordings.</p>
          <p class="instruction-body">Drag to open tears in reality. Release to close them.</p>
          <p class="instruction-body">Press SPACE or double-tap to banish what comes through.</p>
          <p class="instruction-warning">What sees you through the rift remembers your face even after the tear is mended.</p>
        </div>
      </div>
      <div class="glitch-text" data-text="DIMENSIONAL RIFT">DIMENSIONAL RIFT</div>
      <div class="instructions">DRAG TO TEAR REALITY</div>
      <div class="health-bar">
        <div class="health-fill"></div>
      </div>
      <div class="glitch-meter">
        <div class="glitch-fill"></div>
      </div>
    </div>

    <div class="entities-container" id="entitiesContainer"></div>

    <div class="noise-overlay"></div>
    <div class="crt-lines"></div>
    <div class="vignette"></div>
  </div>

  <audio id="ambient" loop>
    <source src="https://assets.codepen.io/1948355/ambient-horror.mp3" type="audio/mpeg">
  </audio>
  <audio id="glitch-sound">
    <source src="https://assets.codepen.io/1948355/glitch-sound.mp3" type="audio/mpeg">
  </audio>
  <audio id="entity-sound">
    <source src="https://assets.codepen.io/1948355/entity-sound.mp3" type="audio/mpeg">
  </audio>
</body>

</html>
@import url('https://fonts.googleapis.com/css2?family=VT323&family=Roboto+Mono:wght@400;700&display=swap');

:root {
--ps1-primary: #2a0e12;
--ps1-secondary: #3d1b1f;
--ps1-accent: #8b0000;
--vhs-primary: #000000;
--vhs-secondary: #111111;
--vhs-accent: #ff0066;
--glitch-color-1: #ff0000;
--glitch-color-2: #0000ff;
--glitch-color-3: #00ff00;
}

*, *::before, *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}

body {
background-color: #000;
font-family: 'VT323', monospace;
height: 100vh;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
color: #ffffff;
cursor: none;
}

.dimension-container {
position:center;
width: 100vw;
height: 100vh;
overflow: hidden;
perspective: 1000px;
}

.dimension {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: opacity 0.5s ease;
}

/* PS1 World Styling */
.ps1-world {
background-color: var(--ps1-primary);
perspective: 800px;
transform-style: preserve-3d;
z-index: 1;
}

.ps1-environment {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform-style: preserve-3d;
}

.low-poly-object {
position: absolute;
background-color: var(--ps1-secondary);
image-rendering: pixelated;
}

.wall {
width: 100%;
height: 100%;
background-image: 
  repeating-linear-gradient(
    to right,
    rgba(0, 0, 0, 0.1) 0px,
    rgba(0, 0, 0, 0.1) 2px,
    transparent 2px,
    transparent 4px
  ),
  repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.1) 0px,
    rgba(0, 0, 0, 0.1) 2px,
    transparent 2px,
    transparent 4px
  );
}

.wall-left {
left: 0;
width: 1px;
transform: translateX(-50%) rotateY(90deg) translateZ(-50vw);
}

.wall-right {
right: 0;
width: 1px;
transform: translateX(50%) rotateY(-90deg) translateZ(-50vw);
}

.wall-back {
transform: translateZ(-100px);
}

.floor {
bottom: 0;
width: 100%;
height: 1px;
transform: translateY(50%) rotateX(90deg) translateZ(50vh);
background-image: 
  repeating-linear-gradient(
    to right,
    rgba(0, 0, 0, 0.2) 0px,
    rgba(0, 0, 0, 0.2) 20px,
    rgba(0, 0, 0, 0.1) 20px,
    rgba(0, 0, 0, 0.1) 40px
  ),
  repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.2) 0px,
    rgba(0, 0, 0, 0.2) 20px,
    rgba(0, 0, 0, 0.1) 20px,
    rgba(0, 0, 0, 0.1) 40px
  );
}

.ceiling {
top: 0;
width: 100%;
height: 1px;
transform: translateY(-50%) rotateX(-90deg) translateZ(50vh);
background-color: var(--ps1-primary);
}

.ps1-character {
position: absolute;
width: 30px;
height: 60px;
bottom: 0;
left: 50%;
transform: translateX(-50%);
background-color: #333;
z-index: 2;
}

.ps1-fog {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(
  circle at center,
  transparent 0%,
  rgba(0, 0, 0, 0.8) 80%
);
z-index: 3;
pointer-events: none;
}

/* VHS World Styling */
.vhs-world {
background-color: var(--vhs-primary);
z-index: 2;
opacity: 0;
}

.vhs-static {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.4'/%3E%3C/svg%3E");
opacity: 0.1;
z-index: 1;
}

.vhs-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
  180deg,
  rgba(255, 0, 102, 0.05) 0%,
  rgba(0, 0, 255, 0.05) 100%
);
z-index: 2;
mix-blend-mode: screen;
}

.vhs-tracking {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 3;
pointer-events: none;
overflow: hidden;
}

.vhs-tracking::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 200%;
background: repeating-linear-gradient(
  transparent 0%,
  rgba(255, 255, 255, 0.05) 0.5%,
  transparent 1%
);
animation: trackingLines 10s linear infinite;
}

.vhs-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 4;
text-align: center;
}

.vhs-text {
font-size: 5rem;
font-family: 'VT323', monospace;
color: var(--vhs-accent);
text-shadow: 4px 4px 0 rgba(0, 0, 0, 0.5);
animation: vhsFlicker 2s infinite;
}

/* Rift Tear Styling */
.rift-tear {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 0;
height: 0;
background: linear-gradient(
  135deg,
  rgba(255, 0, 102, 0.7),
  rgba(0, 0, 255, 0.7)
);
border-radius: 50%;
box-shadow: 0 0 20px rgba(255, 0, 102, 0.7),
            0 0 40px rgba(0, 0, 255, 0.7);
z-index: 10;
transition: all 0.3s ease;
clip-path: polygon(
  50% 0%,
  60% 20%,
  80% 10%,
  70% 30%,
  100% 40%,
  80% 50%,
  100% 60%,
  80% 70%,
  90% 90%,
  70% 80%,
  50% 100%,
  30% 80%,
  10% 90%,
  20% 70%,
  0% 60%,
  20% 50%,
  0% 40%,
  30% 30%,
  20% 10%,
  40% 20%
);
}

/* Interface Styling */
.interface {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 20;
pointer-events: none;
padding: 20px;
}

.glitch-text {
font-size: 2rem;
position: relative;
text-transform: uppercase;
letter-spacing: 4px;
margin-bottom: 10px;
}

@media (prefers-reduced-motion: no-preference) {
.glitch-text::before,
.glitch-text::after {
  content: attr(data-text);
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.glitch-text::before {
  left: 2px;
  text-shadow: -2px 0 var(--glitch-color-1);
  clip: rect(24px, 550px, 90px, 0);
  animation: glitch-anim 3s infinite linear alternate-reverse;
}

.glitch-text::after {
  left: -2px;
  text-shadow: -2px 0 var(--glitch-color-2);
  clip: rect(85px, 550px, 140px, 0);
  animation: glitch-anim2 2.5s infinite linear alternate-reverse;
}
}

.instructions {
font-size: 1rem;
opacity: 0.7;
margin-bottom: 20px;
}

.health-bar, .glitch-meter {
width: 200px;
height: 15px;
background-color: rgba(0, 0, 0, 0.5);
border: 1px solid rgba(255, 255, 255, 0.3);
margin-bottom: 10px;
position: relative;
}

.health-fill {
height: 100%;
width: 100%;
background-color: #ff0000;
transition: width 0.3s ease;
}

.glitch-fill {
height: 100%;
width: 0%;
background: linear-gradient(90deg, #ff00ff, #00ffff);
transition: width 0.3s ease;
}

/* Entities Styling */
.entity {
position: absolute;
width: 40px;
height: 80px;
background-color: rgba(0, 0, 0, 0.8);
z-index: 5;
transition: transform 0.5s ease;
}

.entity::before {
content: '';
position: absolute;
top: 10px;
left: 50%;
transform: translateX(-50%);
width: 20px;
height: 10px;
background-color: var(--vhs-accent);
box-shadow: 0 0 10px var(--vhs-accent);
}

/* Effects Overlays */
.noise-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.05'/%3E%3C/svg%3E");
pointer-events: none;
z-index: 30;
mix-blend-mode: overlay;
}

.crt-lines {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: repeating-linear-gradient(
  to bottom,
  rgba(0, 0, 0, 0) 0px,
  rgba(0, 0, 0, 0) 1px,
  rgba(0, 0, 0, 0.1) 1px,
  rgba(0, 0, 0, 0.1) 2px
);
pointer-events: none;
z-index: 31;
}

.vignette {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(
  ellipse at center,
  rgba(0, 0, 0, 0) 60%,
  rgba(0, 0, 0, 0.7) 100%
);
pointer-events: none;
z-index: 32;
}

/* Animations */
@keyframes trackingLines {
0% {
  transform: translateY(-50%);
}
100% {
  transform: translateY(0%);
}
}

@keyframes vhsFlicker {
0%, 100% {
  opacity: 1;
}
92%, 94%, 96% {
  opacity: 0.8;
}
93%, 95%, 97% {
  opacity: 1;
}
}

@keyframes glitch-anim {
0% {
  clip: rect(41px, 9999px, 44px, 0);
}
5% {
  clip: rect(91px, 9999px, 100px, 0);
}
10% {
  clip: rect(54px, 9999px, 99px, 0);
}
15% {
  clip: rect(37px, 9999px, 56px, 0);
}
20% {
  clip: rect(73px, 9999px, 75px, 0);
}
25% {
  clip: rect(77px, 9999px, 100px, 0);
}
30% {
  clip: rect(94px, 9999px, 98px, 0);
}
35% {
  clip: rect(96px, 9999px, 99px, 0);
}
40% {
  clip: rect(61px, 9999px, 97px, 0);
}
45% {
  clip: rect(60px, 9999px, 73px, 0);
}
50% {
  clip: rect(19px, 9999px, 33px, 0);
}
55% {
  clip: rect(15px, 9999px, 37px, 0);
}
60% {
  clip: rect(14px, 9999px, 49px, 0);
}
65% {
  clip: rect(64px, 9999px, 94px, 0);
}
70% {
  clip: rect(89px, 9999px, 100px, 0);
}
75% {
  clip: rect(53px, 9999px, 54px, 0);
}
80% {
  clip: rect(10px, 9999px, 54px, 0);
}
85% {
  clip: rect(21px, 9999px, 59px, 0);
}
90% {
  clip: rect(70px, 9999px, 74px, 0);
}
95% {
  clip: rect(85px, 9999px, 87px, 0);
}
100% {
  clip: rect(5px, 9999px, 53px, 0);
}
}

@keyframes glitch-anim2 {
0% {
  clip: rect(65px, 9999px, 119px, 0);
}
5% {
  clip: rect(133px, 9999px, 171px, 0);
}
10% {
  clip: rect(13px, 9999px, 80px, 0);
}
15% {
  clip: rect(137px, 9999px, 195px, 0);
}
20% {
  clip: rect(24px, 9999px, 87px, 0);
}
25% {
  clip: rect(132px, 9999px, 172px, 0);
}
30% {
  clip: rect(24px, 9999px, 51px, 0);
}
35% {
  clip: rect(54px, 9999px, 130px, 0);
}
40% {
  clip: rect(123px, 9999px, 169px, 0);
}
45% {
  clip: rect(123px, 9999px, 146px, 0);
}
50% {
  clip: rect(132px, 9999px, 167px, 0);
}
55% {
  clip: rect(19px, 9999px, 66px, 0);
}
60% {
  clip: rect(94px, 9999px, 135px, 0);
}
65% {
  clip: rect(69px, 9999px, 130px, 0);
}
70% {
  clip: rect(96px, 9999px, 166px, 0);
}
75% {
  clip: rect(134px, 9999px, 196px, 0);
}
80% {
  clip: rect(18px, 9999px, 31px, 0);
}
85% {
  clip: rect(61px, 9999px, 143px, 0);
}
90% {
  clip: rect(13px, 9999px, 76px, 0);
}
95% {
  clip: rect(6px, 9999px, 98px, 0);
}
100% {
  clip: rect(25px, 9999px, 45px, 0);
}
}

/* Custom cursor */
.custom-cursor {
position: fixed;
width: 20px;
height: 20px;
border: 2px solid white;
border-radius: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
z-index: 9999;
mix-blend-mode: difference;
}

/* Reduced motion styles */
@media (prefers-reduced-motion: reduce) {
.glitch-text::before,
.glitch-text::after {
  animation: none;
}

.vhs-tracking::before {
  animation: none;
}

.vhs-text {
  animation: none;
}
}
.instruction-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
z-index: 40;
pointer-events: none;
opacity: 1;
transition: opacity 2s ease;
}

.instruction-text {
max-width: 80%;
padding: 20px;
background-color: rgba(0, 0, 0, 0.7);
border: 1px solid rgba(255, 0, 102, 0.3);
text-align: center;
}

.instruction-title {
font-size: 1.5rem;
margin-bottom: 15px;
color: var(--vhs-accent);
letter-spacing: 2px;
}

.instruction-body {
font-size: 1rem;
margin-bottom: 10px;
color: #ffffff;
opacity: 0.8;
}

.instruction-warning {
font-size: 0.9rem;
margin-top: 15px;
color: #ff0000;
font-style: italic;
}
document.addEventListener("DOMContentLoaded", () => {
  // DOM Elements
  const dimensionContainer = document.querySelector(".dimension-container");
  const ps1World = document.getElementById("ps1World");
  const vhsWorld = document.getElementById("vhsWorld");
  const riftTear = document.getElementById("riftTear");
  const entitiesContainer = document.getElementById("entitiesContainer");
  const healthFill = document.querySelector(".health-fill");
  const glitchFill = document.querySelector(".glitch-fill");

  // Audio elements
  const ambientSound = document.getElementById("ambient");
  const glitchSound = document.getElementById("glitch-sound");
  const entitySound = document.getElementById("entity-sound");

  // Game state
  let health = 100;
  let glitchEnergy = 0;
  let isDragging = false;
  let mouseX = 0;
  let mouseY = 0;
  let riftSize = 0;
  let worldBalance = 0; // 0 = PS1 world, 1 = VHS world
  let entities = [];
  let isReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)")
    .matches;

  // Create custom cursor
  const cursor = document.createElement("div");
  cursor.classList.add("custom-cursor");
  document.body.appendChild(cursor);

  // Initialize the experience
  function init() {
    // Set up event listeners
    document.addEventListener("mousemove", handleMouseMove);
    document.addEventListener("mousedown", handleMouseDown);
    document.addEventListener("mouseup", handleMouseUp);
    document.addEventListener("touchstart", handleTouchStart, {
      passive: false
    });
    document.addEventListener("touchmove", handleTouchMove, { passive: false });
    document.addEventListener("touchend", handleTouchEnd);
    setTimeout(() => {
      const instructionOverlay = document.querySelector(".instruction-overlay");
      if (instructionOverlay) {
        instructionOverlay.style.opacity = "0";

        // Remove from DOM after fade out
        setTimeout(() => {
          instructionOverlay.style.display = "none";
        }, 3000);
      }
    }, 6000);

    // Start ambient sound with low volume
    if (ambientSound) {
      ambientSound.volume = 0.4;
      ambientSound.play().catch((e) => console.log("Audio couldn't play: ", e));
    }

    // Generate initial entities
    generateEntities(3);

    // Start game loop
    requestAnimationFrame(gameLoop);
  }

  // Handle mouse movement
  function handleMouseMove(e) {
    mouseX = e.clientX;
    mouseY = e.clientY;

    // Update custom cursor position
    cursor.style.left = `${mouseX}px`;
    cursor.style.top = `${mouseY}px`;

    if (isDragging) {
      updateRiftTear();
    }
  }

  // Handle touch movement
  function handleTouchMove(e) {
    e.preventDefault();
    if (e.touches.length > 0) {
      mouseX = e.touches[0].clientX;
      mouseY = e.touches[0].clientY;

      if (isDragging) {
        updateRiftTear();
      }
    }
  }

  // Handle mouse down
  function handleMouseDown() {
    isDragging = true;
    cursor.style.transform = "translate(-50%, -50%) scale(0.8)";

    // Position the rift tear at the cursor
    riftTear.style.left = `${mouseX}px`;
    riftTear.style.top = `${mouseY}px`;
  }

  // Handle touch start
  function handleTouchStart(e) {
    e.preventDefault();
    isDragging = true;

    if (e.touches.length > 0) {
      mouseX = e.touches[0].clientX;
      mouseY = e.touches[0].clientY;

      // Position the rift tear at the touch point
      riftTear.style.left = `${mouseX}px`;
      riftTear.style.top = `${mouseY}px`;
    }
  }

  // Handle mouse up
  function handleMouseUp() {
    isDragging = false;
    cursor.style.transform = "translate(-50%, -50%) scale(1)";

    // Shrink the rift tear
    shrinkRiftTear();
  }

  // Handle touch end
  function handleTouchEnd() {
    isDragging = false;

    // Shrink the rift tear
    shrinkRiftTear();
  }

  // Update the rift tear
  function updateRiftTear() {
    // Increase rift size while dragging
    riftSize = Math.min(riftSize + 2, 300);

    // Update rift tear size
    riftTear.style.width = `${riftSize}px`;
    riftTear.style.height = `${riftSize}px`;

    // Update world balance based on rift size
    worldBalance = riftSize / 300;

    // Update world visibility
    vhsWorld.style.opacity = worldBalance;

    // Increase glitch energy
    glitchEnergy = Math.min(glitchEnergy + 0.5, 100);
    glitchFill.style.width = `${glitchEnergy}%`;

    // Create glitch effects
    if (riftSize > 50 && !isReducedMotion) {
      createGlitchEffect();
    }

    // Play glitch sound
    if (glitchSound && riftSize % 30 === 0) {
      glitchSound.currentTime = 0;
      glitchSound.volume = 0.2;
      glitchSound.play().catch((e) => {});
    }
  }

  // Shrink the rift tear
  function shrinkRiftTear() {
    const shrinkInterval = setInterval(() => {
      riftSize = Math.max(riftSize - 10, 0);

      // Update rift tear size
      riftTear.style.width = `${riftSize}px`;
      riftTear.style.height = `${riftSize}px`;

      // Update world balance based on rift size
      worldBalance = riftSize / 300;

      // Update world visibility
      vhsWorld.style.opacity = worldBalance;

      if (riftSize === 0) {
        clearInterval(shrinkInterval);
      }
    }, 50);
  }

  // Create glitch effect
  function createGlitchEffect() {
    if (Math.random() > 0.7) {
      const glitchType = Math.floor(Math.random() * 3);

      switch (glitchType) {
        case 0:
          // Color shift
          dimensionContainer.style.filter = `hue-rotate(${
            Math.random() * 360
          }deg)`;
          setTimeout(() => {
            dimensionContainer.style.filter = "";
          }, 100);
          break;
        case 1:
          // Displacement
          dimensionContainer.style.transform = `translateX(${
            Math.random() * 20 - 10
          }px)`;
          setTimeout(() => {
            dimensionContainer.style.transform = "";
          }, 100);
          break;
        case 2:
          // Scanline glitch
          const scanline = document.createElement("div");
          scanline.classList.add("scanline-glitch");
          scanline.style.cssText = `
          position: absolute;
          top: ${Math.random() * 100}%;
          left: 0;
          width: 100%;
          height: ${Math.random() * 10 + 5}px;
          background-color: rgba(255, 255, 255, 0.2);
          z-index: 25;
        `;
          dimensionContainer.appendChild(scanline);

          setTimeout(() => {
            scanline.remove();
          }, 200);
          break;
      }
    }
  }

  // Generate entities
  function generateEntities(count) {
    for (let i = 0; i < count; i++) {
      createEntity();
    }
  }

  // Create entity
  function createEntity() {
    const entity = document.createElement("div");
    entity.classList.add("entity");

    // Random position outside the viewport
    const side = Math.floor(Math.random() * 4);
    let x, y;

    switch (side) {
      case 0: // Top
        x = Math.random() * window.innerWidth;
        y = -100;
        break;
      case 1: // Right
        x = window.innerWidth + 100;
        y = Math.random() * window.innerHeight;
        break;
      case 2: // Bottom
        x = Math.random() * window.innerWidth;
        y = window.innerHeight + 100;
        break;
      case 3: // Left
        x = -100;
        y = Math.random() * window.innerHeight;
        break;
    }

    entity.style.left = `${x}px`;
    entity.style.top = `${y}px`;

    // Add entity to the container and track it
    entitiesContainer.appendChild(entity);
    entities.push({
      element: entity,
      x: x,
      y: y,
      speed: Math.random() * 0.5 + 0.5,
      visible: worldBalance > 0.5 // Only visible in VHS world
    });

    return entity;
  }

  // Update entity positions
  function updateEntities() {
    entities.forEach((entity, index) => {
      // Determine if entity should be visible based on world balance
      entity.visible = worldBalance > 0.5;
      entity.element.style.opacity = entity.visible ? "1" : "0";

      if (entity.visible) {
        // Move toward player
        const dx = window.innerWidth / 2 - entity.x;
        const dy = window.innerHeight / 2 - entity.y;
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance > 5) {
          const angle = Math.atan2(dy, dx);
          entity.x += Math.cos(angle) * entity.speed;
          entity.y += Math.sin(angle) * entity.speed;

          entity.element.style.left = `${entity.x}px`;
          entity.element.style.top = `${entity.y}px`;

          // Apply glitch effect to entity
          if (Math.random() > 0.95 && !isReducedMotion) {
            entity.element.style.transform = `translateX(${
              Math.random() * 10 - 5
            }px)`;
            setTimeout(() => {
              entity.element.style.transform = "";
            }, 100);
          }
        } else {
          // Entity reached player, reduce health
          damagePlayer(5);

          // Remove entity
          entity.element.remove();
          entities.splice(index, 1);

          // Play entity sound
          if (entitySound) {
            entitySound.currentTime = 0;
            entitySound.volume = 0.4;
            entitySound.play().catch((e) => {});
          }

          // Create new entity
          setTimeout(() => {
            createEntity();
          }, 2000);
        }
      }
    });

    // Occasionally spawn new entities
    if (Math.random() > 0.995 && entities.length < 5) {
      createEntity();
    }
  }

  // Damage player
  function damagePlayer(amount) {
    health = Math.max(health - amount, 0);
    healthFill.style.width = `${health}%`;

    // Screen shake effect
    if (!isReducedMotion) {
      dimensionContainer.style.animation = "shake 0.5s";
      setTimeout(() => {
        dimensionContainer.style.animation = "";
      }, 500);
    }

    // Game over if health reaches 0
    if (health <= 0) {
      gameOver();
    }
  }

  // Use glitch energy to attack entities
  function useGlitchAttack() {
    if (glitchEnergy >= 50) {
      // Reduce glitch energy
      glitchEnergy -= 50;
      glitchFill.style.width = `${glitchEnergy}%`;

      // Create attack effect
      const attackEffect = document.createElement("div");
      attackEffect.classList.add("glitch-attack");
      attackEffect.style.cssText = `
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      width: 0;
      height: 0;
      background: radial-gradient(circle, rgba(255,0,255,0.5) 0%, rgba(0,255,255,0.5) 100%);
      border-radius: 50%;
      z-index: 20;
      animation: expandAttack 1s forwards;
    `;
      dimensionContainer.appendChild(attackEffect);

      // Add keyframes for attack animation
      const style = document.createElement("style");
      style.textContent = `
      @keyframes expandAttack {
        0% {
          width: 0;
          height: 0;
          opacity: 1;
        }
        100% {
          width: 200vw;
          height: 200vw;
          opacity: 0;
        }
      }
      
      @keyframes shake {
        0%, 100% { transform: translateX(0); }
        10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
        20%, 40%, 60%, 80% { transform: translateX(5px); }
      }
    `;
      document.head.appendChild(style);

      // Remove entities
      entities.forEach((entity) => {
        entity.element.remove();
      });
      entities = [];

      // Generate new entities after a delay
      setTimeout(() => {
        generateEntities(2);
      }, 3000);

      // Remove attack effect after animation
      setTimeout(() => {
        attackEffect.remove();
      }, 1000);
    }
  }

  // Game over
  function gameOver() {
    // Create game over overlay
    const gameOverOverlay = document.createElement("div");
    gameOverOverlay.classList.add("game-over");
    gameOverOverlay.style.cssText = `
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.8);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 100;
  `;

    const gameOverText = document.createElement("div");
    gameOverText.textContent = "SIGNAL LOST";
    gameOverText.style.cssText = `
    font-size: 4rem;
    color: #ff0000;
    margin-bottom: 20px;
    animation: glitchText 2s infinite;
  `;

    const restartButton = document.createElement("button");
    restartButton.textContent = "RECONNECT";
    restartButton.style.cssText = `
    padding: 10px 20px;
    background-color: transparent;
    border: 2px solid #ff0000;
    color: #ffffff;
    font-family: 'VT323', monospace;
    font-size: 1.5rem;
    cursor: pointer;
  `;

    gameOverOverlay.appendChild(gameOverText);
    gameOverOverlay.appendChild(restartButton);
    dimensionContainer.appendChild(gameOverOverlay);

    // Add restart functionality
    restartButton.addEventListener("click", () => {
      location.reload();
    });
  }

  // Main game loop
  function gameLoop() {
    // Update entities
    updateEntities();

    // Request next frame
    requestAnimationFrame(gameLoop);
  }

  // Add keyboard controls for glitch attack
  document.addEventListener("keydown", (e) => {
    if (e.code === "Space") {
      useGlitchAttack();
    }
  });

  // Add double tap for mobile glitch attack
  let lastTap = 0;
  document.addEventListener("touchend", (e) => {
    const currentTime = new Date().getTime();
    const tapLength = currentTime - lastTap;

    if (tapLength < 300 && tapLength > 0) {
      useGlitchAttack();
      e.preventDefault();
    }

    lastTap = currentTime;
  });

  // Start the experience
  init();
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.