1068 lines
31 KiB
HTML
1068 lines
31 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>TechLex — AI & Tech Vocabulary Game</title>
|
|
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
*, *::before, *::after {
|
|
box-sizing: border-box;
|
|
margin: 0;
|
|
padding: 0;
|
|
}
|
|
|
|
:root {
|
|
--bg: #0a0a0f;
|
|
--card: #12121a;
|
|
--border: #1e1e2e;
|
|
--cyan: #00f0ff;
|
|
--purple: #b44aff;
|
|
--pink: #ff2d7b;
|
|
--green: #00ff88;
|
|
--yellow: #ffd600;
|
|
--text: #e0e0e8;
|
|
--text-dim: #6b6b80;
|
|
--glow-cyan: 0 0 20px rgba(0, 240, 255, 0.3);
|
|
--glow-purple: 0 0 20px rgba(180, 74, 255, 0.3);
|
|
}
|
|
|
|
body {
|
|
font-family: 'Space Grotesk', sans-serif;
|
|
background: var(--bg);
|
|
color: var(--text);
|
|
min-height: 100vh;
|
|
overflow-x: hidden;
|
|
background-image:
|
|
radial-gradient(ellipse at 20% 50%, rgba(0, 240, 255, 0.03) 0%, transparent 50%),
|
|
radial-gradient(ellipse at 80% 50%, rgba(180, 74, 255, 0.03) 0%, transparent 50%);
|
|
}
|
|
|
|
.container {
|
|
max-width: 800px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.screen {
|
|
display: none;
|
|
animation: fadeIn 0.4s ease;
|
|
}
|
|
|
|
.screen.active {
|
|
display: block;
|
|
}
|
|
|
|
@keyframes fadeIn {
|
|
from { opacity: 0; transform: translateY(10px); }
|
|
to { opacity: 1; transform: translateY(0); }
|
|
}
|
|
|
|
@keyframes pulse {
|
|
0%, 100% { transform: scale(1); }
|
|
50% { transform: scale(1.02); }
|
|
}
|
|
|
|
@keyframes glow {
|
|
0%, 100% { box-shadow: 0 0 5px rgba(0, 240, 255, 0.2); }
|
|
50% { box-shadow: 0 0 20px rgba(0, 240, 255, 0.4), 0 0 40px rgba(0, 240, 255, 0.1); }
|
|
}
|
|
|
|
@keyframes slideIn {
|
|
from { opacity: 0; transform: translateX(-20px); }
|
|
to { opacity: 1; transform: translateX(0); }
|
|
}
|
|
|
|
@keyframes shake {
|
|
0%, 100% { transform: translateX(0); }
|
|
20% { transform: translateX(-8px); }
|
|
40% { transform: translateX(8px); }
|
|
60% { transform: translateX(-4px); }
|
|
80% { transform: translateX(4px); }
|
|
}
|
|
|
|
@keyframes success {
|
|
0% { transform: scale(1); }
|
|
50% { transform: scale(1.05); }
|
|
100% { transform: scale(1); }
|
|
}
|
|
|
|
/* Header */
|
|
.header {
|
|
text-align: center;
|
|
padding: 40px 0 30px;
|
|
}
|
|
|
|
.logo {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 3rem;
|
|
font-weight: 700;
|
|
background: linear-gradient(135deg, var(--cyan), var(--purple));
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
letter-spacing: 4px;
|
|
}
|
|
|
|
.tagline {
|
|
color: var(--text-dim);
|
|
font-size: 1rem;
|
|
margin-top: 8px;
|
|
letter-spacing: 2px;
|
|
}
|
|
|
|
/* Cards */
|
|
.card {
|
|
background: var(--card);
|
|
border: 1px solid var(--border);
|
|
border-radius: 16px;
|
|
padding: 30px;
|
|
margin-bottom: 20px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.card:hover {
|
|
border-color: rgba(0, 240, 255, 0.2);
|
|
}
|
|
|
|
/* Buttons */
|
|
.btn {
|
|
font-family: 'Space Grotesk', sans-serif;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
padding: 14px 28px;
|
|
border: none;
|
|
border-radius: 12px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
.btn-primary {
|
|
background: linear-gradient(135deg, var(--cyan), var(--purple));
|
|
color: #000;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: var(--glow-cyan);
|
|
}
|
|
|
|
.btn-secondary {
|
|
background: transparent;
|
|
border: 2px solid var(--purple);
|
|
color: var(--purple);
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
background: rgba(180, 74, 255, 0.1);
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.btn-small {
|
|
padding: 10px 20px;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
transform: none !important;
|
|
}
|
|
|
|
/* Mode Selection */
|
|
.mode-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
|
gap: 20px;
|
|
margin-top: 30px;
|
|
}
|
|
|
|
.mode-card {
|
|
background: var(--card);
|
|
border: 2px solid var(--border);
|
|
border-radius: 20px;
|
|
padding: 35px 30px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.mode-card::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 3px;
|
|
background: linear-gradient(90deg, var(--cyan), var(--purple));
|
|
opacity: 0;
|
|
transition: opacity 0.3s ease;
|
|
}
|
|
|
|
.mode-card:hover {
|
|
border-color: var(--cyan);
|
|
transform: translateY(-4px);
|
|
box-shadow: var(--glow-cyan);
|
|
}
|
|
|
|
.mode-card:hover::before {
|
|
opacity: 1;
|
|
}
|
|
|
|
.mode-icon {
|
|
font-size: 3rem;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.mode-title {
|
|
font-size: 1.4rem;
|
|
font-weight: 700;
|
|
margin-bottom: 10px;
|
|
color: var(--cyan);
|
|
}
|
|
|
|
.mode-desc {
|
|
color: var(--text-dim);
|
|
font-size: 0.95rem;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* Game Area */
|
|
.game-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 25px;
|
|
flex-wrap: wrap;
|
|
gap: 15px;
|
|
}
|
|
|
|
.game-title {
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
color: var(--cyan);
|
|
}
|
|
|
|
.game-stats {
|
|
display: flex;
|
|
gap: 20px;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
}
|
|
|
|
.stat {
|
|
text-align: center;
|
|
}
|
|
|
|
.stat-value {
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
color: var(--purple);
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.75rem;
|
|
color: var(--text-dim);
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
}
|
|
|
|
/* Scramble */
|
|
.scramble-word {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 2.5rem;
|
|
font-weight: 700;
|
|
text-align: center;
|
|
padding: 30px;
|
|
background: linear-gradient(135deg, rgba(0, 240, 255, 0.05), rgba(180, 74, 255, 0.05));
|
|
border: 2px dashed var(--border);
|
|
border-radius: 16px;
|
|
margin: 20px 0;
|
|
letter-spacing: 8px;
|
|
color: var(--cyan);
|
|
word-break: break-word;
|
|
}
|
|
|
|
.hint-text {
|
|
text-align: center;
|
|
color: var(--text-dim);
|
|
font-size: 0.95rem;
|
|
margin-bottom: 20px;
|
|
font-style: italic;
|
|
}
|
|
|
|
.input-group {
|
|
display: flex;
|
|
gap: 12px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.input-group input {
|
|
flex: 1;
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 1.2rem;
|
|
padding: 14px 20px;
|
|
background: var(--bg);
|
|
border: 2px solid var(--border);
|
|
border-radius: 12px;
|
|
color: var(--text);
|
|
outline: none;
|
|
transition: border-color 0.2s ease;
|
|
}
|
|
|
|
.input-group input:focus {
|
|
border-color: var(--cyan);
|
|
}
|
|
|
|
.input-group input::placeholder {
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
/* Definition Match */
|
|
.definitions-grid {
|
|
display: grid;
|
|
gap: 12px;
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.def-option {
|
|
background: var(--bg);
|
|
border: 2px solid var(--border);
|
|
border-radius: 12px;
|
|
padding: 18px 20px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
text-align: left;
|
|
font-size: 1rem;
|
|
color: var(--text);
|
|
font-family: 'Space Grotesk', sans-serif;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.def-option:hover:not(:disabled) {
|
|
border-color: var(--cyan);
|
|
background: rgba(0, 240, 255, 0.05);
|
|
}
|
|
|
|
.def-option.correct {
|
|
border-color: var(--green);
|
|
background: rgba(0, 255, 136, 0.1);
|
|
animation: success 0.4s ease;
|
|
}
|
|
|
|
.def-option.wrong {
|
|
border-color: var(--pink);
|
|
background: rgba(255, 45, 123, 0.1);
|
|
animation: shake 0.4s ease;
|
|
}
|
|
|
|
.def-option:disabled {
|
|
cursor: not-allowed;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.term-display {
|
|
text-align: center;
|
|
font-size: 1.8rem;
|
|
font-weight: 700;
|
|
color: var(--purple);
|
|
margin: 20px 0;
|
|
padding: 20px;
|
|
background: linear-gradient(135deg, rgba(180, 74, 255, 0.1), rgba(0, 240, 255, 0.05));
|
|
border-radius: 16px;
|
|
border: 1px solid rgba(180, 74, 255, 0.2);
|
|
}
|
|
|
|
/* Progress Bar */
|
|
.progress-bar {
|
|
height: 6px;
|
|
background: var(--border);
|
|
border-radius: 3px;
|
|
margin-bottom: 25px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, var(--cyan), var(--purple));
|
|
border-radius: 3px;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
/* Results */
|
|
.results-card {
|
|
text-align: center;
|
|
padding: 40px;
|
|
}
|
|
|
|
.score-display {
|
|
font-family: 'JetBrains Mono', monospace;
|
|
font-size: 4rem;
|
|
font-weight: 700;
|
|
background: linear-gradient(135deg, var(--cyan), var(--purple));
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.score-label {
|
|
color: var(--text-dim);
|
|
font-size: 1.1rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 2px;
|
|
}
|
|
|
|
.high-score {
|
|
color: var(--yellow);
|
|
font-size: 1rem;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.results-actions {
|
|
display: flex;
|
|
gap: 15px;
|
|
justify-content: center;
|
|
margin-top: 30px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
/* Feedback */
|
|
.feedback {
|
|
text-align: center;
|
|
padding: 12px;
|
|
border-radius: 10px;
|
|
margin-top: 15px;
|
|
font-weight: 600;
|
|
animation: slideIn 0.3s ease;
|
|
}
|
|
|
|
.feedback.correct {
|
|
background: rgba(0, 255, 136, 0.1);
|
|
color: var(--green);
|
|
border: 1px solid rgba(0, 255, 136, 0.2);
|
|
}
|
|
|
|
.feedback.wrong {
|
|
background: rgba(255, 45, 123, 0.1);
|
|
color: var(--pink);
|
|
border: 1px solid rgba(255, 45, 123, 0.2);
|
|
}
|
|
|
|
/* Difficulty Badge */
|
|
.difficulty-badge {
|
|
display: inline-block;
|
|
padding: 4px 12px;
|
|
border-radius: 20px;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 1px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.difficulty-badge.easy {
|
|
background: rgba(0, 255, 136, 0.1);
|
|
color: var(--green);
|
|
border: 1px solid rgba(0, 255, 136, 0.2);
|
|
}
|
|
|
|
.difficulty-badge.medium {
|
|
background: rgba(255, 214, 0, 0.1);
|
|
color: var(--yellow);
|
|
border: 1px solid rgba(255, 214, 0, 0.2);
|
|
}
|
|
|
|
.difficulty-badge.hard {
|
|
background: rgba(255, 45, 123, 0.1);
|
|
color: var(--pink);
|
|
border: 1px solid rgba(255, 45, 123, 0.2);
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 600px) {
|
|
.logo { font-size: 2rem; }
|
|
.scramble-word { font-size: 1.5rem; letter-spacing: 4px; }
|
|
.term-display { font-size: 1.3rem; }
|
|
.score-display { font-size: 3rem; }
|
|
.game-stats { gap: 15px; }
|
|
.input-group { flex-direction: column; }
|
|
.mode-grid { grid-template-columns: 1fr; }
|
|
}
|
|
|
|
/* Circuit pattern decoration */
|
|
.circuit-bg {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
pointer-events: none;
|
|
z-index: -1;
|
|
opacity: 0.03;
|
|
background-image:
|
|
linear-gradient(90deg, var(--cyan) 1px, transparent 1px),
|
|
linear-gradient(var(--cyan) 1px, transparent 1px);
|
|
background-size: 50px 50px;
|
|
}
|
|
|
|
/* Timer bar */
|
|
.timer-bar {
|
|
height: 4px;
|
|
background: var(--border);
|
|
border-radius: 2px;
|
|
margin-top: 15px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.timer-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, var(--green), var(--yellow), var(--pink));
|
|
border-radius: 2px;
|
|
transition: width 0.1s linear;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="circuit-bg"></div>
|
|
<div class="container">
|
|
<!-- MENU SCREEN -->
|
|
<div id="menu-screen" class="screen active">
|
|
<div class="header">
|
|
<div class="logo">TECHLEX</div>
|
|
<div class="tagline">Master AI & Tech Vocabulary</div>
|
|
</div>
|
|
<div class="mode-grid">
|
|
<div class="mode-card" onclick="startScramble()">
|
|
<div class="mode-icon">🔀</div>
|
|
<div class="mode-title">Word Scramble</div>
|
|
<div class="mode-desc">Unscramble tech terms before time runs out. Use hints wisely!</div>
|
|
</div>
|
|
<div class="mode-card" onclick="startDefinitions()">
|
|
<div class="mode-icon">📚</div>
|
|
<div class="mode-title">Definition Match</div>
|
|
<div class="mode-desc">Match the correct definition to each tech term. 10 rounds!</div>
|
|
</div>
|
|
</div>
|
|
<div class="card" style="margin-top: 30px; text-align: center;">
|
|
<div style="color: var(--text-dim); font-size: 0.9rem;">
|
|
<strong style="color: var(--cyan);">High Scores</strong>
|
|
</div>
|
|
<div style="display: flex; justify-content: center; gap: 40px; margin-top: 15px; font-family: 'JetBrains Mono', monospace;">
|
|
<div>
|
|
<div style="color: var(--text-dim); font-size: 0.75rem;">SCRAMBLE</div>
|
|
<div id="menu-high-scramble" style="font-size: 1.5rem; color: var(--purple);">0</div>
|
|
</div>
|
|
<div>
|
|
<div style="color: var(--text-dim); font-size: 0.75rem;">DEFINITIONS</div>
|
|
<div id="menu-high-def" style="font-size: 1.5rem; color: var(--purple);">0</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SCRAMBLE SCREEN -->
|
|
<div id="scramble-screen" class="screen">
|
|
<div class="game-header">
|
|
<button class="btn btn-secondary btn-small" onclick="showMenu()">← Menu</button>
|
|
<div class="game-title">Word Scramble</div>
|
|
<div class="game-stats">
|
|
<div class="stat">
|
|
<div id="scramble-score" class="stat-value">0</div>
|
|
<div class="stat-label">Score</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div id="scramble-round" class="stat-value">1/10</div>
|
|
<div class="stat-label">Round</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="progress-bar">
|
|
<div id="scramble-progress" class="progress-fill" style="width: 0%"></div>
|
|
</div>
|
|
<div class="card">
|
|
<div id="scramble-difficulty" class="difficulty-badge easy">Easy</div>
|
|
<div id="scramble-word" class="scramble-word">LOADING</div>
|
|
<div id="scramble-hint" class="hint-text">Hint will appear here</div>
|
|
<div class="timer-bar">
|
|
<div id="scramble-timer" class="timer-fill" style="width: 100%"></div>
|
|
</div>
|
|
<div class="input-group">
|
|
<input type="text" id="scramble-input" placeholder="Type your answer..." autocomplete="off" onkeydown="if(event.key==='Enter')checkScramble()">
|
|
<button class="btn btn-primary" onclick="checkScramble()">Submit</button>
|
|
</div>
|
|
<div style="display: flex; gap: 10px; margin-top: 12px; justify-content: center;">
|
|
<button class="btn btn-secondary btn-small" onclick="useHint()">Hint (-5 pts)</button>
|
|
<button class="btn btn-secondary btn-small" onclick="skipScramble()">Skip</button>
|
|
</div>
|
|
<div id="scramble-feedback"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DEFINITIONS SCREEN -->
|
|
<div id="definitions-screen" class="screen">
|
|
<div class="game-header">
|
|
<button class="btn btn-secondary btn-small" onclick="showMenu()">← Menu</button>
|
|
<div class="game-title">Definition Match</div>
|
|
<div class="game-stats">
|
|
<div class="stat">
|
|
<div id="def-score" class="stat-value">0</div>
|
|
<div class="stat-label">Score</div>
|
|
</div>
|
|
<div class="stat">
|
|
<div id="def-round" class="stat-value">1/10</div>
|
|
<div class="stat-label">Round</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="progress-bar">
|
|
<div id="def-progress" class="progress-fill" style="width: 0%"></div>
|
|
</div>
|
|
<div class="card">
|
|
<div style="text-align: center; color: var(--text-dim); margin-bottom: 10px;">What does this term mean?</div>
|
|
<div id="def-term" class="term-display">TERM</div>
|
|
<div id="def-options" class="definitions-grid"></div>
|
|
<div id="def-feedback"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RESULTS SCREEN -->
|
|
<div id="results-screen" class="screen">
|
|
<div class="card results-card">
|
|
<div class="score-label" id="results-mode">GAME OVER</div>
|
|
<div id="results-score" class="score-display">0</div>
|
|
<div id="results-high" class="high-score"></div>
|
|
<div id="results-details" style="color: var(--text-dim); margin-top: 15px;"></div>
|
|
<div class="results-actions">
|
|
<button class="btn btn-primary" id="results-replay" onclick="replayGame()">Play Again</button>
|
|
<button class="btn btn-secondary" onclick="showMenu()">Main Menu</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// WORD BANK
|
|
const wordBank = [
|
|
{ term: "ALGORITHM", hint: "Step-by-step procedure for calculations", difficulty: "easy" },
|
|
{ term: "SENSOR", hint: "Device that detects changes in environment", difficulty: "easy" },
|
|
{ term: "DRONE", hint: "Unmanned aerial vehicle", difficulty: "easy" },
|
|
{ term: "ROBOT", hint: "Programmable machine that carries out tasks", difficulty: "easy" },
|
|
{ term: "CLOUD", hint: "Remote servers for storing data over the internet", difficulty: "easy" },
|
|
{ term: "DATA", hint: "Facts and statistics collected for analysis", difficulty: "easy" },
|
|
{ term: "CODE", hint: "Instructions written for computers to execute", difficulty: "easy" },
|
|
{ term: "BIAS", hint: "Systematic error in AI decision making", difficulty: "easy" },
|
|
{ term: "NODE", hint: "Connection point in a network or neural structure", difficulty: "easy" },
|
|
{ term: "CHIP", hint: "Small electronic circuit that processes information", difficulty: "easy" },
|
|
{ term: "AUTONOMOUS", hint: "Self-governing, operating without human control", difficulty: "medium" },
|
|
{ term: "NEURAL", hint: "Relating to nerve cells or brain-like networks", difficulty: "medium" },
|
|
{ term: "CYBER", hint: "Prefix relating to computers and information technology", difficulty: "medium" },
|
|
{ term: "VIRTUAL", hint: "Simulated environment created by software", difficulty: "medium" },
|
|
{ term: "DIGITAL", hint: "Using discrete values, typically binary", difficulty: "medium" },
|
|
{ term: "NETWORK", hint: "Interconnected group of computers or people", difficulty: "medium" },
|
|
{ term: "BINARY", hint: "Number system using only 0 and 1", difficulty: "medium" },
|
|
{ term: "PYTHON", hint: "Popular programming language named after a comedy group", difficulty: "medium" },
|
|
{ term: "SERVER", hint: "Computer that provides data to other computers", difficulty: "medium" },
|
|
{ term: "ROUTER", hint: "Device that forwards data between networks", difficulty: "medium" },
|
|
{ term: "ACTUATOR", hint: "Component that moves or controls a mechanism", difficulty: "medium" },
|
|
{ term: "QUANTUM", hint: "Smallest discrete unit of a phenomenon", difficulty: "medium" },
|
|
{ term: "BLOCKCHAIN", hint: "Distributed ledger technology behind cryptocurrencies", difficulty: "hard" },
|
|
{ term: "CYBERSECURITY", hint: "Protection of systems from digital attacks", difficulty: "hard" },
|
|
{ term: "MACHINE LEARNING", hint: "AI that improves through experience without explicit programming", difficulty: "hard" },
|
|
{ term: "DEEP LEARNING", hint: "Neural networks with many layers for complex pattern recognition", difficulty: "hard" },
|
|
{ term: "COMPUTER VISION", hint: "AI field enabling machines to interpret visual information", difficulty: "hard" },
|
|
{ term: "NATURAL LANGUAGE", hint: "Human communication as used in AI processing", difficulty: "hard" },
|
|
{ term: "AUGMENTED REALITY", hint: "Technology overlaying digital info on the real world", difficulty: "hard" },
|
|
{ term: "INTERNET OF THINGS", hint: "Network of connected physical devices with sensors", difficulty: "hard" },
|
|
{ term: "EXOSKELETON", hint: "Wearable robotic device that enhances human strength", difficulty: "hard" },
|
|
{ term: "BIOMETRIC", hint: "Authentication using unique physical characteristics", difficulty: "hard" },
|
|
{ term: "NANOTECHNOLOGY", hint: "Engineering at the atomic or molecular scale", difficulty: "hard" },
|
|
{ term: "AUTOMATION", hint: "Using technology to perform tasks with minimal human input", difficulty: "hard" },
|
|
{ term: "ROBOTICS", hint: "Branch of technology dealing with robot design and operation", difficulty: "hard" }
|
|
];
|
|
|
|
// AUDIO ENGINE
|
|
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
|
|
|
|
function playSound(type) {
|
|
const osc = audioCtx.createOscillator();
|
|
const gain = audioCtx.createGain();
|
|
osc.connect(gain);
|
|
gain.connect(audioCtx.destination);
|
|
|
|
switch(type) {
|
|
case 'correct':
|
|
osc.frequency.setValueAtTime(523.25, audioCtx.currentTime);
|
|
osc.frequency.setValueAtTime(659.25, audioCtx.currentTime + 0.1);
|
|
osc.frequency.setValueAtTime(783.99, audioCtx.currentTime + 0.2);
|
|
gain.gain.setValueAtTime(0.15, audioCtx.currentTime);
|
|
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.4);
|
|
osc.start(audioCtx.currentTime);
|
|
osc.stop(audioCtx.currentTime + 0.4);
|
|
break;
|
|
case 'wrong':
|
|
osc.type = 'sawtooth';
|
|
osc.frequency.setValueAtTime(200, audioCtx.currentTime);
|
|
osc.frequency.setValueAtTime(150, audioCtx.currentTime + 0.15);
|
|
gain.gain.setValueAtTime(0.1, audioCtx.currentTime);
|
|
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.3);
|
|
osc.start(audioCtx.currentTime);
|
|
osc.stop(audioCtx.currentTime + 0.3);
|
|
break;
|
|
case 'click':
|
|
osc.frequency.setValueAtTime(800, audioCtx.currentTime);
|
|
gain.gain.setValueAtTime(0.08, audioCtx.currentTime);
|
|
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.05);
|
|
osc.start(audioCtx.currentTime);
|
|
osc.stop(audioCtx.currentTime + 0.05);
|
|
break;
|
|
case 'hint':
|
|
osc.type = 'sine';
|
|
osc.frequency.setValueAtTime(400, audioCtx.currentTime);
|
|
osc.frequency.setValueAtTime(600, audioCtx.currentTime + 0.1);
|
|
gain.gain.setValueAtTime(0.1, audioCtx.currentTime);
|
|
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.2);
|
|
osc.start(audioCtx.currentTime);
|
|
osc.stop(audioCtx.currentTime + 0.2);
|
|
break;
|
|
case 'win':
|
|
[523.25, 587.33, 659.25, 783.99, 880, 1046.5].forEach((freq, i) => {
|
|
const o = audioCtx.createOscillator();
|
|
const g = audioCtx.createGain();
|
|
o.connect(g);
|
|
g.connect(audioCtx.destination);
|
|
o.frequency.setValueAtTime(freq, audioCtx.currentTime + i * 0.1);
|
|
g.gain.setValueAtTime(0.12, audioCtx.currentTime + i * 0.1);
|
|
g.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + i * 0.1 + 0.3);
|
|
o.start(audioCtx.currentTime + i * 0.1);
|
|
o.stop(audioCtx.currentTime + i * 0.1 + 0.3);
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
|
|
// UTILITIES
|
|
function shuffle(arr) {
|
|
const a = [...arr];
|
|
for (let i = a.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[a[i], a[j]] = [a[j], a[i]];
|
|
}
|
|
return a;
|
|
}
|
|
|
|
function scrambleWord(word) {
|
|
const letters = word.replace(/ /g, '').split('');
|
|
let scrambled;
|
|
do {
|
|
scrambled = shuffle(letters);
|
|
} while (scrambled.join('') === word.replace(/ /g, '') && word.replace(/ /g, '').length > 1);
|
|
|
|
// Insert spaces back for multi-word terms
|
|
const cleanWord = word.replace(/ /g, '');
|
|
let result = '';
|
|
let spaceIdx = word.indexOf(' ');
|
|
let letterIdx = 0;
|
|
|
|
if (spaceIdx === -1) return scrambled.join('');
|
|
|
|
for (let i = 0; i < word.length; i++) {
|
|
if (word[i] === ' ') {
|
|
result += ' ';
|
|
} else {
|
|
result += scrambled[letterIdx++];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
function getHighScore(mode) {
|
|
return parseInt(localStorage.getItem(`techlex_${mode}`) || '0');
|
|
}
|
|
|
|
function setHighScore(mode, score) {
|
|
const current = getHighScore(mode);
|
|
if (score > current) {
|
|
localStorage.setItem(`techlex_${mode}`, score);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// SCREEN MANAGEMENT
|
|
function showScreen(id) {
|
|
document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
|
|
document.getElementById(id).classList.add('active');
|
|
playSound('click');
|
|
}
|
|
|
|
function showMenu() {
|
|
if (scrambleTimer) clearInterval(scrambleTimer);
|
|
updateMenuScores();
|
|
showScreen('menu-screen');
|
|
}
|
|
|
|
function updateMenuScores() {
|
|
document.getElementById('menu-high-scramble').textContent = getHighScore('scramble');
|
|
document.getElementById('menu-high-def').textContent = getHighScore('definitions');
|
|
}
|
|
|
|
// SCRAMBLE GAME
|
|
let scrambleState = {
|
|
words: [],
|
|
current: 0,
|
|
score: 0,
|
|
correct: 0,
|
|
timer: null,
|
|
timeLeft: 100,
|
|
hintUsed: false
|
|
};
|
|
|
|
function startScramble() {
|
|
const easy = wordBank.filter(w => w.difficulty === 'easy');
|
|
const medium = wordBank.filter(w => w.difficulty === 'medium');
|
|
const hard = wordBank.filter(w => w.difficulty === 'hard');
|
|
|
|
scrambleState.words = shuffle([
|
|
...shuffle(easy).slice(0, 3),
|
|
...shuffle(medium).slice(0, 4),
|
|
...shuffle(hard).slice(0, 3)
|
|
]);
|
|
scrambleState.current = 0;
|
|
scrambleState.score = 0;
|
|
scrambleState.correct = 0;
|
|
scrambleState.hintUsed = false;
|
|
|
|
showScreen('scramble-screen');
|
|
loadScrambleWord();
|
|
}
|
|
|
|
function loadScrambleWord() {
|
|
if (scrambleState.current >= scrambleState.words.length) {
|
|
endScramble();
|
|
return;
|
|
}
|
|
|
|
const word = scrambleState.words[scrambleState.current];
|
|
scrambleState.timeLeft = 100;
|
|
scrambleState.hintUsed = false;
|
|
|
|
document.getElementById('scramble-word').textContent = scrambleWord(word.term);
|
|
document.getElementById('scramble-hint').textContent = 'Press Hint for a clue (-5 points)';
|
|
document.getElementById('scramble-score').textContent = scrambleState.score;
|
|
document.getElementById('scramble-round').textContent = `${scrambleState.current + 1}/${scrambleState.words.length}`;
|
|
document.getElementById('scramble-progress').style.width = `${(scrambleState.current / scrambleState.words.length) * 100}%`;
|
|
document.getElementById('scramble-input').value = '';
|
|
document.getElementById('scramble-feedback').innerHTML = '';
|
|
|
|
const diffBadge = document.getElementById('scramble-difficulty');
|
|
diffBadge.textContent = word.difficulty;
|
|
diffBadge.className = `difficulty-badge ${word.difficulty === 'easy' ? 'easy' : word.difficulty === 'medium' ? 'medium' : 'hard'}`;
|
|
|
|
startScrambleTimer();
|
|
document.getElementById('scramble-input').focus();
|
|
}
|
|
|
|
function startScrambleTimer() {
|
|
if (scrambleTimer) clearInterval(scrambleTimer);
|
|
scrambleState.timeLeft = 100;
|
|
document.getElementById('scramble-timer').style.width = '100%';
|
|
|
|
scrambleTimer = setInterval(() => {
|
|
scrambleState.timeLeft -= 0.5;
|
|
document.getElementById('scramble-timer').style.width = `${scrambleState.timeLeft}%`;
|
|
|
|
if (scrambleState.timeLeft <= 0) {
|
|
clearInterval(scrambleTimer);
|
|
scrambleTimeout();
|
|
}
|
|
}, 100);
|
|
}
|
|
|
|
function scrambleTimeout() {
|
|
const word = scrambleState.words[scrambleState.current];
|
|
playSound('wrong');
|
|
document.getElementById('scramble-feedback').innerHTML = `<div class="feedback wrong">Time's up! The answer was: ${word.term}</div>`;
|
|
scrambleState.current++;
|
|
setTimeout(loadScrambleWord, 2000);
|
|
}
|
|
|
|
function checkScramble() {
|
|
const input = document.getElementById('scramble-input').value.trim().toUpperCase();
|
|
if (!input) return;
|
|
|
|
const word = scrambleState.words[scrambleState.current];
|
|
const feedback = document.getElementById('scramble-feedback');
|
|
|
|
if (input === word.term) {
|
|
clearInterval(scrambleTimer);
|
|
playSound('correct');
|
|
let points = 10;
|
|
if (word.difficulty === 'medium') points = 15;
|
|
if (word.difficulty === 'hard') points = 20;
|
|
if (scrambleState.hintUsed) points -= 5;
|
|
if (points < 1) points = 1;
|
|
|
|
scrambleState.score += points;
|
|
scrambleState.correct++;
|
|
document.getElementById('scramble-score').textContent = scrambleState.score;
|
|
feedback.innerHTML = `<div class="feedback correct">Correct! +${points} points</div>`;
|
|
scrambleState.current++;
|
|
setTimeout(loadScrambleWord, 1200);
|
|
} else {
|
|
playSound('wrong');
|
|
feedback.innerHTML = `<div class="feedback wrong">Try again!</div>`;
|
|
document.getElementById('scramble-input').value = '';
|
|
document.getElementById('scramble-input').focus();
|
|
}
|
|
}
|
|
|
|
function useHint() {
|
|
if (scrambleState.hintUsed) return;
|
|
scrambleState.hintUsed = true;
|
|
playSound('hint');
|
|
|
|
const word = scrambleState.words[scrambleState.current];
|
|
const firstLetter = word.term[0];
|
|
const length = word.term.length;
|
|
document.getElementById('scramble-hint').textContent = `Starts with "${firstLetter}" — ${length} characters`;
|
|
}
|
|
|
|
function skipScramble() {
|
|
clearInterval(scrambleTimer);
|
|
const word = scrambleState.words[scrambleState.current];
|
|
playSound('click');
|
|
document.getElementById('scramble-feedback').innerHTML = `<div class="feedback wrong">Skipped! Answer: ${word.term}</div>`;
|
|
scrambleState.current++;
|
|
setTimeout(loadScrambleWord, 1500);
|
|
}
|
|
|
|
function endScramble() {
|
|
clearInterval(scrambleTimer);
|
|
const isNewHigh = setHighScore('scramble', scrambleState.score);
|
|
playSound('win');
|
|
|
|
document.getElementById('results-mode').textContent = 'WORD SCRAMBLE COMPLETE';
|
|
document.getElementById('results-score').textContent = scrambleState.score;
|
|
document.getElementById('results-high').textContent = isNewHigh ? '🏆 New High Score!' : `High Score: ${getHighScore('scramble')}`;
|
|
document.getElementById('results-details').textContent = `${scrambleState.correct}/${scrambleState.words.length} correct`;
|
|
document.getElementById('results-replay').onclick = startScramble;
|
|
|
|
showScreen('results-screen');
|
|
}
|
|
|
|
// DEFINITIONS GAME
|
|
let defState = {
|
|
questions: [],
|
|
current: 0,
|
|
score: 0,
|
|
correct: 0,
|
|
total: 10
|
|
};
|
|
|
|
function startDefinitions() {
|
|
const shuffled = shuffle(wordBank);
|
|
defState.questions = shuffled.slice(0, defState.total).map(word => {
|
|
const wrongDefs = shuffle(wordBank.filter(w => w.term !== word.term)).slice(0, 3).map(w => w.hint);
|
|
const options = shuffle([word.hint, ...wrongDefs]);
|
|
return {
|
|
term: word.term,
|
|
correctHint: word.hint,
|
|
options: options,
|
|
difficulty: word.difficulty
|
|
};
|
|
});
|
|
|
|
defState.current = 0;
|
|
defState.score = 0;
|
|
defState.correct = 0;
|
|
|
|
showScreen('definitions-screen');
|
|
loadDefQuestion();
|
|
}
|
|
|
|
function loadDefQuestion() {
|
|
if (defState.current >= defState.questions.length) {
|
|
endDefinitions();
|
|
return;
|
|
}
|
|
|
|
const q = defState.questions[defState.current];
|
|
document.getElementById('def-term').textContent = q.term;
|
|
document.getElementById('def-score').textContent = defState.score;
|
|
document.getElementById('def-round').textContent = `${defState.current + 1}/${defState.total}`;
|
|
document.getElementById('def-progress').style.width = `${(defState.current / defState.total) * 100}%`;
|
|
document.getElementById('def-feedback').innerHTML = '';
|
|
|
|
const optionsContainer = document.getElementById('def-options');
|
|
optionsContainer.innerHTML = '';
|
|
|
|
q.options.forEach((opt, idx) => {
|
|
const btn = document.createElement('button');
|
|
btn.className = 'def-option';
|
|
btn.textContent = opt;
|
|
btn.onclick = () => checkDefAnswer(idx, btn);
|
|
optionsContainer.appendChild(btn);
|
|
});
|
|
}
|
|
|
|
function checkDefAnswer(idx, btn) {
|
|
const q = defState.questions[defState.current];
|
|
const buttons = document.querySelectorAll('.def-option');
|
|
const feedback = document.getElementById('def-feedback');
|
|
|
|
buttons.forEach(b => b.disabled = true);
|
|
|
|
if (q.options[idx] === q.correctHint) {
|
|
playSound('correct');
|
|
btn.classList.add('correct');
|
|
let points = 10;
|
|
if (q.difficulty === 'medium') points = 15;
|
|
if (q.difficulty === 'hard') points = 20;
|
|
|
|
defState.score += points;
|
|
defState.correct++;
|
|
document.getElementById('def-score').textContent = defState.score;
|
|
feedback.innerHTML = `<div class="feedback correct">Correct! +${points} points</div>`;
|
|
} else {
|
|
playSound('wrong');
|
|
btn.classList.add('wrong');
|
|
buttons.forEach(b => {
|
|
if (b.textContent === q.correctHint) b.classList.add('correct');
|
|
});
|
|
feedback.innerHTML = `<div class="feedback wrong">Wrong! The correct answer is highlighted.</div>`;
|
|
}
|
|
|
|
defState.current++;
|
|
setTimeout(loadDefQuestion, 1800);
|
|
}
|
|
|
|
function endDefinitions() {
|
|
const isNewHigh = setHighScore('definitions', defState.score);
|
|
playSound('win');
|
|
|
|
document.getElementById('results-mode').textContent = 'DEFINITION MATCH COMPLETE';
|
|
document.getElementById('results-score').textContent = defState.score;
|
|
document.getElementById('results-high').textContent = isNewHigh ? '🏆 New High Score!' : `High Score: ${getHighScore('definitions')}`;
|
|
document.getElementById('results-details').textContent = `${defState.correct}/${defState.total} correct`;
|
|
document.getElementById('results-replay').onclick = startDefinitions;
|
|
|
|
showScreen('results-screen');
|
|
}
|
|
|
|
function replayGame() {
|
|
const mode = document.getElementById('results-mode').textContent;
|
|
if (mode.includes('SCRAMBLE')) startScramble();
|
|
else startDefinitions();
|
|
}
|
|
|
|
// INIT
|
|
updateMenuScores();
|
|
</script>
|
|
</body>
|
|
</html>
|