<!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();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.