<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Aim Trainer</title>
  <link rel="stylesheet" href="styles.css">
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Righteous:wght@400;700&display=swap">
</head>

<body>
  <div class="screen">
    <h1>Your Free Aim Trainer!</h1>
    <p class="sub-title">Aim Better, Play Better</p>
    <button class="btn" id="start">Start Training</button>
    <div class="fullscreen-options">
      <button class="btn" id="fullscreen">FULL SCREEN</button>
      <button class="btn" id="minimize">MINIMIZE</button>
    </div>
  </div>
  <div class="screen">
    <h1>CHOOSE TIME</h1>
    <ul class="list" id="time-list">
      <li><button class="btn time-btn" data-time="10">10 SEC</button></li>
      <li><button class="btn time-btn" data-time="30">30 SEC</button></li>
      <li><button class="btn time-btn" data-time="60">1 MIN</button></li>
      <li><button class="btn time-btn" data-time="120">2 MIN</button></li>
      <li><button class="btn time-btn" data-unlimited="true">UNLIMITED</button></li>
    </ul>
  </div>
  <div class="screen">
    <h1>CHOOSE DIFFICULTY</h1>
    <ul class="list" id="difficulty-list">
      <li><button class="btn difficulty-btn" data-difficulty="0">EASY</button></li>
      <li><button class="btn difficulty-btn" data-difficulty="1">MEDIUM</button></li>
      <li><button class="btn difficulty-btn" data-difficulty="2">HARD</button></li>
    </ul>
  </div>
  <div class="screen">
    <div class="info">
      <p>HITS: <span id="hits">0</span></p>
      <p>ACCURACY: <span id="accuracy">0%</span></p>
      <p>TIME: <span id="time">00:00</span></p>
    </div>
    <div class="lives"></div>
    <div class="board" id="board">
      <div id="countdown"></div> <!-- Add this line for the countdown -->
    </div>
    <div class="options">
      <button class="btn restart">RESTART</button>
    </div>
  </div>
  <div class="screen">
    <h1>GAME OVER</h1>
    <div class="results">
      <p>HITS: <span id="hits-over" style="color: #00ff00;">0</span></p>
      <p>ACCURACY: <span id="accuracy-over">0%</span></p>
    </div>
    <div class="centered">
      <button class="btn" id="refresh" onclick="refreshPage()">Restart Training</button>
    </div>
    <div class="Donate">
      <a class="btn no-underline" id="Donate" href="https://venmo.com/u/Tini2x" target="_blank">Donate</a>
    </div>
  </div>
  <script src="backend.js"></script>
  <script src="script.js"></script>
</body>

</html>
/* Common styles */
body {
  cursor: crosshair;
  height: 100vh;
  color: #ffffff;
  overflow: hidden;
  text-align: center;
  font-family: "Righteous", sans-serif;
  background-color: black;
}

h1 {
  font-size: 6vw; /* Relative to viewport width */
  line-height: 2.4;
  margin-bottom: 0;
  margin-top: 0;
}

.sub-title {
  margin-bottom: -1.25vw;
  font-size: 1.5vw; /* Relative to viewport width */
}

.btn {
  font-size: 2vw; /* Relative to viewport width */
  font-family: "Righteous", sans-serif;
  background-color: transparent;
  border: 0.2vw solid #00ff00; /* Relative border size */
  color: #ffffff;
  padding: 1.5vw 2.3vw; /* Relative padding */
  margin: 2vw;
  cursor: crosshair;
  border-radius: 2vw; /* Relative border radius */
  transition: all 0.3s;
}

.btn:hover {
  background-color: rgba(255, 255, 255, 0.075);
  box-shadow: 0 0 2vw #00ff00; /* Relative box-shadow size */
}

.screen {
  position: absolute;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background-color: black;
  transition: top 0.5s ease-out;
  z-index: 1;
}

.screen:not(.active) {
  top: 150vh;
}

.list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  list-style: none;
}

.list li {
  margin: 2vw;
}

.info {
  display: flex;
  justify-content: space-around;
  align-items: center;
  width: 85%;
  margin: 0 auto;
  padding: 1vw;
}

.info p,
.info span {
  font-family: "Righteous", sans-serif;
  font-size: 2vw; /* Relative to viewport width */
  color: #ffffff;
}

.lives {
  display: flex;
  gap: 2vw;
  align-items: center;
  margin-bottom: 1vw;
}

.board {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  height: 70vw;
  width: 70vw; /* Relative to viewport width */
  flex: 1;
  background-color: #0f0f0f;
  overflow: hidden;
  margin-top: -4vw;
  margin-bottom: -4vw;
}

.crosshair {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 4vw; /* Relative to viewport width */
  height: 4vw; /* Relative to viewport width */
  background-color: #00ff00;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 9999;
}

.options {
  width: 100%;
  display: flex;
  justify-content: space-between;
  padding: 3vw;
}

.fullscreen-options {
  position: absolute;
  bottom: 2vw;
  right: 2vw;
  display: flex;
  gap: 2vw;
}

#minimize {
  display: none;
}

#countdown {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 4vw; /* Relative to viewport width */
  color: white;
}

.Donate {
  position: absolute;
  bottom: 2vw;
  right: 2vw;
  display: flex;
  gap: 2vw;
}

.no-underline {
  text-decoration: none;
}

.circle {
  position: absolute;
  background-color: #00ff00;
  animation: circle 1.3s linear forwards;
  border-radius: 50%;
}

@keyframes circle {
  100% {
    transform: scale(0);
  }
}

.results {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 2vw;
  margin-bottom: 2vw;
}

.results p,
.results p span {
  font-size: 2vw; /* Relative to viewport width */
  color: #ffffff;
}
const startBtn = document.querySelector("#start");
const screens = document.querySelectorAll(".screen");
const timeList = document.querySelector("#time-list");
const difficultyList = document.querySelector("#difficulty-list");
const timeEl = document.querySelector("#time");
const board = document.querySelector("#board");
const hitsEl = document.querySelector("#hits");
const accuracyEl = document.querySelector("#accuracy");
const hitsOver = document.querySelector("#hits-over");
const accuracyOver = document.querySelector("#accuracy-over");
const hearts = document.querySelectorAll(".heart");
const restartBtns = document.querySelectorAll(".restart");
const fullscreenBtn = document.querySelector("#fullscreen");
const minimizeBtn = document.querySelector("#minimize");

let time = 0;
let unlimited = false;
let difficulty = 0;
let playing = false;
let hits = 0;
let missed = 0;
let lives = 3;
let interval;
let countdownInterval;
let activeIntervals = [];

// Only show the first screen initially
screens.forEach((screen, index) => {
  if (index === 0) {
    screen.classList.add("active");
  } else {
    screen.classList.remove("active");
  }
});

startBtn.addEventListener("click", () => {
  goToNextScreen(0);
});

// Add click event for time buttons
timeList.addEventListener("click", (e) => {
  if (e.target.classList.contains("time-btn")) {
    time = parseInt(e.target.getAttribute("data-time"));
    unlimited = e.target.getAttribute("data-unlimited") === "true";
    goToNextScreen(1);
  }
});

// Add click event for difficulty buttons
difficultyList.addEventListener("click", (e) => {
  if (e.target.classList.contains("difficulty-btn")) {
    difficulty = parseInt(e.target.getAttribute("data-difficulty"));
    startCountdownAndGame(); // Call the function to start the countdown immediately
  }
});

// Function to transition to the next screen
function goToNextScreen(currentScreenIndex) {
  screens[currentScreenIndex].classList.remove("active");
  if (screens[currentScreenIndex + 1]) {
    screens[currentScreenIndex + 1].classList.add("active");
  }
}

// Fullscreen functionality
fullscreenBtn.addEventListener("click", () => {
  if (!document.fullscreenElement) {
    document.documentElement.requestFullscreen();
    minimizeBtn.textContent = "MINIMIZE"; // Change button text to "MINIMIZE" when in fullscreen
  } else {
    if (document.exitFullscreen) {
      document.exitFullscreen();
      minimizeBtn.textContent = "FULL SCREEN"; // Change button text to "FULL SCREEN" when exiting fullscreen
    }
  }
});

document.addEventListener("fullscreenchange", () => {
  if (document.fullscreenElement) {
    fullscreenBtn.textContent = "MINIMIZE";
  } else {
    fullscreenBtn.textContent = "FULL SCREEN";
  }
});

function startCountdownAndGame() {
  goToNextScreen(2); // Go to the next screen (game screen)
  startCountdown();
}

function startCountdown() {
  let countdown = 3; // Set the initial countdown value
  const countdownElement = document.getElementById("countdown");
  countdownElement.style.display = "block"; // Show the countdown element
  countdownElement.innerHTML = countdown; // Initial display of countdown

  countdownInterval = setInterval(() => {
    countdown--;
    countdownElement.innerHTML = countdown; // Update countdown element

    if (countdown === 0) {
      clearInterval(countdownInterval);
      countdownElement.style.display = "none"; // Hide the countdown element
      startGame(); // Start the game after countdown ends
    }
  }, 1000);
}

function startGame() {
  playing = true;
  hits = 0;
  missed = 0;
  lives = 3;
  resetStats();
  interval = setInterval(decreaseTime, 1000);
  createRandomCircle();
}

function decreaseTime() {
  if (!unlimited && time === 0) {
    finishGame();
    return;
  }

  if (!unlimited) {
    time--;
  }

  const minutes = Math.floor(time / 60);
  const seconds = time % 60;
  const formattedTime = `${minutes
    .toString()
    .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
  setTime(formattedTime);

  if (time <= 5) {
    timeEl.style.color = "#FF000D";
  } else {
    timeEl.style.color = "#00FF00";
  }
}

function setTime(time) {
  timeEl.innerHTML = time;
}

function createRandomCircle() {
  if (!playing) return;

  const existingCircle = document.querySelector(".circle");
  if (existingCircle) {
    existingCircle.remove();
    clearInterval(existingCircle.shrinkInterval);
  }

  const circle = document.createElement("div");
  const size = getRandomNumber(50, 80);
  const colors = [
    "#FFFF00",
    "#FFFF33",
    "#F2EA02",
    "#E6FB04",
    "#FF0000",
    "#FD1C03",
    "#FF3300",
    "#FF6600",
    "#00FF00",
    "#00FF33",
    "#00FF66",
    "#33FF00",
    "#00FFFF",
    "#099FFF",
    "#0062FF",
    "#0033FF",
    "#FF00FF",
    "#FF00CC",
    "#FF0099",
    "#CC00FF",
    "#9D00FF",
    "#6E0DD0",
    "#9900FF"
  ];
  const { width, height } = board.getBoundingClientRect();
  const x = getRandomNumber(0, width - size);
  const y = getRandomNumber(0, height - size);

  circle.classList.add("circle");
  circle.style.width = `${size}px`;
  circle.style.height = `${size}px`;
  circle.style.top = `${y}px`;
  circle.style.left = `${x}px`;
  circle.style.backgroundColor =
    colors[Math.floor(Math.random() * colors.length)];
  board.appendChild(circle);

  circle.addEventListener("click", (e) => {
    hits++;
    e.target.remove();
    clearInterval(circle.shrinkInterval);
    calculateAccuracy();
    updateStats();
    createRandomCircle();
  });

  let shrinkTime;
  if (difficulty === 0) shrinkTime = 95;
  else if (difficulty === 1) shrinkTime = 80;
  else shrinkTime = 60;

  circle.shrinkInterval = setInterval(() => {
    const opacity = parseFloat(
      window.getComputedStyle(circle).getPropertyValue("opacity")
    );
    if (opacity <= 0) {
      clearInterval(circle.shrinkInterval);
      circle.remove();
      if (playing) {
        missed++;
        calculateAccuracy();
        updateStats();
        createRandomCircle();
      }
    } else {
      circle.style.opacity = Math.max(opacity - 0.07, 0);
      const newSize = Math.max(parseInt(circle.style.width) - 1, 0);
      circle.style.width = `${newSize}px`;
      circle.style.height = `${newSize}px`;
    }
  }, shrinkTime);
  activeIntervals.push(circle.shrinkInterval);
}

board.addEventListener("click", (e) => {
  if (!e.target.classList.contains("circle") && playing) {
    missed++;
    calculateAccuracy();
    updateStats();
  }
});

function calculateAccuracy() {
  const total = hits + missed;
  const accuracy = total === 0 ? 100 : (hits / total) * 100;
  accuracyEl.innerHTML = `${accuracy.toFixed(2)}%`;
  updateAccuracyColor(accuracyEl, accuracy);
}

function updateAccuracyColor(element, accuracy) {
  if (accuracy < 65) element.style.color = "#FF000D";
  else if (accuracy < 80) element.style.color = "#FF5B00";
  else element.style.color = "#00FF00";
}

function updateStats() {
  hitsEl.innerHTML = hits;
  const accuracy = parseFloat(accuracyEl.innerHTML);
  updateAccuracyColor(accuracyOver, accuracy);
}

function resetStats() {
  setTime("00:00");
  hitsEl.innerHTML = "0";
  accuracyEl.innerHTML = "100%";
  accuracyOver.innerHTML = "100%";
  hitsEl.style.color = "#00FF00";
  accuracyEl.style.color = "#00FF00";
  accuracyOver.style.color = "#00FF00";
}

function finishGame() {
  playing = false;
  clearInterval(interval);
  board.innerHTML = "";
  goToNextScreen(screens.length - 2);
  hitsOver.innerHTML = hits;
  accuracyOver.innerHTML = accuracyEl.innerHTML;
}

function resetcountdown() {
  clearInterval(countdownInterval); // Stop the countdown interval
  time = initialTime; // Reset the time variable to its initial value
  startCountdown(); // Start the countdown again
}

function resetBoard() {
  board.innerHTML = "";
}

restartBtns.forEach((btn) => {
  btn.addEventListener("click", () => {
    // Corrected 'restartbtn' to 'btn'
    screens.forEach((screen, index) => {
      if (index === 0) {
        screen.classList.add("active");
      } else {
        screen.classList.remove("active");
      }
    });
    clearInterval(interval);
    clearInterval(countdownInterval);
    activeIntervals.forEach(clearInterval);
    activeIntervals = [];
    time = 0;
    hits = 0;
    missed = 0;
    lives = 3;
    resetStats();
    resetcountdown();
    resetBoard();
    playing = false;
  });
});

function getRandomNumber(min, max) {
  return Math.floor(Math.random() * (max - min + 1) + min);
}

function refreshPage() {
  location.reload();
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.