Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions public/Reflex_tester/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# ⏱️ Reflex Tester - Reaction Time Game

A simple, fun, and addictive reflex testing game built with HTML, CSS, and JavaScript. Test your reaction speed and challenge your friends!

---

## 🚀 Features

- 🎯 **Random green screen trigger** (2–5 seconds)
- 🖱️ **React to color change** via tap or mouse click
- ⏱️ **Real-time display** of reaction time (ms)
- 📊 **Track:**
- Average reaction time (last 5 tries)
- Best (fastest) reaction time
- 💾 **Stores scores** in localStorage
- 📱 **Mobile-friendly** layout and interactions
- 🚫 **False start detection** (clicked too early)

---

## 🛠️ Tech Stack

- **HTML5**
- **CSS3** (with transitions & neon theme)
- **JavaScript** (DOM manipulation + Date.now() timing)

---

## 🎮 How to Play

1. Click/tap the **Start Test** button.
2. Wait for the screen to turn **green**.
3. Tap/click as quickly as you can!
4. Your reaction time will be displayed.
5. Try to beat your best score and track your average!

---

## 📊 Stats Tracked
- **Last reaction time**
- **Average (last 5)**
- **Best (fastest)**
- All stats are saved in your browser (localStorage)

---

## 📱 Mobile Friendly
- Fully responsive design
- Touch and click support

---

## 🧠 Possible Enhancements
- 🎵 Sound effects
- 📈 Graph last 10 reaction times
- 🌐 Share best time via link
- 🔄 Dark mode toggle
- 👥 Multiplayer mode

---

## 📂 Project Structure

```
/reflex-tester/
├── index.html
├── style.css
├── script.js
└── README.md
```

---

## © 2024 Reflex Tester
38 changes: 38 additions & 0 deletions public/Reflex_tester/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>⏱️ Reflex Tester - Reaction Time Game</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<header>
<h1>⏱️ Reflex Tester</h1>
<p class="subtitle">How fast are your reflexes?</p>
</header>
<main>
<div id="game-area" class="game-area">
<div id="message" class="message">Tap "Start Test" to begin!</div>
<button id="start-btn" class="start-btn">Start Test</button>
</div>
<div class="stats">
<div class="stat">
<span>Last:</span> <span id="last-time">–</span> ms
</div>
<div class="stat">
<span>Average (5):</span> <span id="avg-time">–</span> ms
</div>
<div class="stat">
<span>Best:</span> <span id="best-time">–</span> ms
</div>
</div>
</main>
<footer>
<p>🎯 Reflex Tester &copy; 2024</p>
</footer>
</div>
<script src="script.js"></script>
</body>
</html>
110 changes: 110 additions & 0 deletions public/Reflex_tester/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
const gameArea = document.getElementById('game-area');
const message = document.getElementById('message');
const startBtn = document.getElementById('start-btn');
const lastTimeEl = document.getElementById('last-time');
avgTimeEl = document.getElementById('avg-time');
bestTimeEl = document.getElementById('best-time');

let waiting = false;
let green = false;
let startTime = 0;
let timeoutId = null;
let reactionTimes = [];
let bestTime = null;

// Load from localStorage
function loadStats() {
const stored = JSON.parse(localStorage.getItem('reflex_stats') || '{}');
reactionTimes = stored.reactionTimes || [];
bestTime = stored.bestTime || null;
updateStats();
}

function saveStats() {
localStorage.setItem('reflex_stats', JSON.stringify({
reactionTimes,
bestTime
}));
}

function updateStats() {
if (reactionTimes.length > 0) {
lastTimeEl.textContent = reactionTimes[reactionTimes.length - 1];
const avg = Math.round(reactionTimes.slice(-5).reduce((a, b) => a + b, 0) / Math.min(5, reactionTimes.length));
avgTimeEl.textContent = avg;
} else {
lastTimeEl.textContent = '–';
avgTimeEl.textContent = '–';
}
bestTimeEl.textContent = bestTime !== null ? bestTime : '–';
}

function setGameAreaState(state) {
gameArea.classList.remove('active', 'false-start');
if (state === 'green') gameArea.classList.add('active');
if (state === 'false') gameArea.classList.add('false-start');
}

function startTest() {
waiting = true;
green = false;
setGameAreaState();
message.textContent = 'Wait for Green…';
startBtn.style.display = 'none';
// Random delay 2-5s
const delay = 2000 + Math.random() * 3000;
timeoutId = setTimeout(() => {
green = true;
waiting = false;
setGameAreaState('green');
message.textContent = 'GO! Tap now!';
startTime = Date.now();
}, delay);
}

function handleUserReact(e) {
// Ignore clicks/taps on the start/try again button
if (e && e.target === startBtn) return;
if (waiting && !green) {
// False start
clearTimeout(timeoutId);
setGameAreaState('false');
message.textContent = '⛔ Too Soon! Wait for green.';
startBtn.style.display = 'block';
startBtn.textContent = 'Try Again';
waiting = false;
green = false;
return;
}
if (green) {
const reaction = Date.now() - startTime;
reactionTimes.push(reaction);
if (reactionTimes.length > 20) reactionTimes = reactionTimes.slice(-20);
if (bestTime === null || reaction < bestTime) bestTime = reaction;
updateStats();
saveStats();
setGameAreaState();
message.textContent = `⏱️ ${reaction} ms!`;
startBtn.style.display = 'block';
startBtn.textContent = 'Go Again';
green = false;
waiting = false;
}
}

startBtn.addEventListener('click', startTest);
gameArea.addEventListener('click', handleUserReact);
gameArea.addEventListener('touchstart', function(e) {
// Prevent 300ms delay on mobile
e.preventDefault();
handleUserReact(e);
}, {passive: false});

// Prevent scrolling on mobile during game
window.addEventListener('touchmove', function(e) {
if (waiting || green) e.preventDefault();
}, {passive: false});

// On load
loadStats();
updateStats();
153 changes: 153 additions & 0 deletions public/Reflex_tester/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Roboto:wght@400;700&display=swap');

:root {
--bg-dark: #181c24;
--bg-light: #232a36;
--accent: #00ff99;
--accent2: #00cfff;
--danger: #ff3b3b;
--text-main: #f4f4f4;
--text-muted: #b0b8c1;
--shadow: 0 4px 32px 0 rgba(0,255,153,0.15);
}

html, body {
height: 100%;
margin: 0;
padding: 0;
font-family: 'Roboto', Arial, sans-serif;
background: linear-gradient(135deg, var(--bg-dark) 0%, var(--bg-light) 100%);
color: var(--text-main);
min-height: 100vh;
}

.container {
max-width: 420px;
margin: 2rem auto;
background: rgba(35, 42, 54, 0.98);
border-radius: 1.5rem;
box-shadow: var(--shadow);
padding: 2rem 1.5rem 1.5rem 1.5rem;
display: flex;
flex-direction: column;
align-items: center;
}

header {
text-align: center;
margin-bottom: 1.5rem;
}

h1 {
font-family: 'Orbitron', monospace;
font-size: 2.2rem;
letter-spacing: 2px;
color: var(--accent);
margin: 0 0 0.2em 0;
text-shadow: 0 0 8px var(--accent2);
}

.subtitle {
color: var(--text-muted);
font-size: 1.1rem;
margin-bottom: 0.5em;
}

.game-area {
width: 100%;
height: 220px;
background: var(--bg-light);
border-radius: 1.2rem;
box-shadow: 0 2px 16px 0 rgba(0,255,153,0.08);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 1.2rem;
transition: background 0.3s cubic-bezier(.4,2,.6,1);
cursor: pointer;
position: relative;
}

.game-area.active {
background: var(--accent);
box-shadow: 0 0 32px 0 var(--accent2);
}

.game-area.false-start {
background: var(--danger);
box-shadow: 0 0 32px 0 var(--danger);
}

.message {
font-size: 1.3rem;
font-weight: 700;
text-align: center;
color: var(--text-main);
margin-bottom: 1.2rem;
text-shadow: 0 0 6px var(--accent2);
}

.start-btn {
background: linear-gradient(90deg, var(--accent2), var(--accent));
color: #181c24;
font-family: 'Orbitron', monospace;
font-size: 1.1rem;
font-weight: 700;
border: none;
border-radius: 2rem;
padding: 0.8em 2.2em;
box-shadow: 0 2px 12px 0 var(--accent2);
cursor: pointer;
transition: background 0.2s, transform 0.1s;
outline: none;
}

.start-btn:active {
background: linear-gradient(90deg, var(--accent), var(--accent2));
transform: scale(0.97);
}

.stats {
display: flex;
justify-content: space-between;
width: 100%;
margin: 1.2rem 0 0.5rem 0;
gap: 0.5rem;
}

.stat {
background: #232a36;
border-radius: 1rem;
padding: 0.7em 1.1em;
font-size: 1.05rem;
color: var(--text-main);
box-shadow: 0 1px 6px 0 rgba(0,255,153,0.07);
text-align: center;
flex: 1 1 0;
}

footer {
margin-top: 1.5rem;
text-align: center;
color: var(--text-muted);
font-size: 0.95rem;
}

@media (max-width: 600px) {
.container {
padding: 1.2rem 0.5rem 1rem 0.5rem;
max-width: 98vw;
}
.game-area {
height: 160px;
}
.stats {
flex-direction: column;
gap: 0.6rem;
}
.stat {
font-size: 1rem;
padding: 0.6em 0.7em;
}
}