1 hra done
This commit is contained in:
401
x.html
Normal file
401
x.html
Normal file
@@ -0,0 +1,401 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Tech English Adventure</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=IBM+Plex+Mono:wght@300;400;500&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
:root{
|
||||
--bg:#0a0e17;--card:#111827;--border:#1e293b;
|
||||
--cyan:#00f0ff;--magenta:#ff2d95;--green:#00ff88;--amber:#ffb300;
|
||||
--text:#e2e8f0;--dim:#64748b;
|
||||
}
|
||||
html,body{height:100%;overflow:hidden}
|
||||
body{
|
||||
font-family:'IBM Plex Mono',monospace;
|
||||
background:var(--bg);color:var(--text);
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
}
|
||||
canvas#stars{position:fixed;top:0;left:0;width:100%;height:100%;z-index:0;pointer-events:none}
|
||||
#app{
|
||||
position:relative;z-index:1;
|
||||
width:100%;max-width:820px;height:100vh;
|
||||
display:flex;flex-direction:column;
|
||||
padding:20px;
|
||||
}
|
||||
|
||||
/* TOP BAR */
|
||||
.topbar{
|
||||
display:flex;justify-content:space-between;align-items:center;
|
||||
padding:12px 0;border-bottom:1px solid var(--border);
|
||||
margin-bottom:16px;flex-shrink:0;
|
||||
}
|
||||
.topbar h1{
|
||||
font-family:'Orbitron',sans-serif;font-size:14px;letter-spacing:3px;
|
||||
color:var(--cyan);text-transform:uppercase;
|
||||
}
|
||||
.stats{display:flex;gap:20px;font-size:12px;color:var(--dim)}
|
||||
.stats span{display:flex;align-items:center;gap:6px}
|
||||
.stats .val{color:var(--cyan);font-weight:500}
|
||||
.xp-bar{width:80px;height:4px;background:var(--border);border-radius:2px;overflow:hidden}
|
||||
.xp-fill{height:100%;background:linear-gradient(90deg,var(--cyan),var(--green));border-radius:2px;transition:width .6s ease}
|
||||
|
||||
/* SCENE */
|
||||
.scene-area{
|
||||
flex:1;overflow-y:auto;display:flex;flex-direction:column;
|
||||
scrollbar-width:thin;scrollbar-color:var(--border) transparent;
|
||||
}
|
||||
.scene-label{
|
||||
font-family:'Orbitron',sans-serif;font-size:10px;letter-spacing:4px;
|
||||
color:var(--magenta);margin-bottom:12px;text-transform:uppercase;
|
||||
}
|
||||
.scene-title{
|
||||
font-family:'Orbitron',sans-serif;font-size:clamp(20px,4vw,32px);
|
||||
font-weight:900;line-height:1.2;margin-bottom:20px;
|
||||
background:linear-gradient(135deg,var(--cyan),var(--green));
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
|
||||
}
|
||||
.scene-text{
|
||||
font-size:15px;line-height:1.8;color:var(--text);
|
||||
margin-bottom:24px;max-width:680px;
|
||||
}
|
||||
.scene-text .highlight{
|
||||
color:var(--cyan);font-weight:500;
|
||||
border-bottom:1px dashed var(--cyan);cursor:help;
|
||||
position:relative;
|
||||
}
|
||||
.scene-text .highlight:hover::after{
|
||||
content:attr(data-tip);position:absolute;bottom:120%;left:0;
|
||||
background:var(--card);border:1px solid var(--cyan);
|
||||
padding:6px 10px;font-size:11px;border-radius:4px;
|
||||
white-space:nowrap;color:var(--cyan);z-index:10;
|
||||
}
|
||||
|
||||
/* CHOICES */
|
||||
.choices{display:flex;flex-direction:column;gap:10px;margin-top:auto;padding-bottom:20px}
|
||||
.choice-btn{
|
||||
position:relative;
|
||||
background:var(--card);border:1px solid var(--border);
|
||||
color:var(--text);font-family:'IBM Plex Mono',monospace;
|
||||
font-size:14px;padding:16px 20px;border-radius:8px;
|
||||
cursor:pointer;text-align:left;
|
||||
transition:all .25s ease;
|
||||
display:flex;align-items:center;gap:14px;
|
||||
}
|
||||
.choice-btn .key{
|
||||
font-family:'Orbitron',sans-serif;font-size:11px;font-weight:700;
|
||||
color:var(--bg);background:var(--cyan);
|
||||
width:28px;height:28px;border-radius:6px;
|
||||
display:flex;align-items:center;justify-content:center;flex-shrink:0;
|
||||
}
|
||||
.choice-btn:hover{
|
||||
border-color:var(--cyan);
|
||||
background:linear-gradient(135deg,rgba(0,240,255,.08),rgba(0,255,136,.05));
|
||||
transform:translateX(6px);
|
||||
}
|
||||
.choice-btn.correct{
|
||||
border-color:var(--green);background:rgba(0,255,136,.12);
|
||||
animation:pulse-green .5s ease;
|
||||
}
|
||||
.choice-btn.wrong{
|
||||
border-color:var(--magenta);background:rgba(255,45,149,.1);
|
||||
animation:shake .4s ease;
|
||||
}
|
||||
@keyframes pulse-green{0%,100%{box-shadow:none}50%{box-shadow:0 0 20px rgba(0,255,136,.3)}}
|
||||
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-6px)}75%{transform:translateX(6px)}}
|
||||
|
||||
/* FEEDBACK */
|
||||
.feedback{
|
||||
margin-top:12px;padding:14px 18px;border-radius:8px;
|
||||
font-size:13px;line-height:1.6;
|
||||
animation:fadeIn .3s ease;
|
||||
}
|
||||
.feedback.ok{background:rgba(0,255,136,.08);border-left:3px solid var(--green);color:var(--green)}
|
||||
.feedback.no{background:rgba(255,45,149,.08);border-left:3px solid var(--magenta);color:var(--magenta)}
|
||||
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
|
||||
|
||||
.next-btn{
|
||||
margin-top:14px;align-self:flex-end;
|
||||
background:linear-gradient(135deg,var(--cyan),var(--green));
|
||||
color:var(--bg);border:none;font-family:'Orbitron',sans-serif;
|
||||
font-size:12px;font-weight:700;letter-spacing:2px;
|
||||
padding:12px 28px;border-radius:6px;cursor:pointer;
|
||||
transition:transform .2s,box-shadow .2s;
|
||||
}
|
||||
.next-btn:hover{transform:translateY(-2px);box-shadow:0 4px 20px rgba(0,240,255,.3)}
|
||||
|
||||
/* END SCREEN */
|
||||
.end-screen{
|
||||
display:flex;flex-direction:column;align-items:center;justify-content:center;
|
||||
text-align:center;flex:1;gap:20px;
|
||||
}
|
||||
.end-screen .grade{
|
||||
font-family:'Orbitron',sans-serif;font-size:64px;font-weight:900;
|
||||
background:linear-gradient(135deg,var(--cyan),var(--magenta));
|
||||
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
|
||||
}
|
||||
.end-screen p{font-size:15px;color:var(--dim);max-width:500px;line-height:1.7}
|
||||
|
||||
.hidden{display:none!important}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="stars"></canvas>
|
||||
<div id="app">
|
||||
<div class="topbar">
|
||||
<h1>Tech English</h1>
|
||||
<div class="stats">
|
||||
<span>XP <span class="val" id="xp">0</span></span>
|
||||
<span><div class="xp-bar"><div class="xp-fill" id="xpBar" style="width:0%"></div></div></span>
|
||||
<span>Level <span class="val" id="lvl">1</span></span>
|
||||
<span>Score <span class="val" id="score">0</span>/<span id="total">0</span></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scene-area" id="scene"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// ─── STAR FIELD ───
|
||||
const cvs=document.getElementById('stars'),ctx=cvs.getContext('2d');
|
||||
let W,H,particles=[];
|
||||
function resizeCvs(){W=cvs.width=innerWidth;H=cvs.height=innerHeight;particles=Array.from({length:120},()=>({x:Math.random()*W,y:Math.random()*H,r:Math.random()*1.5+.3,s:Math.random()*.3+.05,o:Math.random()}))}
|
||||
resizeCvs();addEventListener('resize',resizeCvs);
|
||||
(function draw(){ctx.clearRect(0,0,W,H);particles.forEach(p=>{p.o+=.008;ctx.fillStyle=`rgba(0,240,255,${(.3+Math.sin(p.o)*.3).toFixed(2)})`;ctx.beginPath();ctx.arc(p.x,p.y,p.r,0,6.28);ctx.fill();p.y-=p.s;if(p.y<-2){p.y=H+2;p.x=Math.random()*W}});requestAnimationFrame(draw)})();
|
||||
|
||||
// ─── GAME DATA ───
|
||||
const GAME = [
|
||||
// ── CHAPTER 1: AI LAB ──
|
||||
{
|
||||
chapter:"Chapter 1 — The AI Lab",
|
||||
title:"Neural Network Initialization",
|
||||
text:`You step into the AI research lab. The lead scientist greets you: <br><br>"We need to <span class="highlight" data-tip="train = trénovať model na dátach">train</span> our new deep learning model, but first we must choose the right <span class="highlight" data-tip="architecture = architektúra siete">architecture</span>. The dataset contains 50 million <span class="highlight" data-tip="labeled = označené, s anotáciami">labeled</span> images."<br><br>She asks: <b>"Which approach should we use for image classification?"</b>`,
|
||||
choices:[
|
||||
{text:"A Convolutional Neural Network (CNN) — it excels at spatial feature extraction in images.",correct:true},
|
||||
{text:"A simple Recurrent Neural Network (RNN) — it processes sequences efficiently.",correct:false}
|
||||
],
|
||||
ok:"Excellent! CNNs use convolutional layers to detect spatial patterns like edges, textures, and shapes — making them ideal for image tasks.",
|
||||
no:"Not quite. RNNs are designed for sequential data like text or time series. For images, a CNN is the standard choice because it captures spatial hierarchies of features."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 1 — The AI Lab",
|
||||
title:"The Overfitting Problem",
|
||||
text:`Your CNN reaches 99% accuracy on training data, but only 61% on the test set. A colleague warns:<br><br>"The model is <span class="highlight" data-tip="overfitting = preučenie, model sa naučí šum namiesto vzorov">overfitting</span>. It has memorized the training data instead of learning <span class="highlight" data-tip="generalizable = zovšeobecniteľné">generalizable</span> patterns."<br><br><b>What technique would best help reduce overfitting?</b>`,
|
||||
choices:[
|
||||
{text:"Increase the learning rate to make the model converge faster.",correct:false},
|
||||
{text:"Apply dropout regularization and use data augmentation.",correct:true}
|
||||
],
|
||||
ok:"Correct! Dropout randomly disables neurons during training, forcing the network to learn robust features. Data augmentation increases effective dataset size through transformations.",
|
||||
no:"Increasing the learning rate might actually make things worse — it can cause unstable training. Dropout and data augmentation are proven techniques against overfitting."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 1 — The AI Lab",
|
||||
title:"Deploying the Model",
|
||||
text:`The model performs well. Now you must <span class="highlight" data-tip="deploy = nasadiť do prevádzky">deploy</span> it to production. The engineering lead says:<br><br>"We need low <span class="highlight" data-tip="latency = oneskorenie, čas odozvy">latency</span> inference. The model must respond within 50 milliseconds per request."<br><br><b>What should you prioritize?</b>`,
|
||||
choices:[
|
||||
{text:"Use model quantization and optimize the inference pipeline with ONNX Runtime.",correct:true},
|
||||
{text:"Train a larger model with more parameters for better accuracy.",correct:false}
|
||||
],
|
||||
ok:"Right! Quantization reduces model size and speeds up inference by using lower-precision arithmetic. ONNX Runtime is optimized for fast inference across hardware.",
|
||||
no:"A larger model would increase latency, not reduce it. For real-time deployment, optimization techniques like quantization and efficient runtimes are essential."
|
||||
},
|
||||
|
||||
// ── CHAPTER 2: ROBOTICS ──
|
||||
{
|
||||
chapter:"Chapter 2 — Robotics Bay",
|
||||
title:"Sensor Fusion Challenge",
|
||||
text:`You enter the robotics bay. An autonomous rover sits on the test platform. The robotics engineer explains:<br><br>"The rover uses <span class="highlight" data-tip="sensor fusion = fúzia senzorov, kombinovanie dát z rôznych snímačov">sensor fusion</span> to navigate. We combine data from LiDAR, cameras, and <span class="highlight" data-tip="IMU = Inertial Measurement Unit, inerciálna meracia jednotka">IMU</span> sensors."<br><br><b>"Which algorithm is most commonly used for probabilistic sensor fusion in robotics?"</b>`,
|
||||
choices:[
|
||||
{text:"The Kalman Filter — it provides optimal state estimation for linear systems with Gaussian noise.",correct:true},
|
||||
{text:"Binary search — it efficiently finds data points in sorted sensor arrays.",correct:false}
|
||||
],
|
||||
ok:"Exactly! The Kalman Filter (and its variants like EKF and UKF) is fundamental in robotics for fusing noisy sensor data into accurate state estimates.",
|
||||
no:"Binary search is a data structure algorithm, not a sensor fusion technique. The Kalman Filter is the standard approach for combining uncertain sensor measurements."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 2 — Robotics Bay",
|
||||
title:"Actuator Failure",
|
||||
text:`An alarm sounds. The rover's left <span class="highlight" data-tip="actuator = aktuátor, pohonná jednotka">actuator</span> has failed during a test run. The system log shows:<br><br><code style="color:var(--magenta)">ERROR: Torque feedback loop — signal loss on joint_3</code><br><br>The engineer asks: <b>"What does the feedback loop do in a servo actuator?"</b>`,
|
||||
choices:[
|
||||
{text:"It continuously compares the desired position with the actual position and adjusts the motor output accordingly.",correct:true},
|
||||
{text:"It stores previous movement commands in a database for later analysis.",correct:false}
|
||||
],
|
||||
ok:"Correct! A feedback loop (closed-loop control) constantly measures the actual state and corrects errors — this is fundamental to precise robotic motion.",
|
||||
no:"That describes logging, not feedback control. A feedback loop actively compares the target state with the measured state in real-time to correct deviations."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 2 — Robotics Bay",
|
||||
title:"Path Planning",
|
||||
text:`The actuator is repaired. Now you must program the rover's <span class="highlight" data-tip="path planning = plánovanie trasy">path planning</span> module for an obstacle course.<br><br>"The environment is partially known. The rover will encounter <span class="highlight" data-tip="dynamic obstacles = dynamické prekážky, meniace sa v čase">dynamic obstacles</span> that move unpredictably."<br><br><b>Which path planning approach is best suited?</b>`,
|
||||
choices:[
|
||||
{text:"A hardcoded sequence of waypoints based on the initial map.",correct:false},
|
||||
{text:"A reactive algorithm like D* Lite that replans in real-time as new obstacles are detected.",correct:true}
|
||||
],
|
||||
ok:"Perfect! D* Lite and similar algorithms efficiently update the path when the environment changes, which is essential for dynamic obstacle avoidance.",
|
||||
no:"Hardcoded waypoints cannot adapt to moving obstacles. Reactive algorithms like D* Lite continuously update the path based on new sensor data."
|
||||
},
|
||||
|
||||
// ── CHAPTER 3: AERONAUTICS ──
|
||||
{
|
||||
chapter:"Chapter 3 — Flight Simulation Center",
|
||||
title:"Autopilot Systems",
|
||||
text:`You're now at the flight simulation center. A UAV (<span class="highlight" data-tip="UAV = Unmanned Aerial Vehicle, bezpilotný lietajúci prostriedok">Unmanned Aerial Vehicle</span>) prototype is being tested.<br><br>The avionics engineer explains: "The <span class="highlight" data-tip="autopilot = autopilot, systém automatického riadenia letu">autopilot</span> uses a PID controller for altitude hold. But we're experiencing <span class="highlight" data-tip="oscillation = oscilácia, kmitanie okolo cieľovej hodnoty">oscillation</span> around the target altitude."<br><br><b>What is the most likely cause?</b>`,
|
||||
choices:[
|
||||
{text:"The proportional gain (Kp) is too high, causing the system to overcorrect repeatedly.",correct:true},
|
||||
{text:"The UAV's battery is running low, reducing thrust capacity.",correct:false}
|
||||
],
|
||||
ok:"Correct! When Kp is too high, the controller overreacts to errors, creating oscillations. Tuning PID parameters is critical in flight control systems.",
|
||||
no:"While low battery affects performance, the symptom described — oscillation around a setpoint — is a classic sign of excessive proportional gain in a PID controller."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 3 — Flight Simulation Center",
|
||||
title:"Aerodynamic Vocabulary",
|
||||
text:`The test pilot briefs you before a simulation run:<br><br>"During <span class="highlight" data-tip="takeoff = vzlet">takeoff</span>, the aircraft must generate enough <span class="highlight" data-tip="lift = vztlak">lift</span> to overcome its weight. The shape of the <span class="highlight" data-tip="airfoil = profil krídla">airfoil</span> creates a pressure difference between the upper and lower surfaces of the wing."<br><br><b>What is the primary factor that increases lift during takeoff?</b>`,
|
||||
choices:[
|
||||
{text:"Increasing the airspeed, which increases the pressure differential across the wing surface.",correct:true},
|
||||
{text:"Reducing the aircraft's drag coefficient by retracting all control surfaces.",correct:false}
|
||||
],
|
||||
ok:"Right! According to Bernoulli's principle, higher airspeed creates greater pressure differential across the airfoil, generating more lift. That's why aircraft accelerate on the runway.",
|
||||
no:"Retracting control surfaces would reduce the effective lift area. Lift increases primarily with airspeed — this is why a takeoff roll is necessary."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 3 — Flight Simulation Center",
|
||||
title:"Communication Protocol",
|
||||
text:`You're monitoring the UAV's <span class="highlight" data-tip="telemetry = telemetria, diaľkový prenos meraných dát">telemetry</span> link. The ground station receives data packets containing altitude, speed, GPS coordinates, and battery status.<br><br>Suddenly the link becomes <span class="highlight" data-tip="intermittent = prerušovaný, nestály">intermittent</span>. The signal drops every few seconds.<br><br><b>What is the best immediate response?</b>`,
|
||||
choices:[
|
||||
{text:"Ignore the issue and continue the mission — some packet loss is normal.",correct:false},
|
||||
{text:"Switch to the redundant communication channel and initiate a return-to-home protocol.",correct:true}
|
||||
],
|
||||
ok:"Correct! Redundancy is a core safety principle in aerospace. Switching to a backup link and initiating RTH ensures the UAV remains under control.",
|
||||
no:"In aerospace, intermittent communication is a serious safety concern. Ignoring it could lead to loss of control. Redundant systems and fail-safe protocols exist for exactly this reason."
|
||||
},
|
||||
|
||||
// ── CHAPTER 4: FINAL INTEGRATION ──
|
||||
{
|
||||
chapter:"Chapter 4 — Systems Integration",
|
||||
title:"The Grand Challenge",
|
||||
text:`It's time to integrate everything. Your team is building an <span class="highlight" data-tip="autonomous = autonómny, samočinný">autonomous</span> delivery drone that uses AI for navigation, robotic arms for package handling, and must comply with <span class="highlight" data-tip="airspace regulations = predpisy pre vzdušný priestor">airspace regulations</span>.<br><br>The project manager asks: <b>"What is the most critical engineering principle for this system?"</b>`,
|
||||
choices:[
|
||||
{text:"Making the drone as fast as possible to maximize delivery throughput.",correct:false},
|
||||
{text:"Designing with redundancy, fail-safes, and graceful degradation at every subsystem level.",correct:true}
|
||||
],
|
||||
ok:"Excellent! Safety-critical systems require redundancy (backup components), fail-safes (safe defaults on failure), and graceful degradation (maintaining partial function). Speed is secondary to reliability.",
|
||||
no:"Speed without safety is dangerous, especially in autonomous aerial systems. The correct principle is defense-in-depth: redundancy, fail-safes, and graceful degradation."
|
||||
},
|
||||
{
|
||||
chapter:"Chapter 4 — Systems Integration",
|
||||
title:"Technical Report",
|
||||
text:`Your project succeeds. Now you must write a <span class="highlight" data-tip="technical report = technická správa">technical report</span> for the stakeholders. A senior engineer reviews your draft and comments:<br><br>"Your abstract should be a <span class="highlight" data-tip="concise = stručný, výstižný">concise</span> summary of the entire project — objectives, methods, results, and conclusions — in one paragraph."<br><br><b>Which of these is a well-written opening for a technical abstract?</b>`,
|
||||
choices:[
|
||||
{text:"'This paper presents the design, implementation, and evaluation of an autonomous delivery UAV system integrating CNN-based navigation with redundant flight control.'",correct:true},
|
||||
{text:"'In this report we will talk about our drone project and explain the cool things we did with AI and robots.'",correct:false}
|
||||
],
|
||||
ok:"Perfect! Technical writing requires precise, formal language. The correct abstract clearly states the scope (design, implementation, evaluation) and key technologies used.",
|
||||
no:"Technical writing must be formal, precise, and specific. Words like 'cool things' and 'talk about' are too informal for an engineering report."
|
||||
}
|
||||
];
|
||||
|
||||
// ─── GAME STATE ───
|
||||
let current=0, xp=0, answered=0, correct=0, locked=false;
|
||||
const scene=document.getElementById('scene');
|
||||
const xpEl=document.getElementById('xp'), lvlEl=document.getElementById('lvl');
|
||||
const scoreEl=document.getElementById('score'), totalEl=document.getElementById('total');
|
||||
const xpBar=document.getElementById('xpBar');
|
||||
|
||||
totalEl.textContent=GAME.length;
|
||||
|
||||
function updateStats(){
|
||||
xpEl.textContent=xp;
|
||||
const level=Math.floor(xp/30)+1;
|
||||
lvlEl.textContent=level;
|
||||
scoreEl.textContent=correct;
|
||||
xpBar.style.width=((xp%30)/30*100)+'%';
|
||||
}
|
||||
|
||||
function render(){
|
||||
locked=false;
|
||||
const q=GAME[current];
|
||||
scene.innerHTML=`
|
||||
<div class="scene-label">${q.chapter}</div>
|
||||
<div class="scene-title">${q.title}</div>
|
||||
<div class="scene-text">${q.text}</div>
|
||||
<div class="choices" id="choices">
|
||||
${q.choices.map((c,i)=>`
|
||||
<button class="choice-btn" onclick="answer(${i})">
|
||||
<span class="key">${String.fromCharCode(65+i)}</span>
|
||||
<span>${c.text}</span>
|
||||
</button>
|
||||
`).join('')}
|
||||
</div>
|
||||
`;
|
||||
scene.scrollTop=0;
|
||||
}
|
||||
|
||||
function answer(idx){
|
||||
if(locked) return;
|
||||
locked=true;
|
||||
answered++;
|
||||
const q=GAME[current];
|
||||
const btns=document.querySelectorAll('.choice-btn');
|
||||
const isCorrect=q.choices[idx].correct;
|
||||
|
||||
if(isCorrect){correct++;xp+=20}else{xp+=5}
|
||||
updateStats();
|
||||
|
||||
btns.forEach((b,i)=>{
|
||||
if(i===idx) b.classList.add(isCorrect?'correct':'wrong');
|
||||
q.choices[i].correct && i!==idx && (b.style.borderColor='var(--green)',b.style.opacity='.6');
|
||||
b.style.pointerEvents='none';
|
||||
});
|
||||
|
||||
const fb=document.createElement('div');
|
||||
fb.className='feedback '+(isCorrect?'ok':'no');
|
||||
fb.innerHTML=(isCorrect?'✓ ':'✗ ')+(isCorrect?q.ok:q.no);
|
||||
document.getElementById('choices').after(fb);
|
||||
|
||||
if(current<GAME.length-1){
|
||||
const nb=document.createElement('button');
|
||||
nb.className='next-btn';nb.textContent='CONTINUE →';
|
||||
nb.onclick=()=>{current++;render()};
|
||||
fb.after(nb);
|
||||
setTimeout(()=>nb.focus(),100);
|
||||
} else {
|
||||
const nb=document.createElement('button');
|
||||
nb.className='next-btn';nb.textContent='SEE RESULTS →';
|
||||
nb.onclick=showEnd;
|
||||
fb.after(nb);
|
||||
}
|
||||
fb.scrollIntoView({behavior:'smooth',block:'nearest'});
|
||||
}
|
||||
|
||||
function showEnd(){
|
||||
const pct=Math.round(correct/GAME.length*100);
|
||||
let grade,msg;
|
||||
if(pct>=90){grade='A+';msg="Outstanding! Your technical English is at a professional level. You're ready to write papers and present at conferences."}
|
||||
else if(pct>=70){grade='B+';msg="Great work! You have a solid grasp of technical vocabulary. Review the terms you missed and you'll be fully fluent in engineering English."}
|
||||
else if(pct>=50){grade='C';msg="Decent foundation, but there's room to grow. Revisit the highlighted terms and try again — repetition builds mastery."}
|
||||
else{grade='D';msg="Keep studying! Technical English takes practice. Focus on the vocabulary highlights and give it another shot."}
|
||||
scene.innerHTML=`
|
||||
<div class="end-screen">
|
||||
<div class="scene-label">Mission Complete</div>
|
||||
<div class="grade">${grade}</div>
|
||||
<div class="scene-title">${correct} / ${GAME.length} Correct (${pct}%)</div>
|
||||
<p>${msg}</p>
|
||||
<p style="font-size:12px;color:var(--dim)">Total XP earned: ${xp} · Level ${Math.floor(xp/30)+1}</p>
|
||||
<button class="next-btn" onclick="current=0;xp=0;answered=0;correct=0;updateStats();render()">PLAY AGAIN ↻</button>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// keyboard
|
||||
document.addEventListener('keydown',e=>{
|
||||
if(locked) return;
|
||||
if(e.key==='1'||e.key==='a'||e.key==='A') answer(0);
|
||||
if(e.key==='2'||e.key==='b'||e.key==='B') answer(1);
|
||||
});
|
||||
|
||||
render();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user