Browse Source

Добавить 'docs/file.md'

u23-27dybenko 2 weeks ago
parent
commit
e4d4e40cac
1 changed files with 910 additions and 0 deletions
  1. 910 0
      docs/file.md

+ 910 - 0
docs/file.md

@@ -0,0 +1,910 @@
+<!DOCTYPE html>
+<html lang="ru">
+<head>
+<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<title>Механические волны — неон</title>
+<style>
+  :root{
+    --neon-pink:#ff2ec4;
+    --neon-cyan:#00e5ff;
+    --neon-purple:#a259ff;
+    --neon-green:#39ff14;
+    --text:#e8e6ff;
+  }
+  *{box-sizing:border-box;margin:0;padding:0;}
+  html,body{height:100%;}
+  body{
+    background:radial-gradient(circle at 20% 20%, #1a0033 0%, #0a0014 60%, #000 100%);
+    color:var(--text);
+    font-family:'Segoe UI','Trebuchet MS',sans-serif;
+    overflow:hidden;
+  }
+  #app{position:relative;width:100%;height:100vh;overflow:hidden;}
+  .scene{
+    position:absolute;inset:0;display:none;flex-direction:column;
+    align-items:center;justify-content:center;padding:80px 24px 24px;
+    animation:fadeIn .6s ease;overflow-y:auto;
+  }
+  .scene.active{display:flex;}
+  @keyframes fadeIn{from{opacity:0;transform:translateY(20px);}to{opacity:1;transform:none;}}
+  h1,h2{font-weight:800;letter-spacing:2px;text-transform:uppercase;text-align:center;}
+  h1{font-size:clamp(1.8rem,5vw,3.5rem);color:#fff;
+    text-shadow:0 0 10px var(--neon-pink),0 0 30px var(--neon-pink),0 0 60px var(--neon-purple);
+    margin-bottom:20px;}
+  h2{font-size:clamp(1.3rem,3.5vw,2rem);color:#fff;
+    text-shadow:0 0 8px var(--neon-cyan),0 0 20px var(--neon-cyan);margin-bottom:16px;}
+  p{max-width:720px;text-align:center;line-height:1.6;opacity:.9;}
+  .btn{
+    background:transparent;color:var(--neon-cyan);
+    border:2px solid var(--neon-cyan);padding:12px 28px;margin:8px;
+    font-size:1rem;font-weight:700;letter-spacing:2px;text-transform:uppercase;
+    border-radius:8px;cursor:pointer;transition:.25s;
+    box-shadow:0 0 12px rgba(0,229,255,.6), inset 0 0 12px rgba(0,229,255,.15);
+  }
+  .btn:hover{background:var(--neon-cyan);color:#000;
+    box-shadow:0 0 25px var(--neon-cyan),0 0 60px var(--neon-cyan);transform:translateY(-2px);}
+  .btn.pink{color:var(--neon-pink);border-color:var(--neon-pink);
+    box-shadow:0 0 12px rgba(255,46,196,.6), inset 0 0 12px rgba(255,46,196,.15);}
+  .btn.pink:hover{background:var(--neon-pink);color:#000;box-shadow:0 0 25px var(--neon-pink);}
+  .btn.green{color:var(--neon-green);border-color:var(--neon-green);}
+  .btn.green:hover{background:var(--neon-green);color:#000;box-shadow:0 0 25px var(--neon-green);}
+  .btn:disabled{opacity:.35;cursor:not-allowed;transform:none;}
+  .topbar{
+    position:absolute;top:0;left:0;right:0;display:flex;justify-content:space-between;
+    align-items:center;padding:10px 16px;z-index:10;font-size:.8rem;
+    letter-spacing:2px;text-transform:uppercase;color:var(--neon-cyan);
+    text-shadow:0 0 8px var(--neon-cyan);
+  }
+  .topbar .progress{flex:1;height:4px;margin:0 16px;background:rgba(255,255,255,.1);
+    border-radius:2px;overflow:hidden;}
+  .topbar .progress div{height:100%;width:0%;
+    background:linear-gradient(90deg,var(--neon-pink),var(--neon-cyan));
+    box-shadow:0 0 12px var(--neon-cyan);transition:width .5s;}
+  .icon-btn{background:transparent;border:1px solid var(--neon-cyan);color:var(--neon-cyan);
+    border-radius:6px;padding:4px 10px;cursor:pointer;font-size:.75rem;}
+  .icon-btn:hover{background:var(--neon-cyan);color:#000;}
+  canvas{display:block;max-width:100%;}
+  .canvas-wrap{border:1px solid rgba(0,229,255,.3);border-radius:12px;
+    box-shadow:0 0 30px rgba(162,89,255,.35), inset 0 0 30px rgba(0,229,255,.1);
+    background:rgba(0,0,0,.35);padding:8px;margin:16px 0;}
+  .controls{display:flex;flex-wrap:wrap;justify-content:center;gap:12px;margin:16px 0;}
+  .slider-box{display:flex;flex-direction:column;align-items:center;
+    background:rgba(255,255,255,.04);padding:10px 16px;border-radius:10px;
+    border:1px solid rgba(255,46,196,.35);}
+  .slider-box label{font-size:.75rem;letter-spacing:2px;text-transform:uppercase;
+    color:var(--neon-pink);margin-bottom:6px;}
+  input[type=range]{-webkit-appearance:none;width:160px;height:4px;
+    background:linear-gradient(90deg,var(--neon-pink),var(--neon-cyan));
+    border-radius:2px;outline:none;}
+  input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;
+    border-radius:50%;background:#fff;box-shadow:0 0 12px var(--neon-cyan);cursor:pointer;}
+  input[type=range]::-moz-range-thumb{width:16px;height:16px;border:none;border-radius:50%;
+    background:#fff;box-shadow:0 0 12px var(--neon-cyan);cursor:pointer;}
+  .tubes{display:flex;flex-direction:column;gap:12px;width:min(760px,100%);margin:12px 0;}
+  .tube{position:relative;height:44px;border-radius:22px;background:rgba(255,255,255,.05);
+    border:1px solid rgba(0,229,255,.3);overflow:hidden;}
+  .tube .label{position:absolute;left:12px;top:50%;transform:translateY(-50%);
+    font-size:.8rem;letter-spacing:2px;color:var(--neon-cyan);z-index:2;}
+  .tube .impulse{position:absolute;top:50%;left:0;transform:translate(-50%,-50%);
+    width:20px;height:20px;border-radius:50%;
+    background:radial-gradient(circle,#fff,var(--neon-pink));
+    box-shadow:0 0 20px var(--neon-pink);opacity:0;}
+  .tube .impulse.run{animation:run linear forwards;}
+  @keyframes run{0%{left:0;opacity:1;}100%{left:100%;opacity:1;}}
+  .quiz-options{display:flex;flex-wrap:wrap;gap:12px;justify-content:center;margin-top:16px;}
+  .quiz-options .btn{min-width:120px;}
+  .quiz-options .btn.correct{background:var(--neon-green);color:#000;
+    border-color:var(--neon-green);box-shadow:0 0 25px var(--neon-green);}
+  .quiz-options .btn.wrong{background:#ff2e4c;color:#fff;border-color:#ff2e4c;}
+  .modal{position:absolute;inset:0;background:rgba(0,0,0,.75);display:none;
+    align-items:center;justify-content:center;z-index:50;backdrop-filter:blur(4px);}
+  .modal.active{display:flex;}
+  .modal-content{background:linear-gradient(145deg,#160028,#0a0014);
+    border:1px solid var(--neon-cyan);border-radius:14px;padding:28px;
+    max-width:520px;width:90%;box-shadow:0 0 40px rgba(0,229,255,.5);text-align:center;}
+  .cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
+    gap:14px;width:min(800px,100%);margin:16px 0;}
+  .card{perspective:1000px;height:130px;cursor:pointer;}
+  .card-inner{position:relative;width:100%;height:100%;transition:transform .6s;
+    transform-style:preserve-3d;}
+  .card.flipped .card-inner{transform:rotateY(180deg);}
+  .card-face{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
+    border-radius:12px;padding:12px;text-align:center;backface-visibility:hidden;
+    border:1px solid var(--neon-purple);
+    background:linear-gradient(145deg,rgba(162,89,255,.15),rgba(0,229,255,.08));
+    box-shadow:0 0 20px rgba(162,89,255,.4);font-weight:700;}
+  .card-face.back{transform:rotateY(180deg);font-weight:400;font-size:.85rem;
+    border-color:var(--neon-cyan);color:#cfeaff;}
+  .pairs{display:grid;grid-template-columns:1fr 1fr;gap:24px;width:min(700px,100%);margin:16px 0;}
+  .pair-col{display:flex;flex-direction:column;gap:10px;}
+  .pair-item{padding:10px 14px;border-radius:8px;cursor:pointer;
+    border:1px solid var(--neon-cyan);background:rgba(0,229,255,.05);
+    text-align:center;font-size:.9rem;transition:.2s;}
+  .pair-item:hover{background:rgba(0,229,255,.2);}
+  .pair-item.selected{background:var(--neon-pink);color:#000;}
+  .pair-item.matched{opacity:.35;pointer-events:none;border-color:var(--neon-green);}
+  .molecules{position:relative;width:min(700px,100%);height:120px;
+    border:1px dashed rgba(0,229,255,.4);border-radius:12px;margin:16px 0;
+    background:rgba(0,0,0,.3);}
+  .molecule{position:absolute;top:50%;transform:translate(-50%,-50%);
+    width:26px;height:26px;border-radius:50%;
+    background:radial-gradient(circle,#fff,var(--neon-cyan));
+    box-shadow:0 0 15px var(--neon-cyan);cursor:pointer;transition:left .3s;}
+  .molecule.placed{background:radial-gradient(circle,#fff,var(--neon-green));
+    box-shadow:0 0 15px var(--neon-green);}
+  .target{position:absolute;top:50%;transform:translate(-50%,-50%);
+    width:30px;height:30px;border-radius:50%;border:2px dashed var(--neon-pink);}
+  .progress-quiz{width:min(600px,100%);height:6px;border-radius:3px;
+    background:rgba(255,255,255,.1);margin:16px 0;overflow:hidden;}
+  .progress-quiz div{height:100%;width:0;
+    background:linear-gradient(90deg,var(--neon-pink),var(--neon-cyan));
+    transition:width .4s;}
+  .question{font-size:1.15rem;text-align:center;max-width:700px;margin:16px 0;line-height:1.5;}
+  .result-score{font-size:4rem;font-weight:900;color:#fff;
+    text-shadow:0 0 20px var(--neon-pink),0 0 40px var(--neon-purple);}
+  .hint{font-size:.8rem;color:var(--neon-pink);letter-spacing:1px;
+    margin-top:8px;min-height:1.2em;}
+  .table{font-size:.85rem;color:#cfeaff;margin-top:8px;text-align:center;line-height:1.8;}
+  .table span{color:var(--neon-cyan);font-weight:700;}
+</style>
+</head>
+<body>
+<div id="app">
+  <div class="topbar">
+    <span id="sceneLabel">СЦЕНА 1 / 7</span>
+    <div class="progress"><div id="progressBar"></div></div>
+    <button class="icon-btn" id="soundToggle" type="button">🔊 ЗВУК</button>
+  </div>
+
+  <!-- SCENE 1 -->
+  <section class="scene active" id="scene1">
+    <canvas id="bgCanvas" width="900" height="500"
+      style="position:absolute;top:0;left:0;width:100%;height:100%;opacity:.35;pointer-events:none;"></canvas>
+    <div style="position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;">
+      <h1>Механические волны</h1>
+      <p>Интерактивный курс: колебания, звук и среды распространения.</p>
+      <p class="hint">Наушники приветствуются 🎧</p>
+      <div style="margin-top:24px;">
+        <button class="btn" id="btnStart" type="button">▶ Начать курс</button>
+        <button class="btn pink" id="btnWhat" type="button">Что такое волна?</button>
+      </div>
+    </div>
+  </section>
+
+  <!-- SCENE 2 -->
+  <section class="scene" id="scene2">
+    <h2>Что такое механическая волна?</h2>
+    <p>Это распространение колебаний в упругой среде. Частицы колеблются, но не переносятся вместе с волной.</p>
+    <div class="canvas-wrap"><canvas id="chainCanvas" width="800" height="200"></canvas></div>
+    <div class="controls">
+      <div class="slider-box">
+        <label>Частота: <span id="freqVal">3</span> Гц</label>
+        <input type="range" id="freqSlider" min="1" max="10" value="3">
+      </div>
+      <div class="slider-box">
+        <label>Амплитуда: <span id="ampVal">25</span> px</label>
+        <input type="range" id="ampSlider" min="5" max="40" value="25">
+      </div>
+      <button class="btn green" id="btnPush" type="button">Толкнуть</button>
+    </div>
+    <p class="hint" id="scene2Hint">Толчков: 0 / 3</p>
+    <button class="btn" id="btnNext2" type="button" disabled>Далее →</button>
+  </section>
+
+  <!-- SCENE 3 -->
+  <section class="scene" id="scene3">
+    <h2>Среда распространения. Скорость звука</h2>
+    <p>Чем плотнее и упруже среда — тем быстрее идёт звук.</p>
+    <div class="tubes">
+      <div class="tube"><span class="label">Воздух ≈ 343 м/с</span><div class="impulse" data-speed="2.4"></div></div>
+      <div class="tube"><span class="label">Вода ≈ 1480 м/с</span><div class="impulse" data-speed="1.2"></div></div>
+      <div class="tube"><span class="label">Сталь ≈ 5100 м/с</span><div class="impulse" data-speed="0.5"></div></div>
+    </div>
+    <button class="btn" id="btnImpulse" type="button">Запустить импульс</button>
+    <p class="question" style="margin-top:20px;">В какой среде звук распространяется быстрее всего?</p>
+    <div class="quiz-options" id="quiz3">
+      <button class="btn" data-ans="air" type="button">Воздух</button>
+      <button class="btn" data-ans="water" type="button">Вода</button>
+      <button class="btn" data-ans="steel" type="button">Сталь</button>
+    </div>
+    <button class="btn" id="btnNext3" type="button" disabled style="margin-top:20px;">Далее →</button>
+  </section>
+
+  <!-- SCENE 4 -->
+  <section class="scene" id="scene4">
+    <h2>Колебания: период, частота, амплитуда</h2>
+    <div style="display:flex;flex-wrap:wrap;justify-content:center;gap:16px;">
+      <div class="canvas-wrap"><canvas id="oscCanvas" width="360" height="260"></canvas></div>
+      <div class="canvas-wrap"><canvas id="waveCanvas" width="360" height="260"></canvas></div>
+    </div>
+    <div class="controls">
+      <div class="slider-box">
+        <label>Амплитуда: <span id="ampVal2">60</span></label>
+        <input type="range" id="ampSlider2" min="20" max="100" value="60">
+      </div>
+      <div class="slider-box">
+        <label>Период: <span id="perVal">1.2</span> с</label>
+        <input type="range" id="perSlider" min="4" max="30" value="12">
+      </div>
+      <button class="btn pink" id="btnCheck4" type="button">Проверить понимание</button>
+    </div>
+    <p class="table">Формулы: <span>T = 1/ν</span> · <span>ν = 1/T</span> · <span>v = λν</span></p>
+    <button class="btn" id="btnNext4" type="button" disabled>Далее →</button>
+  </section>
+
+  <!-- SCENE 5 -->
+  <section class="scene" id="scene5">
+    <h2>Виды волн. Звук — продольная волна</h2>
+    <div class="controls">
+      <button class="btn" id="btnLong" type="button">Продольная</button>
+      <button class="btn pink" id="btnTrans" type="button">Поперечная</button>
+    </div>
+    <div class="canvas-wrap"><canvas id="typeCanvas" width="800" height="200"></canvas></div>
+    <p>Собери «звук»: кликни по молекуле — она встанет в ближайшую позицию сжатия/разрежения.</p>
+    <div class="molecules" id="molecules"></div>
+    <p class="hint" id="scene5Hint">Размещено: 0 / 6</p>
+    <button class="btn" id="btnNext5" type="button" disabled>Далее →</button>
+  </section>
+
+  <!-- SCENE 6 -->
+  <section class="scene" id="scene6">
+    <h2>Применение звуковых волн</h2>
+    <p>Нажми на карточку, чтобы узнать подробнее.</p>
+    <div class="cards" id="cards">
+      <div class="card"><div class="card-inner">
+        <div class="card-face">Эхолокация</div>
+        <div class="card-face back">Летучие мыши и дельфины определяют препятствия по отражённому ультразвуку.</div>
+      </div></div>
+      <div class="card"><div class="card-inner">
+        <div class="card-face">УЗИ</div>
+        <div class="card-face back">Медицинская визуализация: ультразвук отражается от границ тканей.</div>
+      </div></div>
+      <div class="card"><div class="card-inner">
+        <div class="card-face">Сейсмология</div>
+        <div class="card-face back">По сейсмическим волнам изучают строение Земли и землетрясения.</div>
+      </div></div>
+      <div class="card"><div class="card-inner">
+        <div class="card-face">Музыка</div>
+        <div class="card-face back">Струны и столбы воздуха создают стоячие волны — ноты.</div>
+      </div></div>
+    </div>
+    <p>Собери пару: пример ↔ физическое явление.</p>
+    <div class="pairs">
+      <div class="pair-col" id="pairLeft"></div>
+      <div class="pair-col" id="pairRight"></div>
+    </div>
+    <p class="hint" id="scene6Hint">Собрано пар: 0 / 4</p>
+    <button class="btn" id="btnNext6" type="button" disabled>К тестированию →</button>
+  </section>
+
+  <!-- SCENE 7 -->
+  <section class="scene" id="scene7">
+    <h2 id="quizTitle">Итоговое тестирование</h2>
+    <div class="progress-quiz"><div id="quizProgress"></div></div>
+    <p class="question" id="quizQuestion">…</p>
+    <div class="quiz-options" id="quizOptions"></div>
+    <div id="quizResult" style="display:none;flex-direction:column;align-items:center;">
+      <div class="result-score" id="finalScore">0</div>
+      <p id="finalText" style="margin:16px 0;"></p>
+      <button class="btn pink" id="btnRestart" type="button">Пройти заново</button>
+    </div>
+  </section>
+
+  <!-- MODAL -->
+  <div class="modal" id="modal">
+    <div class="modal-content">
+      <h2 id="modalTitle">…</h2>
+      <p id="modalText" style="margin:16px 0;">…</p>
+      <button class="btn" id="modalClose" type="button">Закрыть</button>
+    </div>
+  </div>
+</div>
+
+<script>
+/* ================= ЯДРО: НАВИГАЦИЯ + ЗВУК + МОДАЛКА ================= */
+var AudioCtx = window.AudioContext || window.webkitAudioContext;
+var audioCtx = null;
+var soundOn = true;
+
+function ensureAudio(){
+  try{
+    if(!audioCtx) audioCtx = new AudioCtx();
+    if(audioCtx.state === 'suspended') audioCtx.resume();
+  }catch(e){}
+}
+function beep(freq, dur, type, vol){
+  if(!soundOn || !audioCtx) return;
+  try{
+    var o = audioCtx.createOscillator();
+    var g = audioCtx.createGain();
+    o.type = type || 'sine';
+    o.frequency.value = freq || 440;
+    g.gain.setValueAtTime(vol || 0.12, audioCtx.currentTime);
+    g.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + (dur || 0.15));
+    o.connect(g); g.connect(audioCtx.destination);
+    o.start(); o.stop(audioCtx.currentTime + (dur || 0.15));
+  }catch(e){}
+}
+function correctSound(){ beep(880,0.12,'triangle',0.18); setTimeout(function(){ beep(1320,0.15,'triangle',0.18); },110); }
+function wrongSound(){ beep(220,0.25,'sawtooth',0.15); }
+function clickSound(){ beep(600,0.06,'square',0.08); }
+
+var scenes = ['scene1','scene2','scene3','scene4','scene5','scene6','scene7'];
+var currentScene = 0;
+
+function goToScene(idx){
+  if(idx < 0 || idx >= scenes.length) return;
+  var all = document.querySelectorAll('.scene');
+  for(var i=0;i<all.length;i++) all[i].classList.remove('active');
+  document.getElementById(scenes[idx]).classList.add('active');
+  currentScene = idx;
+  document.getElementById('sceneLabel').textContent = 'СЦЕНА ' + (idx+1) + ' / ' + scenes.length;
+  document.getElementById('progressBar').style.width = (idx/(scenes.length-1)*100) + '%';
+  clickSound();
+
+  if(idx === 3 && typeof startOscillators === 'function') startOscillators();
+  if(idx === 4 && typeof initMolecules === 'function') initMolecules();
+  if(idx === 5 && typeof initPairs === 'function') initPairs();
+  if(idx === 6 && typeof startQuiz === 'function') startQuiz();
+}
+
+var modal = document.getElementById('modal');
+function openModal(title, text){
+  document.getElementById('modalTitle').textContent = title;
+  document.getElementById('modalText').textContent = text;
+  modal.classList.add('active');
+}
+document.getElementById('modalClose').addEventListener('click', function(){
+  modal.classList.remove('active'); clickSound();
+});
+modal.addEventListener('click', function(e){ if(e.target === modal) modal.classList.remove('active'); });
+
+document.getElementById('soundToggle').addEventListener('click', function(e){
+  soundOn = !soundOn;
+  e.target.textContent = soundOn ? '🔊 ЗВУК' : '🔇 ВЫКЛ';
+  if(soundOn){ ensureAudio(); clickSound(); }
+});
+
+/* ================= ФОН ================= */
+var bgCanvas = document.getElementById('bgCanvas');
+var bgCtx = bgCanvas.getContext('2d');
+var bgT = 0;
+function drawBg(){
+  var W = bgCanvas.width, H = bgCanvas.height;
+  bgCtx.clearRect(0,0,W,H);
+  for(var k=0;k<3;k++){
+    bgCtx.beginPath();
+    bgCtx.strokeStyle = k===0 ? 'rgba(255,46,196,.5)' : k===1 ? 'rgba(0,229,255,.5)' : 'rgba(162,89,255,.5)';
+    bgCtx.lineWidth = 2;
+    bgCtx.shadowBlur = 20;
+    bgCtx.shadowColor = bgCtx.strokeStyle;
+    for(var x=0;x<W;x+=4){
+      var y = H/2 + Math.sin(x*0.02 + bgT + k*1.3) * (60 + k*20);
+      if(x===0) bgCtx.moveTo(x,y); else bgCtx.lineTo(x,y);
+    }
+    bgCtx.stroke();
+  }
+  bgCtx.shadowBlur = 0;
+  bgT += 0.03;
+  requestAnimationFrame(drawBg);
+}
+drawBg();
+
+/* ================= ГЛАВНАЯ: КНОПКИ ================= */
+document.getElementById('btnStart').addEventListener('click', function(){
+  ensureAudio();
+  clickSound();
+  goToScene(1);   // ← ПЕРЕХОД НА СЦЕНУ 2 (начало курса)
+});
+
+document.getElementById('btnWhat').addEventListener('click', function(){
+  ensureAudio();
+  clickSound();
+  openModal(
+    'Что такое волна?',
+    'Механическая волна — это процесс распространения колебаний в упругой среде. Частицы среды колеблются около положения равновесия, а сама волна переносит энергию, но не вещество. Примеры: звук в воздухе, волны на воде, сейсмические волны в Земле.'
+  );
+});
+
+/* ================= SCENE 2: цепочка ================= */
+(function(){
+  var c = document.getElementById('chainCanvas');
+  var ctx = c.getContext('2d');
+  var t = 0, amp = 25, freq = 3, pushTime = -999, pushes = 0;
+
+  // 🔊 Обновление звука при движении бегунка частоты:
+  // 1 Гц → 440 Гц, 10 Гц → 4400 Гц (линейно: 440 × freq)
+  function playFreqTone(){
+    if(!soundOn) return;
+    ensureAudio();
+    if(!audioCtx) return;
+    // останавливаем предыдущий тон
+    if(freqTone){
+      try{ freqTone.stop(); }catch(e){}
+      freqTone = null;
+    }
+    var soundFreq = 440 * freq;
+    var o = audioCtx.createOscillator();
+    var g = audioCtx.createGain();
+    o.type = 'sine';
+    o.frequency.value = soundFreq;
+    var now = audioCtx.currentTime;
+    g.gain.setValueAtTime(0, now);
+    g.gain.linearRampToValueAtTime(0.12, now + 0.02);
+    g.gain.setValueAtTime(0.12, now + 0.20);
+    g.gain.exponentialRampToValueAtTime(0.001, now + 0.35);
+    o.connect(g); g.connect(audioCtx.destination);
+    o.start(now);
+    o.stop(now + 0.4);
+    freqTone = o;
+  }
+
+  document.getElementById('freqSlider').addEventListener('input', function(e){
+    freq = +e.target.value;
+    document.getElementById('freqVal').textContent = freq;
+    document.getElementById('freqSound').textContent = 440 * freq;
+    playFreqTone();
+  });
+
+  document.getElementById('ampSlider').addEventListener('input', function(e){
+    amp = +e.target.value;
+    document.getElementById('ampVal').textContent = amp;
+  });
+
+  document.getElementById('btnPush').addEventListener('click', function(){
+    pushTime = t; pushes++;
+    document.getElementById('scene2Hint').textContent = 'Толчков: ' + pushes + ' / 3';
+
+    // 🔊 Звук толчка тоже привязан к бегунку: 440 × freq
+    beep(440 * freq, 0.35, 'sine', 0.18);
+
+    if(pushes >= 3){
+      document.getElementById('btnNext2').disabled = false;
+      document.getElementById('scene2Hint').textContent = 'Отлично! Можно идти дальше.';
+    }
+  });
+
+  document.getElementById('btnNext2').addEventListener('click', function(){ goToScene(2); });
+
+  function loop(){
+    var W = c.width, H = c.height;
+    ctx.clearRect(0,0,W,H);
+    var N = 12, spacing = W/(N+1);
+    t += 0.03;
+    var pts = [];
+    for(var i=0;i<N;i++){
+      var x = spacing*(i+1);
+      var delay = i*0.25/Math.max(freq,1);
+      var dt = t - pushTime - delay;
+      var off;
+      if(dt > 0){
+        off = Math.sin(dt*freq*2*Math.PI) * amp * Math.exp(-dt*1.2);
+      } else {
+        off = Math.sin(t*freq*0.5) * amp * 0.15;
+      }
+      pts.push({x:x, y:H/2 + off});
+    }
+    ctx.strokeStyle = 'rgba(0,229,255,.5)';
+    ctx.lineWidth = 2;
+    ctx.shadowBlur = 10; ctx.shadowColor = '#00e5ff';
+    for(var j=0;j<pts.length-1;j++){
+      ctx.beginPath();
+      ctx.moveTo(pts[j].x, pts[j].y);
+      ctx.lineTo(pts[j+1].x, pts[j+1].y);
+      ctx.stroke();
+    }
+    for(var k=0;k<pts.length;k++){
+      ctx.beginPath();
+      ctx.fillStyle = '#ff2ec4';
+      ctx.shadowBlur = 20; ctx.shadowColor = '#ff2ec4';
+      ctx.arc(pts[k].x, pts[k].y, 10, 0, Math.PI*2);
+      ctx.fill();
+    }
+    ctx.shadowBlur = 0;
+    requestAnimationFrame(loop);
+  }
+  loop();
+})();
+
+/* ================= SCENE 3: трубы + квиз ================= */
+document.getElementById('btnImpulse').addEventListener('click', function(){
+  clickSound();
+  var imps = document.querySelectorAll('#scene3 .impulse');
+  for(var i=0;i<imps.length;i++){
+    imps[i].style.animationDuration = imps[i].dataset.speed + 's';
+    imps[i].classList.remove('run');
+    void imps[i].offsetWidth;
+    imps[i].classList.add('run');
+  }
+});
+var q3 = document.querySelectorAll('#quiz3 .btn');
+for(var qi=0; qi<q3.length; qi++){
+  (function(b){
+    b.addEventListener('click', function(){
+      if(b.dataset.ans === 'steel'){
+        b.classList.add('correct'); correctSound();
+        document.getElementById('btnNext3').disabled = false;
+      } else {
+        b.classList.add('wrong'); wrongSound();
+      }
+    });
+  })(q3[qi]);
+}
+document.getElementById('btnNext3').addEventListener('click', function(){ goToScene(3); });
+
+/* ================= SCENE 4: маятник + волна ================= */
+var oscCanvas = document.getElementById('oscCanvas');
+var oscCtx = oscCanvas.getContext('2d');
+var waveCanvas = document.getElementById('waveCanvas');
+var waveCtx = waveCanvas.getContext('2d');
+var oscT = 0, oscAmp = 60, oscPeriod = 1.2;
+var oscRunning = false;
+
+document.getElementById('ampSlider2').addEventListener('input', function(e){
+  oscAmp = +e.target.value;
+  document.getElementById('ampVal2').textContent = oscAmp;
+});
+document.getElementById('perSlider').addEventListener('input', function(e){
+  oscPeriod = +e.target.value / 10;
+  document.getElementById('perVal').textContent = oscPeriod.toFixed(1);
+});
+
+function startOscillators(){
+  if(oscRunning) return;
+  oscRunning = true;
+  oscT = 0;
+  requestAnimationFrame(drawOsc);
+}
+
+function drawOsc(){
+  oscT += 0.04;
+  var W = oscCanvas.width, H = oscCanvas.height;
+  oscCtx.clearRect(0,0,W,H);
+  // ось
+  oscCtx.strokeStyle = 'rgba(0,229,255,.3)';
+  oscCtx.lineWidth = 1;
+  oscCtx.beginPath(); oscCtx.moveTo(W/2,30); oscCtx.lineTo(W/2,H-30); oscCtx.stroke();
+
+  // маятник
+   var ang = Math.sin(oscT * (2*Math.PI/oscPeriod)) * (oscAmp/200);
+  var len = 120, cx = W/2, cy = 40;
+  var bx = cx + Math.sin(ang)*len;
+  var by = cy + Math.cos(ang)*len;
+
+  oscCtx.strokeStyle = '#a259ff';
+  oscCtx.lineWidth = 2;
+  oscCtx.shadowBlur = 12; oscCtx.shadowColor = '#a259ff';
+  oscCtx.beginPath(); oscCtx.moveTo(cx, cy); oscCtx.lineTo(bx, by); oscCtx.stroke();
+
+  oscCtx.beginPath();
+  oscCtx.fillStyle = '#ff2ec4';
+  oscCtx.shadowBlur = 25; oscCtx.shadowColor = '#ff2ec4';
+  oscCtx.arc(bx, by, 14, 0, Math.PI*2);
+  oscCtx.fill();
+  oscCtx.shadowBlur = 0;
+
+  // правый — осциллограмма волны
+  var WW = waveCanvas.width, WH = waveCanvas.height;
+  waveCtx.clearRect(0,0,WW,WH);
+  waveCtx.strokeStyle = 'rgba(0,229,255,.2)';
+  waveCtx.lineWidth = 1;
+  waveCtx.beginPath(); waveCtx.moveTo(0, WH/2); waveCtx.lineTo(WW, WH/2); waveCtx.stroke();
+
+  waveCtx.strokeStyle = '#00e5ff';
+  waveCtx.lineWidth = 2;
+  waveCtx.shadowBlur = 15; waveCtx.shadowColor = '#00e5ff';
+  waveCtx.beginPath();
+  for(var x=0; x<WW; x++){
+    var y = WH/2 + Math.sin((x/WW)*Math.PI*4 + oscT*(2*Math.PI/oscPeriod)) * oscAmp;
+    if(x===0) waveCtx.moveTo(x,y); else waveCtx.lineTo(x,y);
+  }
+  waveCtx.stroke();
+  waveCtx.shadowBlur = 0;
+
+  requestAnimationFrame(drawOsc);
+}
+
+document.getElementById('btnCheck4').addEventListener('click', function(){
+  ensureAudio();
+  openModal(
+    'Проверь себя',
+    'Если период T = 2 с, то частота ν = 1/T = 0,5 Гц. А если частота ν = 4 Гц, то период T = 1/ν = 0,25 с. Запомни: T и ν — взаимно обратные величины.'
+  );
+  document.getElementById('btnNext4').disabled = false;
+  correctSound();
+});
+document.getElementById('btnNext4').addEventListener('click', function(){ goToScene(4); });
+
+/* ================= SCENE 5: виды волн + молекулы ================= */
+var typeCanvas = document.getElementById('typeCanvas');
+var typeCtx = typeCanvas.getContext('2d');
+var typeT = 0;
+var waveType = 'long'; // long | trans
+
+document.getElementById('btnLong').addEventListener('click', function(){
+  waveType = 'long'; clickSound(); initMolecules(); resetNext5();
+});
+document.getElementById('btnTrans').addEventListener('click', function(){
+  waveType = 'trans'; clickSound(); initMolecules(); resetNext5();
+});
+
+function resetNext5(){
+  document.getElementById('btnNext5').disabled = true;
+  document.getElementById('scene5Hint').textContent = 'Размещено: 0 / 6';
+}
+
+function drawType(){
+  var W = typeCanvas.width, H = typeCanvas.height;
+  typeCtx.clearRect(0,0,W,H);
+  typeT += 0.05;
+
+  if(waveType === 'long'){
+    // продольная — сжатия/разрежения
+    var N = 40;
+    for(var i=0;i<N;i++){
+      var baseX = (i+1) * (W/(N+1));
+      var shift = Math.sin(typeT - i*0.3) * 12;
+      var x = baseX + shift;
+      var density = 0.5 + 0.5 * Math.sin(typeT - i*0.3);
+      typeCtx.beginPath();
+      typeCtx.fillStyle = 'rgba(255,46,196,' + (0.4 + density*0.6) + ')';
+      typeCtx.shadowBlur = 15; typeCtx.shadowColor = '#ff2ec4';
+      typeCtx.arc(x, H/2, 6 + density*3, 0, Math.PI*2);
+      typeCtx.fill();
+    }
+    typeCtx.shadowBlur = 0;
+    typeCtx.fillStyle = '#00e5ff';
+    typeCtx.font = '14px Segoe UI';
+    typeCtx.fillText('Продольная (звук в воздухе)', 20, 30);
+  } else {
+    // поперечная — синусоида
+    typeCtx.strokeStyle = 'rgba(0,229,255,.4)';
+    typeCtx.lineWidth = 2;
+    typeCtx.beginPath();
+    for(var x2=0; x2<W; x2+=4){
+      var y2 = H/2 + Math.sin(x2*0.02 + typeT) * 50;
+      if(x2===0) typeCtx.moveTo(x2,y2); else typeCtx.lineTo(x2,y2);
+    }
+    typeCtx.stroke();
+    for(var k=0;k<20;k++){
+      var xx = (k+1) * (W/21);
+      var yy = H/2 + Math.sin(xx*0.02 + typeT) * 50;
+      typeCtx.beginPath();
+      typeCtx.fillStyle = '#ff2ec4';
+      typeCtx.shadowBlur = 15; typeCtx.shadowColor = '#ff2ec4';
+      typeCtx.arc(xx, yy, 6, 0, Math.PI*2);
+      typeCtx.fill();
+    }
+    typeCtx.shadowBlur = 0;
+    typeCtx.fillStyle = '#00e5ff';
+    typeCtx.font = '14px Segoe UI';
+    typeCtx.fillText('Поперечная (волны на воде, струна)', 20, 30);
+  }
+  requestAnimationFrame(drawType);
+}
+drawType();
+
+/* молекулы */
+var molPlaced = 0;
+function initMolecules(){
+  var box = document.getElementById('molecules');
+  box.innerHTML = '';
+  molPlaced = 0;
+  var W = box.clientWidth || 700;
+
+  // цели (позиции сжатия/разрежения)
+  var targetPos = [0.12, 0.25, 0.40, 0.55, 0.70, 0.85];
+  window._molTargets = targetPos.map(function(p){ return p*W; });
+
+  // пунктирные цели
+  targetPos.forEach(function(p){
+    var t = document.createElement('div');
+    t.className = 'target';
+    t.style.left = (p*100) + '%';
+    box.appendChild(t);
+  });
+
+  // молекулы в случайных позициях
+  for(var i=0;i<6;i++){
+    (function(idx){
+      var m = document.createElement('div');
+      m.className = 'molecule';
+      var startPct = [0.05, 0.20, 0.35, 0.50, 0.65, 0.80][idx] * 100;
+      // перемешаем стартовые
+      startPct = 5 + Math.random()*90;
+      m.style.left = startPct + '%';
+      m.dataset.idx = idx;
+      m.addEventListener('click', function(){
+        if(m.classList.contains('placed')) return;
+        // ставим в ближайшую незанятую цель
+        var used = {};
+        var placed = document.querySelectorAll('#molecules .molecule.placed');
+        for(var j=0;j<placed.length;j++) used[placed[j].dataset.target] = true;
+        var best = -1, bestDist = 1e9;
+        for(var k=0;k<targetPos.length;k++){
+          if(used[k]) continue;
+          var d = Math.abs(targetPos[k]*100 - parseFloat(m.style.left));
+          if(d < bestDist){ bestDist = d; best = k; }
+        }
+        if(best === -1) return;
+        m.style.left = (targetPos[best]*100) + '%';
+        m.dataset.target = best;
+        m.classList.add('placed');
+        molPlaced++;
+        beep(500 + molPlaced*80, 0.1, 'triangle', 0.15);
+        document.getElementById('scene5Hint').textContent = 'Размещено: ' + molPlaced + ' / 6';
+        if(molPlaced >= 6){
+          document.getElementById('btnNext5').disabled = false;
+          document.getElementById('scene5Hint').textContent = 'Отлично! Звук собран 🎵';
+          correctSound();
+        }
+      });
+      box.appendChild(m);
+    })(i);
+  }
+}
+document.getElementById('btnNext5').addEventListener('click', function(){ goToScene(5); });
+
+/* ================= SCENE 6: карточки + пары ================= */
+var pairData = [
+  { left: 'Эхолокация', right: 'Отражение ультразвука' },
+  { left: 'УЗИ', right: 'Отражение от тканей' },
+  { left: 'Сейсмология', right: 'Сейсмические волны' },
+  { left: 'Музыка', right: 'Стоячие волны' }
+];
+var pairsDone = 0;
+var selectedLeft = null;
+
+function initPairs(){
+  pairsDone = 0;
+  selectedLeft = null;
+  document.getElementById('scene6Hint').textContent = 'Собрано пар: 0 / 4';
+  document.getElementById('btnNext6').disabled = true;
+
+  var leftCol = document.getElementById('pairLeft');
+  var rightCol = document.getElementById('pairRight');
+  leftCol.innerHTML = ''; rightCol.innerHTML = '';
+
+  // левая колонка по порядку
+  pairData.forEach(function(p, i){
+    var d = document.createElement('div');
+    d.className = 'pair-item';
+    d.textContent = p.left;
+    d.dataset.idx = i;
+    d.dataset.side = 'left';
+    d.addEventListener('click', function(){
+      if(d.classList.contains('matched')) return;
+      var sel = document.querySelectorAll('#pairLeft .pair-item.selected');
+      for(var s=0;s<sel.length;s++) sel[s].classList.remove('selected');
+      d.classList.add('selected');
+      selectedLeft = d;
+      clickSound();
+    });
+    leftCol.appendChild(d);
+  });
+
+  // правая колонка перемешана
+  var shuffled = pairData.map(function(p,i){ return {text:p.right, idx:i}; });
+  shuffled.sort(function(){ return Math.random()-0.5; });
+  shuffled.forEach(function(item){
+    var d = document.createElement('div');
+    d.className = 'pair-item';
+    d.textContent = item.text;
+    d.dataset.idx = item.idx;
+    d.dataset.side = 'right';
+    d.addEventListener('click', function(){
+      if(d.classList.contains('matched')) return;
+      if(!selectedLeft){ wrongSound(); return; }
+      if(selectedLeft.dataset.idx === d.dataset.idx){
+        selectedLeft.classList.add('matched');
+        selectedLeft.classList.remove('selected');
+        d.classList.add('matched');
+        selectedLeft = null;
+        pairsDone++;
+        correctSound();
+        document.getElementById('scene6Hint').textContent = 'Собрано пар: ' + pairsDone + ' / 4';
+        if(pairsDone >= 4){
+          document.getElementById('btnNext6').disabled = false;
+          document.getElementById('scene6Hint').textContent = 'Все пары собраны! 🎉';
+        }
+      } else {
+        wrongSound();
+        d.classList.add('wrong');
+        setTimeout(function(){ d.classList.remove('wrong'); }, 400);
+      }
+    });
+    rightCol.appendChild(d);
+  });
+}
+
+// карточки — переворот
+var cards = document.querySelectorAll('#cards .card');
+for(var ci=0; ci<cards.length; ci++){
+  cards[ci].addEventListener('click', function(){
+    this.classList.toggle('flipped');
+    clickSound();
+  });
+}
+document.getElementById('btnNext6').addEventListener('click', function(){ goToScene(6); });
+
+/* ================= SCENE 7: ТЕСТ ================= */
+var quizQuestions = [
+  { q: 'Что переносит механическая волна?', a: ['Вещество', 'Энергию', 'Заряд', 'Массу'], c: 1 },
+  { q: 'В какой среде звук распространяется быстрее всего?', a: ['Воздух', 'Вода', 'Сталь', 'Вакуум'], c: 2 },
+  { q: 'Формула связи периода и частоты:', a: ['T = ν', 'T = 1/ν', 'T = ν²', 'T = 2ν'], c: 1 },
+  { q: 'Звук — это какая волна?', a: ['Поперечная', 'Продольная', 'Электромагнитная', 'Стоячая'], c: 1 },
+  { q: 'Скорость звука в воздухе примерно равна:', a: ['34 м/с', '343 м/с', '3430 м/с', '3 м/с'], c: 1 },
+  { q: 'Что такое амплитуда?', a: ['Число колебаний в секунду', 'Максимальное отклонение от равновесия', 'Время одного колебания', 'Длина волны'], c: 1 },
+  { q: 'Единица измерения частоты:', a: ['Гц', 'м', 'с', 'кг'], c: 0 },
+  { q: 'Могут ли механические волны распространяться в вакууме?', a: ['Да', 'Нет', 'Только звук', 'Только свет'], c: 1 },
+  { q: 'Связь скорости, длины волны и частоты:', a: ['v = λ/ν', 'v = λ·ν', 'v = ν/λ', 'v = λ+ν'], c: 1 },
+  { q: 'Ультразвук — это:', a: ['ν < 20 Гц', 'ν > 20 кГц', 'ν = 20 Гц', 'Любой звук'], c: 1 }
+];
+
+var qIndex = 0, qScore = 0;
+
+function startQuiz(){
+  qIndex = 0; qScore = 0;
+  document.getElementById('quizResult').style.display = 'none';
+  document.getElementById('quizQuestion').style.display = 'block';
+  document.getElementById('quizOptions').style.display = 'flex';
+  document.getElementById('quizTitle').textContent = 'Итоговое тестирование';
+  showQuestion();
+}
+
+function showQuestion(){
+  var q = quizQuestions[qIndex];
+  document.getElementById('quizProgress').style.width = (qIndex / quizQuestions.length * 100) + '%';
+  document.getElementById('quizQuestion').textContent = (qIndex+1) + '. ' + q.q;
+  var opts = document.getElementById('quizOptions');
+  opts.innerHTML = '';
+  q.a.forEach(function(text, i){
+    var b = document.createElement('button');
+    b.className = 'btn';
+    b.type = 'button';
+    b.textContent = text;
+    b.addEventListener('click', function(){
+      // блокируем остальные
+      var all = opts.querySelectorAll('.btn');
+      for(var k=0;k<all.length;k++) all[k].disabled = true;
+      if(i === q.c){
+        b.classList.add('correct');
+        qScore++;
+        correctSound();
+      } else {
+        b.classList.add('wrong');
+        all[q.c].classList.add('correct');
+        wrongSound();
+      }
+      setTimeout(function(){
+        qIndex++;
+        if(qIndex < quizQuestions.length){
+          showQuestion();
+        } else {
+          showResult();
+        }
+      }, 900);
+    });
+    opts.appendChild(b);
+  });
+}
+
+function showResult(){
+  document.getElementById('quizProgress').style.width = '100%';
+  document.getElementById('quizQuestion').style.display = 'none';
+  document.getElementById('quizOptions').style.display = 'none';
+  var res = document.getElementById('quizResult');
+  res.style.display = 'flex';
+  var pct = Math.round(qScore / quizQuestions.length * 100);
+  document.getElementById('finalScore').textContent = qScore + ' / ' + quizQuestions.length;
+  var grade = pct >= 90 ? 'Отлично! 🏆' : pct >= 70 ? 'Хорошо! 👍' : pct >= 50 ? 'Неплохо, но повтори материал.' : 'Попробуй пройти курс заново.';
+  document.getElementById('finalText').textContent = pct + '% — ' + grade;
+  if(pct >= 70) correctSound(); else wrongSound();
+}
+
+document.getElementById('btnRestart').addEventListener('click', function(){
+  clickSound();
+  goToScene(0);
+});
+</script>