Files
anglina-vibecodin/3.html
2026-04-01 12:23:43 +02:00

895 lines
52 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UPLINK — Engineering English Challenge</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box;margin:0;padding:0}
:root{
--bg:#0a0e17;--bg2:#111827;--bg3:#1a2235;--bg4:#232d42;
--accent:#22d68a;--accent2:#1ba8e0;--warn:#ef9f27;--danger:#e24b4a;--success:#22d68a;
--text:#e8eaf0;--text2:#8b93a7;--text3:#525b6f;
--mono:'JetBrains Mono',monospace;--sans:'DM Sans',sans-serif;
--radius:10px;--radius-lg:14px;
}
html,body{height:100%;overflow:hidden}
body{background:var(--bg);color:var(--text);font-family:var(--sans);display:flex;align-items:center;justify-content:center}
canvas#particles{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:100}
.game{width:100%;max-width:700px;height:100vh;max-height:800px;position:relative;overflow:hidden;display:flex;flex-direction:column}
.screen{position:absolute;inset:0;display:flex;flex-direction:column;padding:24px;opacity:0;pointer-events:none;transition:opacity .4s,transform .4s;transform:translateY(20px);overflow-y:auto}
.screen.active{opacity:1;pointer-events:auto;transform:translateY(0)}
/* SPLASH */
.splash{align-items:center;justify-content:center;text-align:center}
.splash-logo{width:80px;height:80px;border-radius:20px;background:linear-gradient(135deg,#22d68a,#1ba8e0);display:flex;align-items:center;justify-content:center;margin-bottom:20px;animation:pulse-glow 2s ease-in-out infinite}
@keyframes pulse-glow{0%,100%{box-shadow:0 0 30px rgba(34,214,138,.3)}50%{box-shadow:0 0 60px rgba(34,214,138,.5)}}
.splash-logo svg{width:44px;height:44px}
.splash h1{font-family:var(--mono);font-size:42px;font-weight:700;letter-spacing:-1px;margin-bottom:4px}
.splash h1 span{color:var(--accent)}
.splash .tagline{font-family:var(--mono);font-size:12px;color:var(--text2);letter-spacing:3px;text-transform:uppercase;margin-bottom:40px}
.btn{font-family:var(--mono);font-size:14px;font-weight:500;padding:14px 36px;border:none;border-radius:var(--radius);cursor:pointer;transition:all .15s;outline:none;letter-spacing:.5px}
.btn-primary{background:var(--accent);color:#0a0e17}
.btn-primary:hover{background:#2ee89a;transform:translateY(-1px);box-shadow:0 6px 24px rgba(34,214,138,.3)}
.btn-primary:active{transform:translateY(0)}
.btn-ghost{background:transparent;color:var(--text2);border:1px solid var(--bg4)}
.btn-ghost:hover{border-color:var(--text2);color:var(--text)}
/* TOPIC SELECT */
.topic-title{font-family:var(--mono);font-size:11px;letter-spacing:2px;text-transform:uppercase;color:var(--text3);margin-bottom:16px}
.topic-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:24px}
.topic-card{background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);padding:16px;cursor:pointer;transition:all .2s;text-align:left}
.topic-card:hover{border-color:var(--accent);background:var(--bg3)}
.topic-card.selected{border-color:var(--accent);background:rgba(34,214,138,.08)}
.topic-card .tc-icon{font-size:22px;margin-bottom:8px}
.topic-card .tc-name{font-size:14px;font-weight:600;margin-bottom:2px}
.topic-card .tc-desc{font-size:11px;color:var(--text2);line-height:1.4}
/* ROUND INTRO */
.round-intro{align-items:center;justify-content:center;text-align:center}
.ri-num{font-family:var(--mono);font-size:12px;color:var(--accent);letter-spacing:3px;text-transform:uppercase;margin-bottom:8px}
.ri-name{font-size:32px;font-weight:700;margin-bottom:8px}
.ri-desc{font-size:14px;color:var(--text2);max-width:400px;line-height:1.6;margin-bottom:8px}
.ri-meta{display:flex;gap:12px;justify-content:center;margin-bottom:32px}
.ri-pill{font-family:var(--mono);font-size:11px;padding:5px 12px;border-radius:20px;background:var(--bg3);color:var(--text2)}
.ri-countdown{font-family:var(--mono);font-size:60px;font-weight:700;color:var(--accent);animation:count-pop .5s ease}
@keyframes count-pop{0%{transform:scale(1.5);opacity:0}100%{transform:scale(1);opacity:1}}
/* QUESTION */
.q-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;flex-shrink:0}
.q-round-info{display:flex;align-items:center;gap:12px}
.q-round-label{font-family:var(--mono);font-size:11px;color:var(--accent);letter-spacing:1px}
.q-counter{font-family:var(--mono);font-size:11px;color:var(--text3)}
.q-timer{font-family:var(--mono);font-size:16px;font-weight:700;display:flex;align-items:center;gap:6px}
.q-timer.urgent{color:var(--danger);animation:timer-pulse .5s ease infinite}
@keyframes timer-pulse{0%,100%{opacity:1}50%{opacity:.5}}
.q-score-row{display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;flex-shrink:0}
.q-score{font-family:var(--mono);font-size:13px;color:var(--text2)}
.q-score b{color:var(--accent);font-weight:700}
.q-streak{font-family:var(--mono);font-size:12px;color:var(--warn);display:flex;align-items:center;gap:4px}
.q-streak.active{animation:streak-glow .6s ease infinite alternate}
@keyframes streak-glow{0%{text-shadow:0 0 8px rgba(239,159,39,.3)}100%{text-shadow:0 0 16px rgba(239,159,39,.6)}}
.q-progress{height:3px;background:var(--bg3);border-radius:2px;margin-bottom:20px;flex-shrink:0}
.q-progress-fill{height:100%;background:var(--accent);border-radius:2px;transition:width .3s}
.q-passage{background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);padding:16px;font-size:13px;line-height:1.8;color:var(--text2);margin-bottom:16px;max-height:140px;overflow-y:auto;flex-shrink:0}
.q-passage b,.q-passage strong{color:var(--accent);font-weight:600;font-style:normal}
.q-passage .blank{display:inline-block;min-width:80px;border-bottom:2px dashed var(--accent);color:var(--accent);font-weight:600;text-align:center;padding:0 4px}
.q-text{font-size:16px;font-weight:500;line-height:1.6;margin-bottom:20px;flex-shrink:0}
.q-opts{display:flex;flex-direction:column;gap:8px;flex-shrink:0}
.q-opt{background:var(--bg2);border:1px solid var(--bg3);border-radius:var(--radius);padding:14px 16px;font-size:14px;cursor:pointer;transition:all .15s;display:flex;align-items:flex-start;gap:12px;line-height:1.5}
.q-opt:hover:not(.disabled){border-color:var(--accent);background:var(--bg3)}
.q-opt.disabled{cursor:default}
.q-opt.correct{border-color:var(--success);background:rgba(34,214,138,.1)}
.q-opt.wrong{border-color:var(--danger);background:rgba(226,75,74,.1)}
.q-opt-key{font-family:var(--mono);font-size:11px;min-width:22px;height:22px;display:flex;align-items:center;justify-content:center;border-radius:5px;background:var(--bg4);color:var(--text2);flex-shrink:0;margin-top:1px}
.q-opt.correct .q-opt-key{background:var(--success);color:var(--bg)}
.q-opt.wrong .q-opt-key{background:var(--danger);color:#fff}
.q-feedback{margin-top:12px;padding:12px 14px;border-radius:var(--radius);font-size:13px;line-height:1.5;display:none;flex-shrink:0}
.q-feedback.show{display:block}
.q-feedback.correct-fb{background:rgba(34,214,138,.1);border:1px solid rgba(34,214,138,.2);color:var(--success)}
.q-feedback.wrong-fb{background:rgba(226,75,74,.1);border:1px solid rgba(226,75,74,.2);color:#f09595}
.q-points{font-family:var(--mono);font-size:20px;font-weight:700;color:var(--accent);text-align:center;margin-top:8px;opacity:0;transition:opacity .3s}
.q-points.show{opacity:1;animation:pts-pop .4s ease}
@keyframes pts-pop{0%{transform:scale(1.4);opacity:0}100%{transform:scale(1);opacity:1}}
/* ROUND SUMMARY */
.rs{align-items:center;justify-content:center;text-align:center}
.rs-title{font-family:var(--mono);font-size:12px;color:var(--accent);letter-spacing:2px;text-transform:uppercase;margin-bottom:8px}
.rs-score{font-family:var(--mono);font-size:48px;font-weight:700;margin-bottom:4px}
.rs-sub{font-size:14px;color:var(--text2);margin-bottom:24px}
.rs-stats{display:grid;grid-template-columns:1fr 1fr 1fr;gap:12px;margin-bottom:32px;width:100%;max-width:360px}
.rs-stat{background:var(--bg2);border-radius:var(--radius);padding:14px;text-align:center}
.rs-stat-val{font-family:var(--mono);font-size:22px;font-weight:700}
.rs-stat-label{font-size:11px;color:var(--text2);margin-top:2px}
/* FINAL RESULTS */
.final{align-items:center;text-align:center;padding-top:32px}
.final-badge{width:72px;height:72px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin-bottom:16px;font-size:32px}
.final-badge.s{background:linear-gradient(135deg,#ffd700,#ffaa00);box-shadow:0 0 40px rgba(255,215,0,.3)}
.final-badge.a{background:linear-gradient(135deg,#22d68a,#1ba8e0);box-shadow:0 0 40px rgba(34,214,138,.3)}
.final-badge.b{background:linear-gradient(135deg,#1ba8e0,#7f77dd);box-shadow:0 0 30px rgba(27,168,224,.2)}
.final-badge.c{background:linear-gradient(135deg,#8b93a7,#525b6f)}
.final h2{font-size:28px;font-weight:700;margin-bottom:4px}
.final .final-score{font-family:var(--mono);font-size:42px;font-weight:700;color:var(--accent);margin-bottom:4px}
.final .final-max{font-size:13px;color:var(--text3);margin-bottom:24px}
.final-breakdown{width:100%;max-width:420px;margin-bottom:24px}
.fb-row{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--bg3)}
.fb-row:last-child{border:none}
.fb-rnum{font-family:var(--mono);font-size:11px;color:var(--text3);min-width:24px}
.fb-rname{font-size:13px;font-weight:500;flex:1;text-align:left}
.fb-rscore{font-family:var(--mono);font-size:13px;color:var(--accent)}
.fb-rcorrect{font-family:var(--mono);font-size:11px;color:var(--text3);min-width:40px;text-align:right}
.final-actions{display:flex;gap:12px;margin-top:8px}
/* SCANLINES */
.scanlines{position:fixed;inset:0;pointer-events:none;z-index:99;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(0,0,0,.03) 2px,rgba(0,0,0,.03) 4px)}
/* SCORE POPUP */
.score-popup{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);font-family:var(--mono);font-size:28px;font-weight:700;color:var(--accent);pointer-events:none;z-index:200;opacity:0}
.score-popup.show{animation:score-fly .8s ease forwards}
@keyframes score-fly{0%{opacity:1;transform:translate(-50%,-50%) scale(1.3)}60%{opacity:1;transform:translate(-50%,-70%) scale(1)}100%{opacity:0;transform:translate(-50%,-90%) scale(.9)}}
/* COMBO */
.combo-display{position:fixed;top:20%;right:10%;font-family:var(--mono);font-weight:700;pointer-events:none;z-index:200;opacity:0;text-align:center}
.combo-display.show{animation:combo-in .6s ease forwards}
@keyframes combo-in{0%{opacity:0;transform:scale(2) rotate(-5deg)}40%{opacity:1;transform:scale(1) rotate(0)}100%{opacity:0;transform:scale(.8) translateY(-30px)}}
.combo-num{font-size:36px;color:var(--warn)}
.combo-label{font-size:12px;color:var(--warn);letter-spacing:2px}
/* Keyboard hints */
.key-hint{position:fixed;bottom:16px;left:50%;transform:translateX(-50%);font-family:var(--mono);font-size:11px;color:var(--text3);z-index:50;display:flex;gap:16px}
.key-hint span{display:flex;align-items:center;gap:4px}
.key-hint kbd{background:var(--bg3);padding:2px 6px;border-radius:4px;font-size:10px}
</style>
</head>
<body>
<div class="scanlines"></div>
<canvas id="particles"></canvas>
<div class="game" id="game">
<!-- SPLASH -->
<div class="screen splash active" id="screen-splash">
<div class="splash-logo">
<svg viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
</div>
<h1>UP<span>LINK</span></h1>
<div class="tagline">Engineering English Challenge</div>
<button class="btn btn-primary" onclick="showScreen('screen-topics')">Start Mission</button>
<div style="margin-top:16px;font-size:12px;color:var(--text3)">Singleplayer quiz &middot; 5 rounds &middot; ~8 min</div>
</div>
<!-- TOPICS -->
<div class="screen" id="screen-topics">
<div class="topic-title">// Select your mission field</div>
<div class="topic-grid" id="topic-grid"></div>
<button class="btn btn-primary" style="width:100%" onclick="startGame()" id="btn-start" disabled>Launch Mission</button>
</div>
<!-- ROUND INTRO -->
<div class="screen round-intro" id="screen-round-intro">
<div class="ri-num" id="ri-num"></div>
<div class="ri-name" id="ri-name"></div>
<div class="ri-desc" id="ri-desc"></div>
<div class="ri-meta" id="ri-meta"></div>
<div class="ri-countdown" id="ri-countdown"></div>
</div>
<!-- QUESTION -->
<div class="screen" id="screen-question" style="justify-content:flex-start;padding-top:16px">
<div class="q-header">
<div class="q-round-info">
<span class="q-round-label" id="q-round-label"></span>
<span class="q-counter" id="q-counter"></span>
</div>
<div class="q-timer" id="q-timer">⏱ 15</div>
</div>
<div class="q-score-row">
<div class="q-score">Score: <b id="q-score-val">0</b></div>
<div class="q-streak" id="q-streak"></div>
</div>
<div class="q-progress"><div class="q-progress-fill" id="q-progress"></div></div>
<div id="q-passage-wrap"></div>
<div class="q-text" id="q-text"></div>
<div class="q-opts" id="q-opts"></div>
<div class="q-feedback" id="q-feedback"></div>
<div class="q-points" id="q-points"></div>
</div>
<!-- ROUND SUMMARY -->
<div class="screen rs" id="screen-round-summary">
<div class="rs-title" id="rs-title"></div>
<div class="rs-score" id="rs-score"></div>
<div class="rs-sub" id="rs-sub"></div>
<div class="rs-stats" id="rs-stats"></div>
<button class="btn btn-primary" onclick="nextRound()">Next Round</button>
</div>
<!-- FINAL -->
<div class="screen final" id="screen-final">
<div class="final-badge" id="final-badge"></div>
<h2 id="final-title"></h2>
<div class="final-score" id="final-score"></div>
<div class="final-max" id="final-max"></div>
<div class="final-breakdown" id="final-breakdown"></div>
<div class="final-actions">
<button class="btn btn-primary" onclick="location.reload()">Play Again</button>
</div>
</div>
</div>
<div class="score-popup" id="score-popup"></div>
<div class="combo-display" id="combo-display">
<div class="combo-num" id="combo-num"></div>
<div class="combo-label">STREAK</div>
</div>
<script>
// ============ QUESTION DATABASE ============
const QUESTIONS = {
// ROUND 1: Term Scan - definition → pick term
term_scan: {
aero: [
{def:"An unmanned aircraft system controlled remotely or autonomously",opts:["Helicopter","Satellite","UAV (Drone)","Glider"],ans:2},
{def:"The upward force on a wing caused by differences in air pressure",opts:["Thrust","Drag","Lift","Torque"],ans:2},
{def:"The ratio of aircraft speed to the speed of sound",opts:["Reynolds number","Mach number","Knot index","Bernoulli ratio"],ans:1},
{def:"The adjustable surface on an aircraft wing that controls roll",opts:["Rudder","Flap","Aileron","Elevator"],ans:2},
{def:"A rocket engine that uses liquid hydrogen and liquid oxygen",opts:["Solid rocket booster","Cryogenic engine","Turbofan","Ramjet"],ans:1},
{def:"The point where all gravitational forces on an aircraft are balanced",opts:["Fulcrum","Center of gravity","Aerodynamic center","Neutral point"],ans:1},
],
robo: [
{def:"A sensor that measures angular velocity",opts:["Accelerometer","Gyroscope","Magnetometer","Barometer"],ans:1},
{def:"A mechanical device that converts energy into physical motion",opts:["Transducer","Capacitor","Actuator","Resistor"],ans:2},
{def:"The number of independent parameters that define a robot's configuration",opts:["Axes","Degrees of freedom","Joints","Dimensions"],ans:1},
{def:"A robotic gripper that uses vacuum suction to hold objects",opts:["Pneumatic gripper","Suction cup end-effector","Magnetic chuck","Mechanical claw"],ans:1},
{def:"A control method that adjusts output based on error feedback",opts:["Open-loop control","PID control","Binary control","Sequential logic"],ans:1},
{def:"The workspace volume a robotic arm can reach",opts:["Range","Work envelope","Motion area","Sweep zone"],ans:1},
],
ai: [
{def:"A neural network layer that identifies spatial features in images",opts:["Dense layer","Recurrent layer","Convolutional layer","Dropout layer"],ans:2},
{def:"The process of adjusting model weights by propagating errors backwards",opts:["Forward pass","Gradient descent","Backpropagation","Regularization"],ans:2},
{def:"A model that generates new data samples resembling training data",opts:["Classifier","Discriminator","Generative model","Regressor"],ans:2},
{def:"When a model performs well on training data but poorly on new data",opts:["Underfitting","Overfitting","Convergence","Normalization"],ans:1},
{def:"A technique that randomly disables neurons during training to prevent overfitting",opts:["Pruning","Batch normalization","Dropout","Weight decay"],ans:2},
{def:"A sequence-to-sequence architecture using self-attention mechanisms",opts:["CNN","RNN","Transformer","Autoencoder"],ans:2},
],
cyber: [
{def:"Malicious software that encrypts files and demands payment for decryption",opts:["Trojan","Spyware","Ransomware","Adware"],ans:2},
{def:"A network security system that monitors and filters incoming traffic",opts:["Router","Firewall","Load balancer","DNS server"],ans:1},
{def:"An attack that floods a server with traffic to make it unavailable",opts:["Phishing","SQL injection","DDoS attack","Man-in-the-middle"],ans:2},
{def:"A cryptographic function that converts data into a fixed-size hash value",opts:["Encryption key","Hash function","Digital signature","Certificate"],ans:1},
{def:"A test that simulates an attack to find system vulnerabilities",opts:["Code review","Penetration test","Unit test","Stress test"],ans:1},
{def:"A security protocol that establishes an encrypted link between server and client",opts:["HTTP","FTP","TLS/SSL","SMTP"],ans:2},
],
embed: [
{def:"A small computer on a single integrated circuit for specific tasks",opts:["GPU","FPGA","Microcontroller","Mainframe"],ans:2},
{def:"A communication protocol using two wires: SDA (data) and SCL (clock)",opts:["SPI","I2C","UART","CAN bus"],ans:1},
{def:"A type of memory that retains data without power",opts:["SRAM","DRAM","Flash memory","Cache"],ans:2},
{def:"An operating system designed for real-time application constraints",opts:["Linux","RTOS","Windows CE","Android"],ans:1},
{def:"A technique to reduce processor power consumption in idle states",opts:["Overclocking","Sleep mode","Pipelining","Caching"],ans:1},
{def:"A hardware description language for designing digital circuits",opts:["Python","VHDL","Assembly","MATLAB"],ans:1},
],
net: [
{def:"A protocol that assigns IP addresses to devices automatically",opts:["DNS","DHCP","ARP","ICMP"],ans:1},
{def:"A virtual private network that creates an encrypted tunnel over the internet",opts:["LAN","WAN","VPN","CDN"],ans:2},
{def:"The process of distributing network traffic across multiple servers",opts:["Routing","Load balancing","Caching","Bridging"],ans:1},
{def:"A containerization platform for deploying applications in isolated environments",opts:["Kubernetes","Docker","Vagrant","Ansible"],ans:1},
{def:"A lightweight data interchange format using key-value pairs",opts:["XML","YAML","JSON","CSV"],ans:2},
{def:"An architectural style for designing networked applications using HTTP methods",opts:["SOAP","GraphQL","REST API","gRPC"],ans:2},
],
},
// ROUND 2: Debug the Doc - cloze/fill-in-blank
debug_doc: {
aero: [
{passage:"The aircraft's ______ system detected windshear at 500ft. The autopilot immediately increased ______ to maintain altitude.",blanks:["TAWS / thrust","GPS / drag","ATC / lift"],ans:0},
{passage:"During re-entry, the spacecraft's ______ shield protects against temperatures exceeding 1,600°C caused by atmospheric ______.",blanks:["thermal / friction","radiation / pressure","magnetic / gravity"],ans:0},
{passage:"The ______ ratio of the wing determines its aerodynamic efficiency. Higher values reduce induced ______ at cruise speeds.",blanks:["aspect / drag","pressure / thrust","sweep / lift"],ans:0},
],
robo: [
{passage:"The robot's ______ detected an obstacle at 2.3 meters. The control system triggered an emergency stop by disabling the ______.",blanks:["LiDAR sensor / actuator","GPS module / transistor","camera / capacitor"],ans:0},
{passage:"The ______ algorithm calculates the optimal joint angles needed for the end-effector to reach the target ______.",blanks:["inverse kinematics / position","pathfinding / velocity","PID / torque"],ans:0},
{passage:"The collaborative robot uses ______ sensors in its joints to detect unexpected contact and limit applied ______ to safe levels.",blanks:["force-torque / force","optical / speed","thermal / voltage"],ans:0},
],
ai: [
{passage:"The ______ function maps the weighted sum of inputs to an output, introducing ______ into the neural network.",blanks:["activation / non-linearity","loss / accuracy","cost / bias"],ans:0},
{passage:"During training, the ______ rate determines how much the weights are updated in each iteration of gradient ______.",blanks:["learning / descent","dropout / ascent","batch / propagation"],ans:0},
{passage:"The model uses ______ to convert words into dense vector representations, capturing semantic ______ between terms.",blanks:["embeddings / similarity","tokenization / frequency","hashing / distance"],ans:0},
],
cyber: [
{passage:"The ______ attack exploited an unpatched vulnerability in the web server's input ______ mechanism.",blanks:["SQL injection / validation","brute-force / encryption","phishing / authentication"],ans:0},
{passage:"The security team implemented ______ authentication, requiring both a password and a time-based ______ code.",blanks:["multi-factor / one-time","single / permanent","biometric / session"],ans:0},
{passage:"The ______ certificate expired, causing browsers to display warnings about the site's ______ not being verified.",blanks:["TLS / identity","DNS / location","HTTP / content"],ans:0},
],
embed: [
{passage:"The ______ converter samples the analog signal at 12-bit resolution, providing ______ discrete voltage levels.",blanks:["ADC / 4096","DAC / 256","PWM / 1024"],ans:0},
{passage:"The ______ handles time-critical tasks with guaranteed response times, unlike general-purpose operating systems that use ______ scheduling.",blanks:["RTOS / preemptive","BIOS / cooperative","kernel / random"],ans:0},
{passage:"The microcontroller communicates with the sensor via the ______ bus, using a master-slave ______ to synchronize data transfer.",blanks:["I2C / protocol","USB / interface","GPIO / standard"],ans:0},
],
net: [
{passage:"The ______ server translates human-readable domain names into ______ addresses that computers use to identify each other.",blanks:["DNS / IP","DHCP / MAC","proxy / port"],ans:0},
{passage:"The ______ orchestration platform automatically scales containerized applications based on CPU ______ and memory usage.",blanks:["Kubernetes / utilization","Docker / frequency","Terraform / allocation"],ans:0},
{passage:"The CDN caches static ______ at edge servers located geographically close to end users, reducing ______.",blanks:["assets / latency","packets / bandwidth","queries / throughput"],ans:0},
],
},
// ROUND 3: Mission Brief - reading comprehension
mission_brief: {
aero: [
{text:"The Ingenuity helicopter completed its 50th flight on Mars, covering 1.2km at an altitude of 12 meters. The rotorcraft operates in an atmosphere with 1% of Earth's density, requiring blade speeds of 2,400 RPM — five times faster than a terrestrial helicopter. Despite being designed for only five flights, the engineering team extended the mission by uploading firmware updates.",q:"Why must Ingenuity's blades spin five times faster than Earth helicopters?",opts:["The gravity on Mars is stronger","Mars has much thinner atmosphere","The helicopter carries heavy equipment","NASA required higher speeds for safety"],ans:1},
{text:"The new hypersonic vehicle achieved Mach 5.1 during a 20-second sustained flight at 65,000 feet. Unlike traditional jet engines, the scramjet compresses incoming air without mechanical components — the vehicle's speed itself forces air into the combustion chamber. However, ignition below Mach 4 is impossible, requiring a rocket booster for initial acceleration.",q:"What is the main limitation of a scramjet engine?",opts:["It cannot fly above 60,000 feet","It cannot ignite without already moving at high speed","It requires mechanical compressors","It only works in thin atmosphere"],ans:1},
],
robo: [
{text:"Boston Dynamics' Atlas robot uses model predictive control (MPC) to plan movements 0.5 seconds ahead. The system evaluates thousands of potential trajectories per second, selecting the one that minimizes energy expenditure while maintaining balance. Each joint contains a custom hydraulic actuator capable of generating 40 Nm of torque, giving Atlas the power-to-weight ratio needed for dynamic maneuvers like backflips.",q:"How does Atlas plan its movements according to the text?",opts:["It reacts to balance changes in real-time only","It evaluates thousands of future trajectories and picks the most efficient","It uses pre-programmed movement sequences","It copies human movements captured by sensors"],ans:1},
{text:"Surgical robots achieve sub-millimeter precision by using a combination of force feedback and tremor filtering. The system scales the surgeon's hand movements by a ratio of 5:1 — a 5mm hand movement translates to 1mm at the instrument tip. Additionally, high-frequency tremors above 6 Hz are algorithmically removed, allowing procedures that would be impossible with unassisted human hands.",q:"What does the 5:1 scaling ratio achieve?",opts:["It speeds up the surgery by 5 times","It amplifies the surgeon's movements","It reduces the surgeon's movements to much smaller, precise motions","It filters out 5 types of tremor"],ans:2},
],
ai: [
{text:"Researchers discovered that large language models develop emergent abilities at certain scale thresholds. A model with 10 billion parameters could not perform multi-step arithmetic, but the same architecture with 100 billion parameters solved these problems with 80% accuracy — without being explicitly trained on arithmetic. This suggests that scale itself can unlock qualitatively new capabilities, though the exact mechanism remains poorly understood.",q:"What is the key finding about emergent abilities?",opts:["Larger models are always more accurate","Certain capabilities appear suddenly when models reach sufficient scale","Arithmetic training is unnecessary for all models","10 billion parameters is too few for any useful task"],ans:1},
{text:"The attention mechanism allows a transformer to weigh the relevance of every input token against every other token. For a sequence of 1,000 tokens, this creates a 1,000×1,000 attention matrix — one million values computed per layer. This quadratic scaling is why processing very long documents remains computationally expensive, and why researchers are developing linear attention alternatives.",q:"Why is processing long documents expensive for transformers?",opts:["Long documents have more complex vocabulary","The attention computation grows quadratically with sequence length","Transformers can only handle 1,000 tokens","Each layer needs a separate GPU"],ans:1},
],
cyber: [
{text:"A zero-day exploit targeting the VPN gateway was detected when the intrusion detection system flagged anomalous outbound traffic at 3 AM. The attackers had obtained initial access through a compromised employee credential purchased on a dark web forum. Post-exploitation analysis revealed they had maintained persistent access for 11 days, exfiltrating 2.3 TB of data through encrypted DNS tunneling — a technique that hides data inside DNS query responses.",q:"How did the attackers initially gain access to the system?",opts:["They exploited a zero-day vulnerability in the VPN","They used a stolen employee credential","They broke the DNS encryption","They hacked the intrusion detection system"],ans:1},
],
embed: [
{text:"The new RISC-V microcontroller achieves 3.2 CoreMark/MHz while consuming only 45 μA/MHz in active mode. Its power management unit supports five distinct power states, from full-speed operation at 1.8V down to a deep sleep mode drawing just 120 nA with RTC and 8KB of retained SRAM. The chip targets battery-powered IoT sensors expected to operate for 10+ years on a single coin cell.",q:"What enables the chip to run for 10+ years on a coin cell battery?",opts:["Its high processing speed","Its extremely low power consumption across multiple sleep states","The large amount of retained SRAM","The high voltage operation at 1.8V"],ans:1},
],
net: [
{text:"The microservices architecture replaced the monolithic application, splitting it into 47 independent services communicating via gRPC. Each service owns its database, eliminating shared state. Deployment frequency increased from monthly to 200+ times per day. However, distributed tracing became essential — a single user request now traverses an average of 12 services, making debugging failures significantly more complex.",q:"What new challenge arose from the microservices migration?",opts:["Services could no longer share databases","Deployment frequency dropped significantly","Debugging became harder because requests span many services","gRPC proved too slow for inter-service communication"],ans:2},
],
},
// ROUND 4: Command Line - communication
command_line: {
aero: [
{situation:"You're presenting a flight test report. A reviewer asks: 'Why did the altitude readings fluctuate during the climb phase?'",opts:["'I don't know, the sensors were probably broken.'","'The fluctuations correlate with turbulence events recorded by the IMU. We've cross-referenced with weather data and confirmed moderate CAT at FL280.'","'That's not my department, ask the avionics team.'"],ans:1},
],
robo: [
{situation:"Your team lead asks in a standup: 'Any blockers on the navigation module?' You found a bug in the pathfinding algorithm yesterday.",opts:["'No, everything's fine.'","'Yes, I identified a bug in the A* implementation — the heuristic isn't admissible, causing suboptimal paths. I'll need about half a day to fix and retest.'","'The code is broken, I can't do anything.'"],ans:1},
{situation:"A client asks: 'Can your robot handle objects heavier than 5kg?' Your robot's max payload is 3kg.",opts:["'Sure, we can probably make it work.'","'Currently our end-effector is rated for 3kg. We could upgrade to a heavier-duty actuator, but that would affect cycle time. Would you like me to spec out the tradeoffs?'","'No, it cannot. You need a different robot.'"],ans:1},
],
ai: [
{situation:"A non-technical manager asks: 'Why can't we just use AI to replace all our customer service agents by next month?'",opts:["'That's technically impossible, AI can't do that.'","'AI can handle routine queries effectively — we're seeing 70% automation rates in similar deployments. However, a phased rollout with human oversight would reduce risk. I'd suggest starting with FAQ automation and measuring CSAT scores before expanding.'","'Sure, we can probably do that if we start immediately.'"],ans:1},
{situation:"During code review, your colleague's ML pipeline has a data leakage issue — test data is being used during feature scaling.",opts:["'This code is wrong, you should know better.'","'I noticed the StandardScaler is fit on the full dataset before the train-test split. This introduces data leakage — the test set statistics influence the training features. If we move the fit_transform inside the cross-validation loop, we'll get more reliable validation scores.'","'Looks good to me, approved.'"],ans:1},
],
cyber: [
{situation:"A colleague sends you a Slack message: 'Hey, I need admin access to the production database for a quick fix. Can you share the credentials?'",opts:["'Sure, here are the credentials: admin/[password].'","'I can't share credentials directly — that would violate our access control policy. You can request temporary elevated access through the IAM portal, which logs the session for audit compliance. Want me to walk you through the process?'","'No, I don't trust you with that.'"],ans:1},
],
embed: [
{situation:"Your professor asks why your embedded system prototype keeps crashing intermittently during the demo.",opts:["'I have no idea, it worked fine in the lab.'","'We're seeing a stack overflow in the interrupt service routine. The ISR is calling a function that allocates a large local buffer — we need to refactor it to use a statically allocated buffer and defer processing to the main loop.'","'The hardware is faulty, we need a new board.'"],ans:1},
],
net: [
{situation:"During a meeting, someone proposes storing user passwords in plaintext 'to simplify the login system.'",opts:["'That sounds like a reasonable approach for now.'","'Plaintext storage would expose all user accounts if we're ever breached. Using bcrypt with a work factor of 12 adds minimal latency — about 250ms per hash — but makes credential theft computationally infeasible. It's an industry standard and most frameworks support it out of the box.'","'That's the dumbest idea I've ever heard.'"],ans:1},
],
},
};
// ============ ROUND CONFIG ============
const ROUNDS = [
{id:"term_scan",name:"Term Scan",desc:"Match the definition to the correct technical term.",time:15,qs:5,pills:["vocabulary","15s / question"],color:"var(--accent2)"},
{id:"debug_doc",name:"Debug the Doc",desc:"Fill in the missing terms in technical documentation.",time:25,qs:5,pills:["reading","vocabulary","25s / question"],color:"var(--accent)"},
{id:"mission_brief",name:"Mission Brief",desc:"Read technical passages and answer comprehension questions.",time:40,qs:4,pills:["comprehension","40s / question"],color:"#7f77dd"},
{id:"command_line",name:"Command Line",desc:"Choose the most appropriate professional response.",time:25,qs:4,pills:["communication","25s / question"],color:"var(--warn)"},
{id:"system_override",name:"System Override",desc:"Boss round — all skills mixed, shorter time, higher stakes!",time:12,qs:6,pills:["all skills","12s / question","×2 points"],color:"var(--danger)"},
];
const TOPICS = [
{id:"aero",icon:"✈️",name:"Aeronautics & Space",desc:"Flight, spacecraft, navigation"},
{id:"robo",icon:"🤖",name:"Robotics & Automation",desc:"Sensors, actuators, control"},
{id:"ai",icon:"🧠",name:"AI & Machine Learning",desc:"Neural nets, training, models"},
{id:"cyber",icon:"🔒",name:"Cybersecurity",desc:"Threats, protocols, defense"},
{id:"embed",icon:"⚡",name:"Embedded Systems",desc:"MCUs, RTOS, hardware"},
{id:"net",icon:"🌐",name:"Networking & Cloud",desc:"Protocols, servers, APIs"},
{id:"mix",icon:"🎲",name:"Random Mix",desc:"All topics combined"},
];
// ============ GAME STATE ============
let state = {
topic: null,
round: 0,
questionIdx: 0,
score: 0,
streak: 0,
maxStreak: 0,
roundScores: [],
roundCorrect: [],
roundQuestions: [],
currentQuestions: [],
timerInterval: null,
timeLeft: 0,
answered: false,
totalCorrect: 0,
totalQuestions: 0,
};
// ============ AUDIO ============
const AudioCtx = window.AudioContext || window.webkitAudioContext;
let audioCtx;
function initAudio(){if(!audioCtx)audioCtx=new AudioCtx()}
function playTone(freq,dur,type='sine',vol=.12){
if(!audioCtx)return;
const o=audioCtx.createOscillator(),g=audioCtx.createGain();
o.type=type;o.frequency.value=freq;
g.gain.setValueAtTime(vol,audioCtx.currentTime);
g.gain.exponentialRampToValueAtTime(.001,audioCtx.currentTime+dur);
o.connect(g);g.connect(audioCtx.destination);
o.start();o.stop(audioCtx.currentTime+dur);
}
function sfxCorrect(){playTone(523,.08);setTimeout(()=>playTone(659,.08),80);setTimeout(()=>playTone(784,.15),160)}
function sfxWrong(){playTone(200,.2,'sawtooth',.08)}
function sfxTick(){playTone(800,.03,'sine',.04)}
function sfxRoundStart(){playTone(440,.1);setTimeout(()=>playTone(554,.1),100);setTimeout(()=>playTone(659,.15),200)}
function sfxCombo(){playTone(880,.06);setTimeout(()=>playTone(1109,.06),60);setTimeout(()=>playTone(1319,.12),120)}
// ============ PARTICLES ============
const cvs=document.getElementById('particles');
const ctx=cvs.getContext('2d');
let parts=[];
function resizeCvs(){cvs.width=window.innerWidth;cvs.height=window.innerHeight}
window.addEventListener('resize',resizeCvs);resizeCvs();
function spawnParticles(x,y,count,color){
for(let i=0;i<count;i++){
const angle=Math.random()*Math.PI*2;
const speed=2+Math.random()*4;
parts.push({x,y,vx:Math.cos(angle)*speed,vy:Math.sin(angle)*speed,life:1,color,size:2+Math.random()*3});
}
}
function animParticles(){
ctx.clearRect(0,0,cvs.width,cvs.height);
parts=parts.filter(p=>{
p.x+=p.vx;p.y+=p.vy;p.vy+=.1;p.life-=.02;
if(p.life<=0)return false;
ctx.globalAlpha=p.life;
ctx.fillStyle=p.color;
ctx.fillRect(p.x,p.y,p.size,p.size);
return true;
});
ctx.globalAlpha=1;
requestAnimationFrame(animParticles);
}
animParticles();
// ============ SCREEN MANAGEMENT ============
function showScreen(id){
document.querySelectorAll('.screen').forEach(s=>s.classList.remove('active'));
document.getElementById(id).classList.add('active');
}
// ============ TOPICS ============
function renderTopics(){
const grid=document.getElementById('topic-grid');
grid.innerHTML=TOPICS.map(t=>`
<div class="topic-card" onclick="selectTopic('${t.id}')" id="tc-${t.id}">
<div class="tc-icon">${t.icon}</div>
<div class="tc-name">${t.name}</div>
<div class="tc-desc">${t.desc}</div>
</div>
`).join('');
}
renderTopics();
function selectTopic(id){
initAudio();
state.topic=id;
document.querySelectorAll('.topic-card').forEach(c=>c.classList.remove('selected'));
document.getElementById('tc-'+id).classList.add('selected');
document.getElementById('btn-start').disabled=false;
playTone(600,.06);
}
// ============ GET QUESTIONS ============
function getTopicKeys(){
if(state.topic==='mix') return ['aero','robo','ai','cyber','embed','net'];
return [state.topic];
}
function pickQuestions(roundId, count){
const topics=getTopicKeys();
let pool=[];
const qBank = QUESTIONS[roundId] || {};
topics.forEach(t=>{if(qBank[t])pool.push(...qBank[t])});
// shuffle
for(let i=pool.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[pool[i],pool[j]]=[pool[j],pool[i]]}
return pool.slice(0, Math.min(count, pool.length));
}
function pickSystemOverrideQuestions(count){
const topics=getTopicKeys();
let pool=[];
// Grab from all round types
['term_scan','debug_doc','mission_brief','command_line'].forEach(roundId=>{
const qBank=QUESTIONS[roundId]||{};
topics.forEach(t=>{if(qBank[t])pool.push(...qBank[t].map(q=>({...q,_type:roundId})))});
});
for(let i=pool.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[pool[i],pool[j]]=[pool[j],pool[i]]}
return pool.slice(0,Math.min(count,pool.length));
}
// ============ START GAME ============
function startGame(){
state.round=0;
state.score=0;
state.streak=0;
state.maxStreak=0;
state.roundScores=[];
state.roundCorrect=[];
state.roundQuestions=[];
state.totalCorrect=0;
state.totalQuestions=0;
sfxRoundStart();
showRoundIntro();
}
// ============ ROUND INTRO ============
function showRoundIntro(){
const r=ROUNDS[state.round];
document.getElementById('ri-num').textContent=`ROUND 0${state.round+1}${state.round===4?' — BOSS ROUND':''}`;
document.getElementById('ri-name').textContent=r.name;
document.getElementById('ri-desc').textContent=r.desc;
document.getElementById('ri-meta').innerHTML=r.pills.map(p=>`<span class="ri-pill">${p}</span>`).join('');
showScreen('screen-round-intro');
let count=3;
const cdEl=document.getElementById('ri-countdown');
cdEl.textContent=count;
sfxTick();
const cdInt=setInterval(()=>{
count--;
if(count>0){cdEl.textContent=count;sfxTick();}
else{
clearInterval(cdInt);
cdEl.textContent='GO!';
sfxRoundStart();
setTimeout(()=>startRound(),400);
}
},800);
}
// ============ START ROUND ============
function startRound(){
const r=ROUNDS[state.round];
if(r.id==='system_override'){
state.currentQuestions=pickSystemOverrideQuestions(r.qs);
} else {
state.currentQuestions=pickQuestions(r.id, r.qs);
}
state.questionIdx=0;
state.roundScores.push(0);
state.roundCorrect.push(0);
state.roundQuestions.push(state.currentQuestions.length);
showQuestion();
}
// ============ SHOW QUESTION ============
function showQuestion(){
const r=ROUNDS[state.round];
const q=state.currentQuestions[state.questionIdx];
if(!q){showRoundSummary();return;}
state.answered=false;
const isOverride=r.id==='system_override';
const qType=isOverride?(q._type||'term_scan'):r.id;
const timeLimit=isOverride?r.time:r.time;
// Header
document.getElementById('q-round-label').textContent=`R${state.round+1} · ${isOverride?getTypeName(qType):r.name}`;
document.getElementById('q-counter').textContent=`${state.questionIdx+1} / ${state.currentQuestions.length}`;
document.getElementById('q-score-val').textContent=state.score;
// Streak
updateStreakDisplay();
// Progress
document.getElementById('q-progress').style.width=((state.questionIdx/state.currentQuestions.length)*100)+'%';
// Build question content based on type
const passWrap=document.getElementById('q-passage-wrap');
const qText=document.getElementById('q-text');
const qOpts=document.getElementById('q-opts');
const feedback=document.getElementById('q-feedback');
const pts=document.getElementById('q-points');
passWrap.innerHTML='';
feedback.className='q-feedback';
feedback.style.display='none';
pts.className='q-points';
pts.textContent='';
if(qType==='term_scan'){
qText.textContent=q.def;
qOpts.innerHTML=q.opts.map((o,i)=>`
<div class="q-opt" onclick="answer(${i},${q.ans},'${qType}')">
<span class="q-opt-key">${String.fromCharCode(65+i)}</span>${o}
</div>`).join('');
}
else if(qType==='debug_doc'){
passWrap.innerHTML=`<div class="q-passage">${formatPassage(q.passage)}</div>`;
qText.textContent='Select the correct terms to fill the blanks:';
qOpts.innerHTML=q.blanks.map((b,i)=>`
<div class="q-opt" onclick="answer(${i},${q.ans},'${qType}')">
<span class="q-opt-key">${String.fromCharCode(65+i)}</span>${b}
</div>`).join('');
}
else if(qType==='mission_brief'){
passWrap.innerHTML=`<div class="q-passage">${q.text}</div>`;
qText.textContent=q.q;
qOpts.innerHTML=q.opts.map((o,i)=>`
<div class="q-opt" onclick="answer(${i},${q.ans},'${qType}')">
<span class="q-opt-key">${String.fromCharCode(65+i)}</span>${o}
</div>`).join('');
}
else if(qType==='command_line'){
passWrap.innerHTML=`<div class="q-passage" style="font-style:normal"><strong>Situation:</strong> ${q.situation}</div>`;
qText.textContent='Choose the most appropriate response:';
qOpts.innerHTML=q.opts.map((o,i)=>`
<div class="q-opt" onclick="answer(${i},${q.ans},'${qType}')">
<span class="q-opt-key">${String.fromCharCode(65+i)}</span>${o}
</div>`).join('');
}
// Timer
state.timeLeft=timeLimit;
updateTimerDisplay();
clearInterval(state.timerInterval);
state.timerInterval=setInterval(()=>{
state.timeLeft--;
updateTimerDisplay();
if(state.timeLeft<=5&&state.timeLeft>0)sfxTick();
if(state.timeLeft<=0){
clearInterval(state.timerInterval);
timeUp();
}
},1000);
showScreen('screen-question');
}
function getTypeName(t){
const m={term_scan:'Term Scan',debug_doc:'Debug Doc',mission_brief:'Mission Brief',command_line:'Command Line'};
return m[t]||t;
}
function formatPassage(text){
return text.replace(/______/g,'<span class="blank">???</span>');
}
function updateTimerDisplay(){
const el=document.getElementById('q-timer');
el.textContent='⏱ '+state.timeLeft+'s';
el.classList.toggle('urgent',state.timeLeft<=5);
}
function updateStreakDisplay(){
const el=document.getElementById('q-streak');
if(state.streak>=3){
const mult=state.streak>=7?'×3.0':state.streak>=5?'×2.0':'×1.5';
el.textContent='🔥 '+state.streak+' streak '+mult;
el.classList.add('active');
} else {
el.textContent=state.streak>0?'🔥 '+state.streak:'';
el.classList.remove('active');
}
}
// ============ ANSWER ============
function answer(picked, correct, qType){
if(state.answered)return;
state.answered=true;
clearInterval(state.timerInterval);
const opts=document.querySelectorAll('#q-opts .q-opt');
opts.forEach((o,i)=>{
o.classList.add('disabled');
if(i===correct)o.classList.add('correct');
if(i===picked&&picked!==correct)o.classList.add('wrong');
});
const isCorrect=picked===correct;
const feedback=document.getElementById('q-feedback');
const pts=document.getElementById('q-points');
const r=ROUNDS[state.round];
const isOverride=r.id==='system_override';
if(isCorrect){
state.streak++;
if(state.streak>state.maxStreak)state.maxStreak=state.streak;
state.roundCorrect[state.round]++;
state.totalCorrect++;
// Calculate points
let points=100;
if(isOverride)points=200;
// Speed bonus
const timeRatio=state.timeLeft/(isOverride?r.time:r.time);
if(timeRatio>.5)points=Math.round(points*1.5);
// Streak bonus
if(state.streak>=7)points=Math.round(points*3);
else if(state.streak>=5)points=Math.round(points*2);
else if(state.streak>=3)points=Math.round(points*1.5);
state.score+=points;
state.roundScores[state.round]+=points;
document.getElementById('q-score-val').textContent=state.score;
feedback.className='q-feedback show correct-fb';
feedback.textContent='✓ Correct!';
pts.textContent='+'+points;
pts.className='q-points show';
sfxCorrect();
// Particles
const rect=opts[correct].getBoundingClientRect();
spawnParticles(rect.left+rect.width/2,rect.top,20,'#22d68a');
// Show score popup
showScorePopup('+'+points);
// Combo display
if(state.streak>=3){
sfxCombo();
showCombo(state.streak);
}
} else {
state.streak=0;
feedback.className='q-feedback show wrong-fb';
feedback.textContent='✗ Incorrect. The correct answer is highlighted above.';
sfxWrong();
}
state.totalQuestions++;
updateStreakDisplay();
// Auto-advance
setTimeout(()=>{
state.questionIdx++;
if(state.questionIdx<state.currentQuestions.length){
showQuestion();
} else {
showRoundSummary();
}
},2000);
}
function timeUp(){
if(state.answered)return;
state.answered=true;
state.streak=0;
state.totalQuestions++;
updateStreakDisplay();
const q=state.currentQuestions[state.questionIdx];
const r=ROUNDS[state.round];
const isOverride=r.id==='system_override';
const qType=isOverride?(q._type||'term_scan'):r.id;
const correct=q.ans;
const opts=document.querySelectorAll('#q-opts .q-opt');
opts.forEach((o,i)=>{
o.classList.add('disabled');
if(i===correct)o.classList.add('correct');
});
const feedback=document.getElementById('q-feedback');
feedback.className='q-feedback show wrong-fb';
feedback.textContent='⏱ Time\'s up! The correct answer is highlighted above.';
sfxWrong();
setTimeout(()=>{
state.questionIdx++;
if(state.questionIdx<state.currentQuestions.length){
showQuestion();
} else {
showRoundSummary();
}
},2000);
}
// ============ POPUPS ============
function showScorePopup(text){
const el=document.getElementById('score-popup');
el.textContent=text;
el.className='score-popup show';
setTimeout(()=>el.className='score-popup',800);
}
function showCombo(n){
const el=document.getElementById('combo-display');
document.getElementById('combo-num').textContent=n+'×';
el.className='combo-display show';
setTimeout(()=>el.className='combo-display',700);
}
// ============ ROUND SUMMARY ============
function showRoundSummary(){
clearInterval(state.timerInterval);
const r=ROUNDS[state.round];
const correct=state.roundCorrect[state.round];
const total=state.roundQuestions[state.round];
const score=state.roundScores[state.round];
document.getElementById('rs-title').textContent=`ROUND ${state.round+1} COMPLETE`;
document.getElementById('rs-score').textContent=score+' pts';
const pct=total>0?Math.round((correct/total)*100):0;
document.getElementById('rs-sub').textContent=pct>=80?'Excellent performance!':pct>=60?'Good work, keep going!':'Room for improvement.';
document.getElementById('rs-stats').innerHTML=`
<div class="rs-stat"><div class="rs-stat-val" style="color:var(--success)">${correct}/${total}</div><div class="rs-stat-label">Correct</div></div>
<div class="rs-stat"><div class="rs-stat-val" style="color:var(--warn)">${state.maxStreak}</div><div class="rs-stat-label">Best Streak</div></div>
<div class="rs-stat"><div class="rs-stat-val">${state.score}</div><div class="rs-stat-label">Total Score</div></div>
`;
// Change button text for last round
const btn=document.querySelector('#screen-round-summary .btn');
btn.textContent=state.round>=ROUNDS.length-1?'See Results':'Next Round';
showScreen('screen-round-summary');
}
function nextRound(){
state.round++;
if(state.round>=ROUNDS.length){
showFinalResults();
} else {
sfxRoundStart();
showRoundIntro();
}
}
// ============ FINAL RESULTS ============
function showFinalResults(){
const pct=state.totalQuestions>0?Math.round((state.totalCorrect/state.totalQuestions)*100):0;
let grade,emoji,title;
if(pct>=90){grade='s';emoji='🏆';title='Mission Accomplished!';}
else if(pct>=75){grade='a';emoji='⭐';title='Outstanding Performance!';}
else if(pct>=60){grade='b';emoji='👍';title='Good Work, Engineer!';}
else{grade='c';emoji='📡';title='Keep Training, Cadet!';}
const badge=document.getElementById('final-badge');
badge.className='final-badge '+grade;
badge.textContent=emoji;
document.getElementById('final-title').textContent=title;
document.getElementById('final-score').textContent=state.score;
const maxPossible=state.totalQuestions*450; // rough max
document.getElementById('final-max').textContent=`${state.totalCorrect}/${state.totalQuestions} correct · ${pct}% accuracy · Best streak: ${state.maxStreak}`;
let breakdown='';
ROUNDS.forEach((r,i)=>{
if(i<state.roundScores.length){
const c=state.roundCorrect[i];
const t=state.roundQuestions[i];
breakdown+=`
<div class="fb-row">
<span class="fb-rnum">R${i+1}</span>
<span class="fb-rname">${r.name}</span>
<span class="fb-rcorrect">${c}/${t}</span>
<span class="fb-rscore">${state.roundScores[i]} pts</span>
</div>`;
}
});
document.getElementById('final-breakdown').innerHTML=breakdown;
showScreen('screen-final');
// Celebration particles
if(pct>=75){
for(let i=0;i<5;i++){
setTimeout(()=>{
spawnParticles(Math.random()*window.innerWidth,Math.random()*window.innerHeight*.5,30,['#22d68a','#1ba8e0','#ef9f27','#7f77dd'][Math.floor(Math.random()*4)]);
},i*300);
}
}
}
// ============ KEYBOARD CONTROLS ============
document.addEventListener('keydown',e=>{
if(state.answered)return;
const screen=document.querySelector('.screen.active');
if(!screen||screen.id!=='screen-question')return;
const keyMap={'a':0,'b':1,'c':2,'d':3,'1':0,'2':1,'3':2,'4':3};
const idx=keyMap[e.key.toLowerCase()];
if(idx!==undefined){
const opts=document.querySelectorAll('#q-opts .q-opt');
if(opts[idx])opts[idx].click();
}
});
</script>
</body>
</html>