improve this geometry dash styled game

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Infinite Wave Game</title>
  <style>
    /* Reset and Body Styling */
    body {
      margin: 0;
      overflow: hidden;
      background-color: #1e1e1e;
      font-family: Arial, sans-serif;
    }

    /* Center the Canvas */
    canvas {
      display: block;
      margin: 0 auto;
      background-color: #111;
    }

    /* Score Display */
    #score {
      position: absolute;
      top: 20px;
      left: 50%;
      transform: translateX(-50%);
      color: #fff;
      font-size: 24px;
      z-index: 1;
      text-shadow: 2px 2px 4px #000;
    }

    /* Game Over Overlay */
    #gameOver {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.85);
      color: #fff;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      font-size: 32px;
      z-index: 2;
      visibility: hidden;
      opacity: 0;
      transition: opacity 0.5s;
    }

    #gameOver.visible {
      visibility: visible;
      opacity: 1;
    }

    #gameOver button {
      margin-top: 20px;
      padding: 10px 20px;
      font-size: 24px;
      cursor: pointer;
      background-color: #00ffea;
      border: none;
      border-radius: 5px;
      transition: background-color 0.3s;
    }

    #gameOver button:hover {
      background-color: #00c4b4;
    }

    /* Instruction Text */
    #instruction {
      position: absolute;
      bottom: 20px;
      left: 50%;
      transform: translateX(-50%);
      color: #fff;
      font-size: 18px;
      z-index: 1;
      text-shadow: 1px 1px 2px #000;
    }
  </style>
</head>
<body>
  <!-- Score Display -->
  <div id="score">Score: 0</div>

  <!-- Game Canvas -->
  <canvas id="gameCanvas" width="800" height="400"></canvas>

  <!-- Game Over Overlay -->
  <div id="gameOver">
    <div id="gameOverText">Game Over! Your score: 0</div>
    <button id="restartButton">Restart</button>
  </div>

  <!-- Instruction Text -->
  <div id="instruction">Hold Space or Click to Move Up</div>

  <!-- Game Script -->
  <script>
    // Canvas Setup
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const WIDTH = canvas.width;
    const HEIGHT = canvas.height;

    // DOM Elements
    const scoreDisplay = document.getElementById('score');
    const gameOverOverlay = document.getElementById('gameOver');
    const gameOverText = document.getElementById('gameOverText');
    const restartButton = document.getElementById('restartButton');

    // Game Variables
    let score = 0;
    let gameSpeed = 5;
    let obstacles = [];
    let keys = {};
    let animationId;
    let obstacleSpawnInterval;
    let lastTime = 0;
    let playerColor = '#00ffea';
    let inputHeld = false; // Flag to track user input

    // Player Object (Wave Shape)
    const player = {
      x: 100,
      y: HEIGHT / 2,
      width: 40,
      height: 40,
      dy: 0,
      gravity: 0.6,
      lift: -12, // Upward force when input is held
      maxY: HEIGHT - 40, // Prevent player from going below the canvas
      color: playerColor,

      update: function() {
        if (inputHeld) {
          this.dy = this.lift;
        } else {
          this.dy += this.gravity;
        }

        this.y += this.dy;

        // Boundary Detection
        if (this.y + this.height > HEIGHT) {
          this.y = HEIGHT - this.height;
          this.dy = 0;
          endGame();
        }

        if (this.y < 0) {
          this.y = 0;
          this.dy = 0;
        }

        this.draw();
      },

      draw: function() {
        ctx.fillStyle = this.color;
        ctx.beginPath();
        // Create a wave-like shape using arcs and curves
        ctx.moveTo(this.x, this.y + this.height / 2);
        ctx.quadraticCurveTo(
          this.x + this.width / 2, this.y - this.height / 2,
          this.x + this.width, this.y + this.height / 2
        );
        ctx.quadraticCurveTo(
          this.x + this.width / 2, this.y + this.height * 1.5,
          this.x, this.y + this.height / 2
        );
        ctx.closePath();
        ctx.fill();
      }
    };

    // Obstacle Class
    class Obstacle {
      constructor() {
        this.width = 30 + Math.random() * 20;
        this.height = 30 + Math.random() * 100;
        this.x = WIDTH;
        this.y = HEIGHT - this.height;
        this.color = '#ff005e';
        this.speed = gameSpeed;
      }

      update() {
        this.x -= this.speed;
        this.draw();
      }

      draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
      }
    }

    // Handle Key Presses
    document.addEventListener('keydown', function(e) {
      if (e.code === 'Space' || e.code === 'ArrowUp') {
        keys[e.code] = true;
        inputHeld = true;
      }
    });

    document.addEventListener('keyup', function(e) {
      if (e.code === 'Space' || e.code === 'ArrowUp') {
        keys[e.code] = false;
        inputHeld = false;
      }
    });

    // Handle Mouse Clicks or Touches
    document.addEventListener('mousedown', function() {
      inputHeld = true;
    });

    document.addEventListener('mouseup', function() {
      inputHeld = false;
    });

    // For touch devices
    document.addEventListener('touchstart', function(e) {
      e.preventDefault(); // Prevents mouse events from also firing
      inputHeld = true;
    }, { passive: false });

    document.addEventListener('touchend', function(e) {
      e.preventDefault();
      inputHeld = false;
    }, { passive: false });

    // Spawn Obstacles at Random Intervals
    function spawnObstacle() {
      obstacles.push(new Obstacle());
      // Spawn next obstacle between 1 to 1.5 seconds
      const time = 1000 + Math.random() * 500;
      obstacleSpawnInterval = setTimeout(spawnObstacle, time);
    }

    // Collision Detection using Axis-Aligned Bounding Box (AABB)
    function collisionDetection() {
      for (let obs of obstacles) {
        if (
          player.x < obs.x + obs.width &&
          player.x + player.width > obs.x &&
          player.y < obs.y + obs.height &&
          player.y + player.height > obs.y
        ) {
          endGame();
        }
      }
    }

    // Update Score
    function updateScore(deltaTime) {
      score += deltaTime * 0.01; // Increment score based on time
      scoreDisplay.innerText = `Score: ${Math.floor(score)}`;
    }

    // End Game Function
    function endGame() {
      cancelAnimationFrame(animationId);
      clearTimeout(obstacleSpawnInterval);
      gameOverText.innerText = `Game Over! Your score: ${Math.floor(score)}`;
      gameOverOverlay.classList.add('visible');
    }

    // Restart Game Function
    function restartGame() {
      // Reset Variables
      score = 0;
      gameSpeed = 5;
      obstacles = [];
      player.y = HEIGHT / 2;
      player.dy = 0;
      inputHeld = false;
      scoreDisplay.innerText = `Score: ${score}`;
      gameOverOverlay.classList.remove('visible');

      // Restart Obstacle Spawning and Game Loop
      spawnObstacle();
      lastTime = performance.now();
      gameLoop(lastTime);
    }

    // Main Game Loop
    function gameLoop(timestamp) {
      const deltaTime = timestamp - lastTime;
      lastTime = timestamp;

      ctx.clearRect(0, 0, WIDTH, HEIGHT);

      // Update and Draw Player
      player.update();

      // Update and Draw Obstacles
      for (let i = obstacles.length - 1; i >= 0; i--) {
        obstacles[i].update();

        // Remove off-screen obstacles
        if (obstacles[i].x + obstacles[i].width < 0) {
          obstacles.splice(i, 1);
          score += 10; // Bonus for passing an obstacle
        }
      }

      // Collision Detection
      collisionDetection();

      // Update Score
      updateScore(deltaTime);

      // Gradually Increase Game Speed
      gameSpeed += 0.0005; // Adjust this value for difficulty ramp
      for (let obs of obstacles) {
        obs.speed = gameSpeed;
      }

      animationId = requestAnimationFrame(gameLoop);
    }

    // Start the Game
    spawnObstacle();
    lastTime = performance.now();
    gameLoop(lastTime);

    // Restart Button Event Listener
    restartButton.addEventListener('click', restartGame);
  </script>
</body>
</html>