key / index.html
Ketamin's picture
Add 2 files
d588d2d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SpeedType - Keyboard Typing Trainer</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.key {
transition: all 0.1s ease;
position: relative;
}
.key.active {
transform: translateY(2px);
background-color: #3b82f6;
color: white;
}
.key.wrong {
background-color: #ef4444;
color: white;
}
.key.correct {
background-color: #10b981;
color: white;
}
.cursor {
position: absolute;
width: 2px;
height: 24px;
background-color: #3b82f6;
animation: blink 1s infinite;
}
@keyframes blink {
0%, 100% { opacity: 1; }
50% { opacity: 0; }
}
.text-display {
font-family: 'Courier New', monospace;
}
.character.correct {
color: #10b981;
}
.character.wrong {
color: #ef4444;
text-decoration: underline;
}
.character.current {
background-color: #e0f2fe;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8 max-w-6xl">
<header class="text-center mb-8">
<h1 class="text-4xl font-bold text-blue-600 mb-2">SpeedType</h1>
<p class="text-gray-600">Improve your typing speed and accuracy</p>
</header>
<div class="bg-white rounded-xl shadow-lg p-6 mb-8">
<div class="flex justify-between items-center mb-6">
<div class="flex space-x-4">
<div class="bg-blue-100 text-blue-800 px-4 py-2 rounded-lg">
<span class="text-sm font-medium">Time:</span>
<span id="timer" class="text-xl font-bold ml-1">60</span>s
</div>
<div class="bg-green-100 text-green-800 px-4 py-2 rounded-lg">
<span class="text-sm font-medium">WPM:</span>
<span id="wpm" class="text-xl font-bold ml-1">0</span>
</div>
<div class="bg-purple-100 text-purple-800 px-4 py-2 rounded-lg">
<span class="text-sm font-medium">Accuracy:</span>
<span id="accuracy" class="text-xl font-bold ml-1">100</span>%
</div>
</div>
<div>
<button id="new-text-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg transition">
<i class="fas fa-sync-alt mr-2"></i>New Text
</button>
</div>
</div>
<div class="mb-8">
<div class="flex justify-between text-sm text-gray-500 mb-2">
<span>Difficulty:</span>
<div class="flex space-x-2">
<button class="difficulty-btn px-3 py-1 rounded-full bg-blue-100 text-blue-800" data-level="easy">Easy</button>
<button class="difficulty-btn px-3 py-1 rounded-full" data-level="medium">Medium</button>
<button class="difficulty-btn px-3 py-1 rounded-full" data-level="hard">Hard</button>
</div>
</div>
<div class="flex justify-between text-sm text-gray-500 mb-2">
<span>Time:</span>
<div class="flex space-x-2">
<button class="time-btn px-3 py-1 rounded-full bg-blue-100 text-blue-800" data-time="30">30s</button>
<button class="time-btn px-3 py-1 rounded-full" data-time="60">60s</button>
<button class="time-btn px-3 py-1 rounded-full" data-time="120">120s</button>
</div>
</div>
</div>
<div id="text-display" class="text-display bg-gray-100 p-6 rounded-lg text-lg leading-relaxed mb-8 relative">
<!-- Text will be inserted here -->
</div>
<div class="mb-8">
<textarea id="input-field" class="w-full p-4 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" rows="4" placeholder="Start typing here..."></textarea>
</div>
<div class="flex justify-center mb-8">
<button id="start-btn" class="bg-green-600 hover:bg-green-700 text-white px-8 py-3 rounded-lg text-lg font-medium transition">
<i class="fas fa-play mr-2"></i>Start Typing
</button>
</div>
<div class="grid grid-cols-12 gap-2 mb-8">
<!-- First row -->
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">`</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">1</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">2</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">3</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">4</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">5</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">6</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">7</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">8</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">9</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">0</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">-</div>
<!-- Second row -->
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Tab</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Q</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">W</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">E</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">R</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">T</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Y</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">U</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">I</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">O</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">P</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">[</div>
<!-- Third row -->
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Caps</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">A</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">S</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">D</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">F</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">G</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">H</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">J</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">K</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">L</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">;</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">'</div>
<!-- Fourth row -->
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Shift</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Z</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">X</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">C</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">V</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">B</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">N</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">M</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">,</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">.</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">/</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Shift</div>
<!-- Fifth row -->
<div class="key col-span-2 bg-gray-200 p-3 rounded text-center font-medium">Ctrl</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Win</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Alt</div>
<div class="key col-span-4 bg-gray-200 p-3 rounded text-center font-medium">Space</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Alt</div>
<div class="key col-span-1 bg-gray-200 p-3 rounded text-center font-medium">Win</div>
<div class="key col-span-2 bg-gray-200 p-3 rounded text-center font-medium">Ctrl</div>
</div>
</div>
<div class="bg-white rounded-xl shadow-lg p-6">
<h2 class="text-xl font-bold text-gray-800 mb-4">Your Progress</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="bg-blue-50 p-4 rounded-lg">
<div class="flex items-center">
<div class="bg-blue-100 p-3 rounded-full mr-3">
<i class="fas fa-tachometer-alt text-blue-600"></i>
</div>
<div>
<p class="text-sm text-gray-500">Average WPM</p>
<p class="text-2xl font-bold">42</p>
</div>
</div>
</div>
<div class="bg-green-50 p-4 rounded-lg">
<div class="flex items-center">
<div class="bg-green-100 p-3 rounded-full mr-3">
<i class="fas fa-bullseye text-green-600"></i>
</div>
<div>
<p class="text-sm text-gray-500">Best Accuracy</p>
<p class="text-2xl font-bold">98%</p>
</div>
</div>
</div>
<div class="bg-purple-50 p-4 rounded-lg">
<div class="flex items-center">
<div class="bg-purple-100 p-3 rounded-full mr-3">
<i class="fas fa-clock text-purple-600"></i>
</div>
<div>
<p class="text-sm text-gray-500">Time Practiced</p>
<p class="text-2xl font-bold">2h 15m</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Sample texts for different difficulty levels
const texts = {
easy: [
"The quick brown fox jumps over the lazy dog. This sentence contains all the letters in the English alphabet.",
"Learning to type quickly and accurately is an essential skill in today's digital world. Practice makes perfect.",
"Typing is the process of writing or inputting text by pressing keys on a typewriter, computer keyboard, or touchscreen."
],
medium: [
"The ability to type without looking at the keyboard is called touch typing. This skill can significantly improve your productivity.",
"According to research, the average typing speed is around 40 words per minute. Professional typists can reach speeds of 65 to 75 WPM.",
"The QWERTY keyboard layout was designed in the 1870s for mechanical typewriters. Despite newer layouts, it remains the most popular."
],
hard: [
"The Dvorak Simplified Keyboard is an alternative keyboard layout patented in 1936 by August Dvorak. Studies have shown mixed results regarding its superiority over QWERTY.",
"Stenotype machines allow trained users to type at speeds exceeding 300 words per minute by pressing multiple keys simultaneously to represent syllables or words.",
"The world record for typing speed on a QWERTY keyboard is 216 words per minute, achieved by Barbara Blackburn in 2005 using the Dvorak Simplified Keyboard layout."
]
};
// DOM elements
const textDisplay = document.getElementById('text-display');
const inputField = document.getElementById('input-field');
const startBtn = document.getElementById('start-btn');
const newTextBtn = document.getElementById('new-text-btn');
const timerElement = document.getElementById('timer');
const wpmElement = document.getElementById('wpm');
const accuracyElement = document.getElementById('accuracy');
const difficultyBtns = document.querySelectorAll('.difficulty-btn');
const timeBtns = document.querySelectorAll('.time-btn');
const keys = document.querySelectorAll('.key');
// Game state
let currentText = '';
let currentIndex = 0;
let timer;
let timeLeft = 60;
let isPlaying = false;
let correctChars = 0;
let totalChars = 0;
let startTime;
let currentDifficulty = 'easy';
let currentTimeSetting = 60;
// Initialize the game
function initGame() {
// Set initial difficulty and time
setDifficulty('easy');
setTime(60);
// Load initial text
loadNewText();
// Set up event listeners
setupEventListeners();
}
// Set up event listeners
function setupEventListeners() {
// Start button
startBtn.addEventListener('click', () => {
if (!isPlaying) {
startGame();
}
});
// New text button
newTextBtn.addEventListener('click', () => {
loadNewText();
if (isPlaying) {
resetGame();
startGame();
} else {
resetGame();
}
});
// Input field
inputField.addEventListener('input', handleInput);
inputField.addEventListener('keydown', handleKeyDown);
// Difficulty buttons
difficultyBtns.forEach(btn => {
btn.addEventListener('click', () => {
setDifficulty(btn.dataset.level);
loadNewText();
if (isPlaying) {
resetGame();
startGame();
}
});
});
// Time buttons
timeBtns.forEach(btn => {
btn.addEventListener('click', () => {
setTime(parseInt(btn.dataset.time));
if (isPlaying) {
resetGame();
startGame();
}
});
});
// Keyboard visualization
document.addEventListener('keydown', (e) => {
const key = e.key.toLowerCase();
keys.forEach(k => {
const keyText = k.textContent.toLowerCase();
if (keyText === key ||
(key === ' ' && keyText === 'space') ||
(key === 'tab' && keyText === 'tab') ||
(key === 'capslock' && keyText === 'caps') ||
(key === 'shift' && keyText === 'shift') ||
(key === 'control' && keyText === 'ctrl') ||
(key === 'alt' && keyText === 'alt') ||
(key === 'meta' && keyText === 'win')) {
k.classList.add('active');
}
});
});
document.addEventListener('keyup', (e) => {
const key = e.key.toLowerCase();
keys.forEach(k => {
const keyText = k.textContent.toLowerCase();
if (keyText === key ||
(key === ' ' && keyText === 'space') ||
(key === 'tab' && keyText === 'tab') ||
(key === 'capslock' && keyText === 'caps') ||
(key === 'shift' && keyText === 'shift') ||
(key === 'control' && keyText === 'ctrl') ||
(key === 'alt' && keyText === 'alt') ||
(key === 'meta' && keyText === 'win')) {
k.classList.remove('active');
}
});
});
}
// Set difficulty level
function setDifficulty(level) {
currentDifficulty = level;
// Update UI
difficultyBtns.forEach(btn => {
if (btn.dataset.level === level) {
btn.classList.add('bg-blue-100', 'text-blue-800');
} else {
btn.classList.remove('bg-blue-100', 'text-blue-800');
}
});
}
// Set time setting
function setTime(time) {
currentTimeSetting = time;
timeLeft = time;
timerElement.textContent = time;
// Update UI
timeBtns.forEach(btn => {
if (parseInt(btn.dataset.time) === time) {
btn.classList.add('bg-blue-100', 'text-blue-800');
} else {
btn.classList.remove('bg-blue-100', 'text-blue-800');
}
});
}
// Load new text based on difficulty
function loadNewText() {
const textArray = texts[currentDifficulty];
currentText = textArray[Math.floor(Math.random() * textArray.length)];
renderText();
}
// Render the text to type
function renderText() {
textDisplay.innerHTML = '';
for (let i = 0; i < currentText.length; i++) {
const span = document.createElement('span');
span.className = 'character';
span.textContent = currentText[i];
span.id = `char-${i}`;
textDisplay.appendChild(span);
}
// Add cursor to first character
const cursor = document.createElement('div');
cursor.className = 'cursor';
cursor.id = 'cursor';
document.getElementById('char-0').appendChild(cursor);
}
// Start the game
function startGame() {
if (isPlaying) return;
isPlaying = true;
currentIndex = 0;
correctChars = 0;
totalChars = 0;
startTime = new Date().getTime();
// Update UI
startBtn.innerHTML = '<i class="fas fa-stop mr-2"></i>Stop';
startBtn.classList.remove('bg-green-600', 'hover:bg-green-700');
startBtn.classList.add('bg-red-600', 'hover:bg-red-700');
inputField.disabled = false;
inputField.value = '';
inputField.focus();
// Start timer
timer = setInterval(updateTimer, 1000);
// Highlight first character
updateCurrentCharacter();
}
// Update timer
function updateTimer() {
timeLeft--;
timerElement.textContent = timeLeft;
if (timeLeft <= 0) {
endGame();
}
}
// Handle input
function handleInput(e) {
const inputText = e.target.value;
const currentChar = currentText[currentIndex];
// Check if input matches current character
if (inputText[inputText.length - 1] === currentChar) {
// Correct character
document.getElementById(`char-${currentIndex}`).classList.add('correct');
document.getElementById(`char-${currentIndex}`).classList.remove('wrong', 'current');
correctChars++;
} else {
// Wrong character
document.getElementById(`char-${currentIndex}`).classList.add('wrong');
document.getElementById(`char-${currentIndex}`).classList.remove('correct', 'current');
}
totalChars++;
currentIndex++;
// Clear input
e.target.value = '';
// Update stats
updateStats();
// Move to next character or end game if finished
if (currentIndex >= currentText.length) {
loadNewText();
currentIndex = 0;
}
updateCurrentCharacter();
}
// Handle key down (for backspace)
function handleKeyDown(e) {
if (e.key === 'Backspace' && currentIndex > 0) {
currentIndex--;
document.getElementById(`char-${currentIndex}`).classList.remove('correct', 'wrong');
updateCurrentCharacter();
}
}
// Update current character highlight
function updateCurrentCharacter() {
// Remove current class from all characters
document.querySelectorAll('.character').forEach(char => {
char.classList.remove('current');
});
// Add current class to current character
if (currentIndex < currentText.length) {
document.getElementById(`char-${currentIndex}`).classList.add('current');
// Move cursor
const cursor = document.getElementById('cursor');
if (cursor) cursor.remove();
const newCursor = document.createElement('div');
newCursor.className = 'cursor';
newCursor.id = 'cursor';
document.getElementById(`char-${currentIndex}`).appendChild(newCursor);
}
}
// Update stats (WPM and accuracy)
function updateStats() {
// Calculate WPM (5 characters = 1 word)
const timeElapsed = (new Date().getTime() - startTime) / 60000; // in minutes
const wordsTyped = correctChars / 5;
const wpm = Math.round(wordsTyped / timeElapsed) || 0;
wpmElement.textContent = wpm;
// Calculate accuracy
const accuracy = totalChars > 0 ? Math.round((correctChars / totalChars) * 100) : 100;
accuracyElement.textContent = accuracy;
}
// End the game
function endGame() {
isPlaying = false;
clearInterval(timer);
// Update UI
startBtn.innerHTML = '<i class="fas fa-play mr-2"></i>Start Typing';
startBtn.classList.remove('bg-red-600', 'hover:bg-red-700');
startBtn.classList.add('bg-green-600', 'hover:bg-green-700');
inputField.disabled = true;
// Show results
alert(`Game over!\nYour typing speed: ${wpmElement.textContent} WPM\nAccuracy: ${accuracyElement.textContent}%`);
}
// Reset the game
function resetGame() {
isPlaying = false;
clearInterval(timer);
timeLeft = currentTimeSetting;
timerElement.textContent = timeLeft;
wpmElement.textContent = '0';
accuracyElement.textContent = '100';
currentIndex = 0;
correctChars = 0;
totalChars = 0;
// Update UI
startBtn.innerHTML = '<i class="fas fa-play mr-2"></i>Start Typing';
startBtn.classList.remove('bg-red-600', 'hover:bg-red-700');
startBtn.classList.add('bg-green-600', 'hover:bg-green-700');
inputField.disabled = false;
inputField.value = '';
// Reset text display
document.querySelectorAll('.character').forEach(char => {
char.classList.remove('correct', 'wrong', 'current');
});
// Reset cursor
const cursor = document.getElementById('cursor');
if (cursor) cursor.remove();
const newCursor = document.createElement('div');
newCursor.className = 'cursor';
newCursor.id = 'cursor';
if (document.getElementById('char-0')) {
document.getElementById('char-0').appendChild(newCursor);
document.getElementById('char-0').classList.add('current');
}
}
// Initialize the game when page loads
window.addEventListener('load', initGame);
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Ketamin/key" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>