Files
Learn_System/frontend/textbooks/physics_11_ch1.html
T
Maxim Dolgolyov fb01e5aafb feat(phys11 W2): Глава 1 §4-§6 + Финал + ResonanceCurve/TransverseWave/LongitudinalWave
phys-fx.js (+3 компонента):
- PHYS.ResonanceCurve: график A(ω) при разных γ затухания, маркер ω₀ и текущей ω
- PHYS.TransverseWave: бегущая поперечная волна (струна) с красным маркером колеблющейся точки + скобка λ
- PHYS.LongitudinalWave: зоны сжатия/разрежения через 60 точек-молекул

physics_11_ch1.html (63→89 КБ):

§4 Резонанс:
- 2 теор. карточки (свобод./вынужд., резонанс ω≈ω₀, формула A(ω))
- Инт. 1: ResonanceCurve с ползунками γ и ω — видно как пик уменьшается с ростом затухания
- Инт. 2: верно/неверно (5)
- Инт. 3: что произойдёт (5, качели/мост Tacoma/солдатский шаг)
- Босс §4: 5 этапов, +70 XP

§5 Волны:
- 2 теор. карточки (определение, поперечные/продольные, λ=vT)
- Инт. 1: TransverseWave с 3 ползунками (A, λ, v) — красная точка показывает что частица колеблется на месте
- Инт. 2: LongitudinalWave (звук-аналог) с 2 ползунками
- Инт. 3: расчёт λ,v,T (5 input)
- Инт. 4: тип волны и свойства (5 MC)
- Босс §5: 5 этапов, +70 XP

§6 Звук:
- 2 теор. карточки (звук как продол. упруг. волна, диапазоны, громкость/высота/тембр)
- Инт. 1: LongitudinalWave (звуковая) с ползунками A, λ
- Инт. 2: расчёт λ звука в воздухе (5 input)
- Инт. 3: свойства звука (5 MC)
- Босс §6: 5 этапов, +65 XP

Финал главы 1:
- 4 интегральных босса (колебания, маятники+энергия, резонанс, волны+звук)
- Celebration: ачивка phys11_ch1_master + 100 XP бонус
- Сохранение в localStorage.physics11_achievements
2026-05-29 18:02:53 +03:00

1241 lines
99 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="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Физика 11 · Глава 1 · «Механические колебания и волны»</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/phys-fx.js?v=1"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#fafafa; --card:#fff; --card-soft:#f8fafc; --text:#0f172a; --ink:#0f172a; --muted:#64748b;
--border:#e2e8f0; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
--pri:#0891b2; --pri2:#0e7490; --pri-soft:#cffafe;
--acc:#06b6d4; --acc2:#0891b2; --acc-soft:#a5f3fc;
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
}
.dark{--bg:#06181a; --card:#0a2225; --card-soft:#0d2a2e; --text:#cffafe; --ink:#cffafe; --muted:#67e8f9; --border:#0f4750}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;font-size:15px}
button,input,select,textarea{font-family:inherit;font-size:inherit}
button{cursor:pointer;border:0;background:transparent;color:inherit}
a{color:inherit;text-decoration:none}
.ic{width:16px;height:16px;display:inline-block;flex-shrink:0;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;vertical-align:middle}
.hdr{position:relative;background:linear-gradient(110deg,#155e75 0%,#0891b2 55%,#a5f3fc 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(165,243,252,.2);min-height:130px}
.hdr::before{content:'ГЛАВА 1';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(5rem,15vw,11rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(255,255,255,.12);line-height:1;pointer-events:none;user-select:none;z-index:0}
.hdr-row{position:relative;z-index:1;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.3;padding-top:4px}
.hdr-sub{font-size:.85rem;opacity:.88;margin-top:6px;font-weight:500;line-height:1.4}
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.hdr-btn{padding:7px 12px;border-radius:9px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;text-decoration:none}
.hdr-btn:hover{background:rgba(255,255,255,.24)}
.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}
.col-main{min-width:0}
.hero{background:linear-gradient(135deg,var(--pri-soft) 0%,var(--acc-soft) 50%,var(--pri-soft) 100%);background-size:200% 200%;animation:heroShift 12s ease-in-out infinite;border:1px solid var(--border);border-radius:18px;padding:24px 22px;margin-bottom:24px;position:relative;overflow:hidden}
@keyframes heroShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
.hero::before{content:'\223F';position:absolute;right:0;top:-30px;font-size:clamp(2rem,12vw,8rem);font-weight:900;color:var(--pri);opacity:.10;line-height:1;pointer-events:none;font-family:'Unbounded',sans-serif}
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px;letter-spacing:-.01em}
.hero p{font-size:.95rem;color:var(--text);opacity:.88;margin-bottom:14px;max-width:640px}
.hero-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.btn-primary{padding:11px 22px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:11px;font-weight:700;font-size:.92rem;display:inline-flex;align-items:center;gap:8px;box-shadow:var(--sh2);transition:transform .15s,box-shadow .15s}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(0,0,0,.18)}
.hero-progress{flex:1;min-width:200px;max-width:280px}
.hp-label{font-size:.74rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:5px}
.hp-bar{height:8px;background:rgba(0,0,0,.12);border-radius:5px;overflow:hidden}
.hp-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:5px;width:0%;transition:width .6s cubic-bezier(.16,1,.3,1)}
.hp-text{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:4px;display:block}
.hero-xp-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,var(--warn,#f59e0b),var(--pri));color:#fff;border-radius:99px;font-size:.82rem;font-weight:800;letter-spacing:.02em;box-shadow:0 4px 12px rgba(0,0,0,.18);font-family:'Unbounded',sans-serif}
.psel{margin-bottom:24px}
.psel-title{font-size:.72rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px}
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:14px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;text-align:left;position:relative}
.psel-card:hover{transform:translateY(-3px);box-shadow:var(--sh2);border-color:var(--pri)}
.psel-card.active{border-color:var(--pri);background:linear-gradient(135deg,var(--pri-soft),var(--card));box-shadow:var(--sh2)}
.psel-card.active::after{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:13px 13px 0 0}
.psel-num{font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;color:var(--pri);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px}
.psel-name{font-size:.84rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:8px}
.psel-prog{height:4px;background:rgba(0,0,0,.10);border-radius:3px;overflow:hidden}
.psel-prog-fill{height:100%;background:var(--pri);width:0%;transition:width .4s}
.psel-card.final{background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft))}
.psel-card.final .psel-num{color:var(--warn)}
.psel-card.locked{opacity:.55}
.psel-card .psel-done{position:absolute;top:6px;right:6px;width:18px;height:18px;border-radius:50%;background:#10b981;display:none;align-items:center;justify-content:center;box-shadow:0 2px 6px rgba(16,185,129,.45);z-index:2}
.psel-card .psel-done svg{width:11px;height:11px;stroke:#fff;fill:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round}
.psel-card.done .psel-done{display:flex}
.sec{display:none;position:relative;animation:fadeIn .35s ease}
.sec.active{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.sec::before{content:attr(data-watermark);position:absolute;right:-20px;top:10%;font-family:'Unbounded',sans-serif;font-size:clamp(6rem,18vw,14rem);font-weight:900;color:transparent;-webkit-text-stroke:1.5px var(--pri-soft);line-height:1;pointer-events:none;user-select:none;z-index:0;opacity:.35}
.sec-header{margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--pri-soft);position:relative;z-index:1}
.sec-num{display:inline-block;padding:4px 10px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:7px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;margin-bottom:8px}
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:800;color:var(--pri2);letter-spacing:-.01em;line-height:1.25}
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:18px 20px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 24px rgba(0,0,0,.04);position:relative;z-index:1;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
.card:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(0,0,0,.06),0 16px 36px rgba(0,0,0,.08)}
.card-header{display:flex;align-items:center;gap:10px;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
.card-icon{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff}
.card-icon.repeat{background:#0ea5e9}.card-icon.theory{background:#8b5cf6}.card-icon.algo{background:#f59e0b}.card-icon.rule{background:#ec4899}.card-icon.example{background:#10b981}.card-icon.oral{background:#06b6d4}
.card-icon .ic{width:18px;height:18px}
.card-title{font-family:'Unbounded',sans-serif;font-size:.82rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);flex:1}
.card-num{font-size:.74rem;font-weight:700;color:var(--muted);background:var(--pri-soft);padding:3px 7px;border-radius:5px}
.card-body{font-size:.94rem;line-height:1.65}
.card-body p{margin-bottom:8px}
.card-body p:last-child{margin-bottom:0}
.card-body ul{margin:6px 0 6px 22px;line-height:1.7}
.btn{padding:8px 16px;border-radius:8px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:600;font-size:.88rem;transition:background .15s,border-color .15s,transform .1s}
.btn:hover{background:var(--pri-soft);border-color:var(--pri)}
.btn:active{transform:scale(.96)}
.btn.primary{background:var(--pri);color:#fff;border-color:var(--pri)}
.btn.primary:hover{background:var(--pri2);border-color:var(--pri2)}
.feedback{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none}
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
.wg{background:linear-gradient(135deg,var(--card),var(--pri-soft));border:1.5px solid var(--pri);border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1}
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.wg-badge{padding:4px 9px;background:var(--pri);color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--pri2);flex:1}
.wg-help{font-size:.88rem;color:var(--text);margin-bottom:12px;line-height:1.55;background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft));border-left:4px solid var(--warn);padding:9px 14px;border-radius:9px}
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);transition:border-color .15s;font-family:'JetBrains Mono',monospace;width:140px}
.tinp:focus{outline:0;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-soft)}
.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px;align-items:center}
.opts-row{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.opt-btn{padding:8px 14px;background:var(--card);border:1.5px solid var(--border);border-radius:9px;font-weight:700;font-size:.88rem;color:var(--text);cursor:pointer;transition:all .15s}
.opt-btn:hover{background:var(--pri-soft);border-color:var(--pri)}
.opt-btn.correct{background:var(--ok-bg);border-color:var(--ok);color:#065f46}
.opt-btn.wrong{background:var(--fail-bg);border-color:var(--fail);color:#991b1b}
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.sidecard-row{margin-bottom:8px;font-size:.84rem;line-height:1.55}
.sidecard-row b{color:var(--pri);font-weight:700}
.sidecard-row:last-child{margin-bottom:0}
@media(max-width:980px){.col-side{position:static;max-height:none}}
.xp-card{background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft));border:1.5px solid var(--warn);border-radius:12px;padding:14px;margin-bottom:14px}
.xp-card-title{font-size:.68rem;font-weight:800;color:var(--warn);text-transform:uppercase;letter-spacing:.07em;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between}
.xp-level{font-size:1.1rem;font-weight:900;color:#92400e;font-family:'Unbounded',sans-serif}
.xp-bar{height:9px;background:rgba(0,0,0,.10);border-radius:6px;overflow:hidden;margin:7px 0}
.xp-fill{height:100%;background:linear-gradient(90deg,var(--warn),var(--pri));border-radius:6px;transition:width .5s cubic-bezier(.4,0,.2,1)}
.xp-nums{font-size:.74rem;color:var(--muted);display:flex;justify-content:space-between}
.sec-nav{display:flex;gap:10px;margin-top:24px;padding-top:20px;border-top:1px solid var(--border);justify-content:space-between;flex-wrap:wrap}
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,var(--pri),var(--warn));color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(0,0,0,.32);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
.ach-popup.show{display:flex}
.fx-holder{margin:10px 0;padding:0;text-align:center}
.fx-sliders{margin-top:10px;display:flex;flex-wrap:wrap;gap:4px;background:rgba(255,255,255,.5);border-radius:9px;padding:6px 4px}
.fx-row{display:flex;gap:14px;flex-wrap:wrap;align-items:flex-start;justify-content:center}
.fx-cell{flex:1 1 280px;max-width:340px}
.fx-cell-label{font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);margin-bottom:6px}
.boss-card{background:var(--card);border:2px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;transition:border-color .35s,box-shadow .35s,transform .2s}
.boss-card.solved{border-color:#10b981;box-shadow:0 0 0 3px rgba(16,185,129,.18)}
.boss-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
.boss-tag{font-size:.7rem;font-weight:800;padding:3px 9px;border-radius:99px;background:var(--pri-soft);color:var(--pri2);letter-spacing:.04em;text-transform:uppercase}
.boss-title{font-family:'Unbounded',sans-serif;font-weight:800;color:var(--text);font-size:1.02rem;flex:1;min-width:0}
.boss-q{padding:12px 14px;background:var(--pri-soft);border-radius:10px;font-size:.96rem;line-height:1.55;margin-bottom:10px;color:var(--text)}
.boss-input{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);font-family:'JetBrains Mono',monospace;width:140px;text-align:center;font-size:.95rem}
.boss-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
.boss-fb{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none;line-height:1.45}
.boss-fb.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
.boss-fb.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
.stub-note{padding:18px 22px;background:linear-gradient(135deg,var(--pri-soft),var(--warn-bg));border:1.5px dashed var(--pri);border-radius:13px;text-align:center;color:var(--text);margin-bottom:14px}
.stub-note h3{font-family:'Unbounded',sans-serif;color:var(--pri2);margin-bottom:8px;font-size:1.05rem}
.stub-note p{color:var(--muted);font-size:.9rem;line-height:1.55}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-row">
<div>
<h1>Физика 11 · Глава 1</h1>
<div class="hdr-sub">Механические колебания и волны · гармонические колебания, маятники, энергия, резонанс, волны</div>
</div>
<div class="hdr-side">
<a href="/textbook/physics-11" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 11</a>
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
</div>
</div>
</header>
<main class="main">
<div class="col-main">
<section class="hero">
<h2>Механические колебания и волны</h2>
<p>Колебания — повторяющиеся движения вокруг положения равновесия. Изучаем гармонические колебания, маятники, превращения энергии, резонанс и распространение колебаний в виде волн (включая звук).</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p1')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 1</button>
<div class="hero-progress">
<span class="hp-label">Прогресс по главе</span>
<div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div>
<span id="hero-hp-text" class="hp-text">0%</span>
</div>
<div id="hero-xp-badge" class="hero-xp-badge"></div>
</div>
</section>
<section class="psel">
<div class="psel-title">Параграфы главы</div>
<div id="psel-grid" class="psel-grid"></div>
</section>
<section id="sec-p1" class="sec" data-watermark="&#8767;"><div class="sec-header"><span class="sec-num">§ 1</span><h2 class="sec-h">Колебательное движение. Гармонические колебания</h2></div><div id="p1-body"></div></section>
<section id="sec-p2" class="sec" data-watermark="&#9701;"><div class="sec-header"><span class="sec-num">§ 2</span><h2 class="sec-h">Пружинный и математический маятники</h2></div><div id="p2-body"></div></section>
<section id="sec-p3" class="sec" data-watermark="E"><div class="sec-header"><span class="sec-num">§ 3</span><h2 class="sec-h">Превращения энергии при гарм. колебаниях</h2></div><div id="p3-body"></div></section>
<section id="sec-p4" class="sec" data-watermark="&#9776;"><div class="sec-header"><span class="sec-num">§ 4</span><h2 class="sec-h">Свободные и вынужденные колебания. Резонанс</h2></div><div id="p4-body"></div></section>
<section id="sec-p5" class="sec" data-watermark="&#8767;"><div class="sec-header"><span class="sec-num">§ 5</span><h2 class="sec-h">Распр. колебаний в упругой среде</h2></div><div id="p5-body"></div></section>
<section id="sec-p6" class="sec" data-watermark="&#119082;"><div class="sec-header"><span class="sec-num">§ 6</span><h2 class="sec-h">Звуковые волны</h2></div><div id="p6-body"></div></section>
<section id="sec-final" class="sec" data-watermark="&#9733;"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#d97706,#f59e0b)">&#9733;</span><h2 class="sec-h">Финал главы 1</h2></div><div id="final-body"></div></section>
</div>
<aside class="col-side"><div id="sidebar-content"></div></aside>
</main>
<footer class="foot">Интерактивный учебник «Физика 11» · Глава 1 · «Механические колебания и волны» · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
<script>
'use strict';
const STATE = { current:'p1', progress:{}, achievements:new Map(), xp:0, level:1 };
const TOTAL_PARAS = 6;
const _TB_SLUG = 'physics-11-ch1';
const PARAS = [
{ id:'p1', num:'§ 1', name:'Гармонические колебания', sub:'$T, \\nu, \\omega$', built:true },
{ id:'p2', num:'§ 2', name:'Маятники', sub:'$T = 2\\pi\\sqrt{m/k}$', built:true },
{ id:'p3', num:'§ 3', name:'Превращения энергии', sub:'$W_{мех} = \\text{const}$', built:true },
{ id:'p4', num:'§ 4', name:'Резонанс', sub:'$\\omega_{рез} \\approx \\omega_0$', built:true },
{ id:'p5', num:'§ 5', name:'Волны', sub:'$\\lambda = vT$', built:true },
{ id:'p6', num:'§ 6', name:'Звук', sub:'16 Гц 20 кГц', built:true },
{ id:'final', num:'★', name:'Финал главы', sub:'4 интегр. босса', final:true, built:true }
];
PARAS.forEach(p => { STATE.progress[p.id] = 0; });
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
function _xpForLevel(lv){ return (lv-1)*(lv-1)*100; }
const ACH_LABELS = {
p1_done:'§1 — гармонические колебания освоены',
p2_done:'§2 — маятники освоены',
p3_done:'§3 — превращения энергии освоены',
p4_done:'§4 — резонанс освоен',
p5_done:'§5 — волны освоены',
p6_done:'§6 — звук освоен',
start:'Начало главы 1!',
ch1_done:'Глава 1 пройдена — колебания и волны!'
};
function loadProgress(){
try{
const s=localStorage.getItem('physics11_ch1_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
const a=localStorage.getItem('physics11_ch1_achievements');
if(a){ const p=JSON.parse(a); if(p&&typeof p==='object'){ for(const[id,t] of Object.entries(p)) STATE.achievements.set(id,(t&&t!==id)?t:(ACH_LABELS[id]||id)); } }
STATE.xp=+(localStorage.getItem('physics11_xp')||0); STATE.level=calcLevel(STATE.xp);
}catch(e){}
}
function saveProgress(){
try{
localStorage.setItem('physics11_ch1_progress', JSON.stringify(STATE.progress));
localStorage.setItem('physics11_ch1_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
localStorage.setItem('physics11_xp', String(STATE.xp));
}catch(e){}
}
function bumpProgress(key, delta){
STATE.progress[key]=Math.max(0,Math.min(100,(STATE.progress[key]||0)+delta));
saveProgress(); refreshProgressUI();
if(STATE.progress[key]>=50) markParaRead(key);
}
const _markedRead=new Set();
let _pendingProgressBody=null, _progressTimer=null;
function _flushProgress(){
const body=_pendingProgressBody; _pendingProgressBody=null; if(!body) return;
const tok=(window.LS&&LS.getToken)?LS.getToken():''; if(!tok) return;
fetch('/api/textbooks/'+_TB_SLUG+'/progress',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+tok},body:JSON.stringify(body),keepalive:true}).catch(()=>{});
}
function _queueProgress(patch){ _pendingProgressBody=Object.assign(_pendingProgressBody||{},patch); if(_progressTimer) clearTimeout(_progressTimer); _progressTimer=setTimeout(_flushProgress, 600); }
function markLastPara(id){ _queueProgress({last_para:id}); }
function markParaRead(id){ if(_markedRead.has(id)) return; _markedRead.add(id); _queueProgress({mark_read:id}); }
window.addEventListener('beforeunload', _flushProgress);
function addXp(n,src){
if(!n) return;
const prev=STATE.level; STATE.xp=Math.max(0,(STATE.xp||0)+n); STATE.level=calcLevel(STATE.xp);
saveProgress(); refreshProgressUI();
if(window.LS&&window.LS.xp) window.LS.xp.add(n,'physics11-ch1-'+(src||'misc'));
if(STATE.level>prev){
const pop=document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent='Уровень '+STATE.level+'!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),2600); }
}
}
function refreshProgressUI(){
const total=Math.round(Object.values(STATE.progress).reduce((a,b)=>a+b,0)/TOTAL_PARAS);
const f=document.getElementById('hero-hp-fill'); if(f) f.style.width=total+'%';
const t=document.getElementById('hero-hp-text'); if(t) t.textContent=total+'% пройдено';
document.querySelectorAll('[data-prog-card]').forEach(el=>{ const k=el.dataset.progCard; const fl=el.querySelector('.psel-prog-fill'); if(fl) fl.style.width=(STATE.progress[k]||0)+'%'; if((STATE.progress[k]||0)>=100) el.classList.add('done'); });
const xpBadge=document.getElementById('hero-xp-badge');
if(xpBadge){ xpBadge.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:13px;height:13px"><polygon points="12 2 22 20 2 20"/></svg> Ур. '+STATE.level+' \xb7 '+(STATE.xp||0)+' XP'; }
if(STATE.current && document.getElementById('sidebar-content')){ try{ buildSidebar(STATE.current); }catch(e){} }
}
function achievement(id,text){
if(STATE.achievements.has(id)) return;
STATE.achievements.set(id, text||ACH_LABELS[id]||id); saveProgress();
const pop=document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent=text||ACH_LABELS[id]||id; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'),3300); }
addXp(20,'ach-'+id);
}
function buildParaSelector(){
const g=document.getElementById('psel-grid'); g.innerHTML='';
PARAS.forEach(p=>{
const card=document.createElement('div');
card.className='psel-card'+(p.final?' final':'')+(p.built?'':' locked');
card.dataset.id=p.id; card.dataset.progCard=p.id;
card.innerHTML='<div class="psel-num">'+p.num+'</div><div class="psel-name">'+p.name+'</div><div class="psel-prog"><div class="psel-prog-fill"></div></div><div class="psel-done"><svg viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg></div>';
card.addEventListener('click', ()=>goTo(p.id));
g.appendChild(card);
});
if(window.renderMathInElement) try{ renderMath(g); }catch(e){}
}
const BUILT=new Set();
const BUILDERS = { p1:()=>buildP1(), p2:()=>buildP2(), p3:()=>buildP3(), p4:()=>buildP4(), p5:()=>buildP5(), p6:()=>buildP6(), final:()=>buildFinal() };
function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } }
function goTo(id){
STATE.current=id; ensureBuilt(id);
document.querySelectorAll('.sec').forEach(s=>s.classList.remove('active'));
const el=document.getElementById('sec-'+id); if(el) el.classList.add('active');
document.querySelectorAll('.psel-card').forEach(c=>c.classList.toggle('active', c.dataset.id===id));
buildSidebar(id);
window.scrollTo({top:0,behavior:'smooth'});
if((STATE.progress[id]||0)<10) bumpProgress(id, 10);
if(window.renderMathInElement) setTimeout(()=>renderMath(el), 0);
markLastPara(id);
}
const SIDEBARS = {
p1:{title:'Шпаргалка § 1', rows:[['Период','$T = \\Delta t / N$'],['Частота','$\\nu = 1/T$'],['Цикл. частота','$\\omega = 2\\pi\\nu = 2\\pi/T$'],['Уравнение','$x = A\\cos(\\omega t + \\varphi_0)$'],['Размерности','$[T]=$ с, $[\\nu]=$ Гц, $[\\omega]=$ рад/с']]},
p2:{title:'Шпаргалка § 2', rows:[['Пружинный','$T = 2\\pi\\sqrt{m/k}$'],['Математ.','$T = 2\\pi\\sqrt{l/g}$'],['Условие','малые амплитуды'],['Не зависит от','амплитуды (для гарм.)']]},
p3:{title:'Шпаргалка § 3', rows:[['$W_{кинет}$','$\\dfrac{mv^2}{2}$'],['$W_{потенц}$','$\\dfrac{kx^2}{2}$'],['$W_{мех}$','$\\dfrac{kA^2}{2} = $ const'],['Связь','$k = m\\omega^2$']]},
p4:{title:'Шпаргалка § 4', rows:[['Свободные','без внеш. силы, затухают'],['Вынужденные','$F_{вынужд} = F_0\\cos(\\omega t)$'],['Резонанс','$\\omega \\to \\omega_0$, $A \\to $ max'],['Декремент','$\\gamma$ — затухание']]},
p5:{title:'Шпаргалка § 5', rows:[['Длина волны','$\\lambda = vT = v/\\nu$'],['Скорость','$v = \\lambda\\nu$'],['Поперечная','колебание $\\perp$ распр.'],['Продольная','колебание $\\parallel$ распр.'],['Примеры','струна (попереч.), звук (продол.)']]},
p6:{title:'Шпаргалка § 6', rows:[['Слышимый','16 Гц 20 кГц'],['Инфразвук','$\\nu < 16$ Гц'],['Ультразвук','$\\nu > 20$ кГц'],['$v$ в возд.','$\\approx 340$ м/с'],['$v$ в воде','$\\approx 1500$ м/с'],['Природа','продольная упругая волна']]},
final:{title:'Финал главы 1', rows:[['§ 1 § 6','Все темы главы'],['Боссов','4 интегрированных'],['Награда','+100 XP + ачивка ch1_done']]}
};
const TIPS=[
{sec:'p1',html:'§ 1 — крути ползунки осциллограммы. Главное: $\\omega = 2\\pi/T$ связывает все 3 величины.'},
{sec:'p2',html:'§ 2 — для пружины период зависит от $m, k$, для матем. от $l, g$. <b>Амплитуда не входит</b>!'},
{sec:'p3',html:'§ 3 — пока $W_к$ растёт, $W_п$ убывает. Сумма постоянна: $W_{мех} = kA^2/2$.'},
{sec:'p4',html:'§ 4 — двигай ползунок $\\gamma$ (затухание). При $\\gamma \\to 0$ резонансный пик становится бесконечно острым.'},
{sec:'p5',html:'§ 5 — $\\lambda = vT$ — главная формула. Поперечные: волна на струне. Продольные: звук.'},
{sec:'p6',html:'§ 6 — звук = продольная упругая волна. В вакууме <b>не распространяется</b>! $v_{зв}^{возд} \\approx 340$ м/с.'},
{sec:'final',html:'Финал главы 1 — 4 интегральных босса на все темы главы. Победа = ачивка ch1_done + 100 XP.'}
];
function buildSidebar(id){
const box=document.getElementById('sidebar-content');
const sb=SIDEBARS[id]||SIDEBARS[PARAS[0].id];
let html='';
const xpForLv=_xpForLevel(STATE.level), xpNext=_xpForLevel(STATE.level+1);
const xpInLv=STATE.xp-xpForLv, xpRange=xpNext-xpForLv;
const xpPct=xpRange>0?Math.round(xpInLv/xpRange*100):100;
html+='<div class="xp-card"><div class="xp-card-title"><span>XP-прогресс</span><span class="xp-level">Ур. '+STATE.level+'</span></div><div class="xp-bar"><div class="xp-fill" style="width:'+xpPct+'%"></div></div><div class="xp-nums"><span>'+STATE.xp+' XP</span><span>'+xpNext+' XP</span></div></div>';
html+='<div class="sidecard"><h4>'+sb.title+'</h4>';
sb.rows.forEach(([k,v])=>{ html+='<div class="sidecard-row"><b>'+k+'</b>'+(v?' — '+v:'')+'</div>'; });
html+='</div>';
const tip=TIPS.find(t=>t.sec===id)||TIPS[0];
if(tip){
html+='<div class="sidecard" style="background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft));border-color:var(--warn)"><h4 style="color:#92400e;display:flex;align-items:center;gap:6px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><polygon points="12,2 22,20 2,20"/></svg>Подсказка</h4><div class="sidecard-row" style="margin-bottom:0;font-size:.82rem;line-height:1.55">'+tip.html+'</div></div>';
}
if(STATE.achievements.size>0){
html+='<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">'+STATE.achievements.size+'</span></h4>';
[...STATE.achievements.values()].slice(-4).forEach(text=>{ html+='<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">&#10003; '+text+'</div>'; });
html+='</div>';
}
box.innerHTML=html;
if(window.renderMathInElement) try{ renderMath(box); }catch(e){}
}
function initTheme(){
const t=localStorage.getItem('physics11_theme')||localStorage.getItem('theme')||'light';
if(t==='dark') document.documentElement.classList.add('dark');
document.getElementById('theme-lab').textContent=t==='dark'?'Светлая':'Тёмная';
document.getElementById('theme-btn').addEventListener('click', ()=>{
document.documentElement.classList.toggle('dark');
const dark=document.documentElement.classList.contains('dark');
localStorage.setItem('physics11_theme', dark?'dark':'light');
localStorage.setItem('theme', dark?'dark':'light');
document.getElementById('theme-lab').textContent=dark?'Светлая':'Тёмная';
});
}
function renderMath(root){ if(window.renderMathInElement){ try{ renderMathInElement(root, {delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false}); }catch(e){} } }
const ICONS = {
repeat:'<svg class="ic" viewBox="0 0 24 24"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',
theory:'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>',
algo:'<svg class="ic" viewBox="0 0 24 24"><polyline points="17 11 21 7 17 3"/><line x1="21" y1="7" x2="9" y2="7"/><polyline points="7 13 3 17 7 21"/><line x1="3" y1="17" x2="15" y2="17"/></svg>',
rule:'<svg class="ic" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>',
example:'<svg class="ic" viewBox="0 0 24 24"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 13c1 1 2 2 2 4h4c0-2 1-3 2-4a7 7 0 0 0-4-13z"/></svg>'
};
function makeCard(kind, title, num, body){
const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример'};
return '<div class="card"><div class="card-header"><div class="card-icon '+kind+'">'+ICONS[kind]+'</div><div class="card-title">'+(labels[kind]||'')+(title&&title!==labels[kind]?' \xb7 '+title:'')+'</div>'+(num?'<div class="card-num">'+num+'</div>':'')+'</div><div class="card-body">'+body+'</div></div>';
}
function secNavFor(curId){
const idx = PARAS.findIndex(p => p.id === curId);
const prev = idx > 0 ? PARAS[idx-1].id : null;
const next = idx < PARAS.length - 1 ? PARAS[idx+1].id : null;
const NAMES = {p1:'\xA71',p2:'\xA72',p3:'\xA73',p4:'\xA74',p5:'\xA75',p6:'\xA76',final:'Финал'};
let h='<div class="sec-nav">';
h+=prev?'<button class="btn" onclick="goTo(\''+prev+'\')"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> '+NAMES[prev]+'</button>':'<span></span>';
h+=next?'<button class="btn primary" onclick="goTo(\''+next+'\')">'+NAMES[next]+' <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>':'<span></span>';
h+='</div>'; return h;
}
function readButton(paraId){
const p = PARAS.find(x => x.id === paraId);
const labelTail = p && p.final ? 'финал' : (p ? p.num : '\xA7?');
return '<div style="margin-top:18px;display:flex;justify-content:center"><button class="btn primary" id="'+paraId+'-read-btn">'
+'<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>'
+' Я прочитал — '+labelTail+' (+10 XP)</button></div>';
}
function wireReadBtn(paraId){
const btn = document.getElementById(paraId+'-read-btn'); if(!btn) return;
btn.addEventListener('click', ()=>{
addXp(10, paraId+'-read'); bumpProgress(paraId, 30);
btn.textContent='Прочитано! +10 XP'; btn.disabled=true; btn.style.opacity=.6;
const aId = paraId+'_done';
if(ACH_LABELS[aId]) achievement(aId);
});
}
function normalizeAns(s){
return String(s||'').toLowerCase().replace(/\s+/g,'').replace(/°/g,'').replace(/sqrt/g,'√').replace(/корень/g,'√').replace(/,/g,'.');
}
function makeBoss(id, def){
const stage = (typeof def.stage === 'number') ? def.stage : 0;
const solved = !!def.solved;
const total = def.stages.length;
const stageObj = def.stages[Math.min(stage, total-1)];
let optsHtml = '';
if(solved){
return '<div class="boss-card solved" id="boss-'+id+'"><div class="boss-head"><span class="boss-tag">'+(def.tag||'Босс')+'</span><span class="boss-title">'+def.title+'</span></div><div class="boss-q">Побеждён! +'+def.xp+' XP получены.</div></div>';
}
if(stageObj.type === 'mc'){
optsHtml = '<div class="opts-row">';
stageObj.opts.forEach((o,i)=>{ optsHtml += '<button class="opt-btn" data-i="'+i+'">'+o+'</button>'; });
optsHtml += '</div>';
} else {
optsHtml = '<div class="boss-row"><input class="boss-input" id="boss-'+id+'-inp" placeholder="ответ"><button class="btn primary" id="boss-'+id+'-go">Атака</button></div>';
}
return '<div class="boss-card" id="boss-'+id+'"><div class="boss-head"><span class="boss-tag">'+(def.tag||'Босс')+'</span><span class="boss-title">'+def.title+' — этап '+(stage+1)+' / '+total+'</span></div><div class="boss-q">'+stageObj.q+'</div>'+optsHtml+'<div class="boss-fb" id="boss-'+id+'-fb"></div></div>';
}
function bindBoss(id, def, state, save, onWin){
const card = document.getElementById('boss-'+id);
if(!card || state.solved) return;
const stageObj = def.stages[state.stage];
const fb = document.getElementById('boss-'+id+'-fb');
function advance(){
state.stage++;
if(state.stage >= def.stages.length){
state.solved = true; save(); addXp(def.xp, 'boss-'+id);
if(onWin) onWin();
} else { save(); }
rebuildBoss(id, def, state, save, onWin);
}
if(stageObj.type === 'mc'){
card.querySelectorAll('.opt-btn').forEach(btn=>{
btn.addEventListener('click', ()=>{
const i = +btn.dataset.i;
if(i === stageObj.correct){
btn.classList.add('correct');
fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+(stageObj.explain||''); fb.style.display='block'; renderMath(fb);
setTimeout(advance, 700);
} else {
btn.classList.add('wrong');
fb.className='feedback fail'; fb.innerHTML='&#10007; Не так. '+(stageObj.explain||''); fb.style.display='block'; renderMath(fb);
}
});
});
} else {
const inp = document.getElementById('boss-'+id+'-inp');
const go = document.getElementById('boss-'+id+'-go');
function attack(){
const v = normalizeAns(inp.value);
const ans = Array.isArray(stageObj.a) ? stageObj.a.map(normalizeAns) : [normalizeAns(stageObj.a)];
if(ans.indexOf(v) >= 0){
fb.className='feedback ok'; fb.innerHTML='&#10003; Верно! '+(stageObj.explain||''); fb.style.display='block'; renderMath(fb);
setTimeout(advance, 600);
} else {
fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+(stageObj.explain||''); fb.style.display='block'; renderMath(fb);
}
}
go.addEventListener('click', attack);
inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); attack(); } });
}
}
function rebuildBoss(id, def, state, save, onWin){
const card = document.getElementById('boss-'+id);
if(!card) return;
card.outerHTML = makeBoss(id, Object.assign({}, def, state));
bindBoss(id, def, state, save, onWin);
renderMath(document.getElementById('boss-'+id));
}
function makeAndBindBoss(slotId, id, def, state, save, onWin){
const slot = document.getElementById(slotId); if(!slot) return;
slot.innerHTML = makeBoss(id, Object.assign({}, def, state));
bindBoss(id, def, state, save, onWin);
renderMath(slot);
}
function ensureFx(cb){ if(window.PHYS) return cb(); setTimeout(()=>ensureFx(cb), 60); }
/* ===== §1 ===== */
function buildP1(){
const box = document.getElementById('p1-body'); if(!box) return;
let html = '';
html += makeCard('theory', 'Колебательное движение', '§ 1.1',
'<p><b>Колебательное движение</b> — повторяющееся (периодическое) движение тела вокруг положения равновесия.</p>'
+ '<p>Примеры: маятник часов, груз на пружине, биение сердца, листья на ветру, струна гитары.</p>'
+ '<p>Если значения физических величин повторяются через равные промежутки времени, колебания называются <b>периодическими</b>.</p>');
html += makeCard('rule', 'Период, частота, цикл. частота', '§ 1.2',
'<p><b>Период $T$</b> — минимальный промежуток времени, за который повторяются значения всех физических величин:</p>'
+ '<p style="text-align:center;margin:6px 0">$$T = \\dfrac{\\Delta t}{N}$$</p>'
+ '<p>где $\\Delta t$ — промежуток времени, за который произошло $N$ колебаний.</p>'
+ '<p><b>Частота $\\nu$</b> — число колебаний в единицу времени:</p>'
+ '<p style="text-align:center;margin:6px 0">$$\\nu = \\dfrac{N}{\\Delta t} = \\dfrac{1}{T}$$</p>'
+ '<p>Единица частоты — <b>герц (Гц)</b>: $1$ Гц $= 1$ кол/с.</p>'
+ '<p><b>Циклическая (угловая) частота $\\omega$</b> — число колебаний за $2\\pi$ секунд:</p>'
+ '<p style="text-align:center;margin:6px 0">$$\\omega = 2\\pi\\nu = \\dfrac{2\\pi}{T}$$</p>'
+ '<p>Единица: рад/с.</p>');
html += makeCard('rule', 'Гармонические колебания', '§ 1.3',
'<p>Колебания, при которых координата меняется по закону косинуса (или синуса), называются <b>гармоническими</b>:</p>'
+ '<p style="text-align:center;margin:8px 0">$$x(t) = A\\cos(\\omega t + \\varphi_0)$$</p>'
+ '<p>где:</p>'
+ '<ul>'
+ '<li>$A$ — <b>амплитуда</b> (максимальное отклонение от равновесия);</li>'
+ '<li>$\\omega$ — циклическая частота;</li>'
+ '<li>$\\varphi_0$ — <b>начальная фаза</b> (в момент $t=0$);</li>'
+ '<li>$\\omega t + \\varphi_0$ — <b>фаза колебаний</b>.</li>'
+ '</ul>'
+ '<p>График $x(t)$ — синусоида (косинусоида), которая называется <b>осциллограммой</b>.</p>');
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><span class="wg-title">Осциллограмма — поиграй с амплитудой, частотой, фазой</span></div>'
+ '<div class="wg-help">Двигай ползунки и наблюдай за изменением графика $x(t) = A\\cos(\\omega t + \\varphi_0)$.</div>'
+ '<div class="fx-holder" id="fx-osc1"></div>'
+ '<div class="fx-sliders" id="fx-osc1-sl"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 2</span><span class="wg-title">Подсчёт $T, \\nu, \\omega$</span></div>'
+ '<div class="wg-help">Решено: <b id="i1-calc-score">0</b> / 5.</div>'
+ '<div id="i1-calc-q" style="margin:8px 0"></div><div class="actions"><input class="tinp" id="i1-calc-inp" placeholder="число"><button class="btn primary" id="i1-calc-go">Проверить</button></div><div class="feedback" id="i1-calc-fb"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 3</span><span class="wg-title">Свойства колебаний</span></div>'
+ '<div class="wg-help">Решено: <b id="i1-prop-score">0</b> / 5.</div>'
+ '<div id="i1-prop-q" style="margin:8px 0"></div><div class="opts-row" id="i1-prop-opts"></div><div class="feedback" id="i1-prop-fb"></div></div>';
html += '<div id="boss-1-slot"></div>';
html += readButton('p1');
html += secNavFor('p1');
box.innerHTML = html;
/* Mount Oscillogram + sliders */
ensureFx(()=>{
const oscEl = document.getElementById('fx-osc1');
const osc = new PHYS.Oscillogram(oscEl, {width:560, height:200, A:0.7, omega:2*Math.PI, phi0:0, label:'x(t)'});
const slBox = document.getElementById('fx-osc1-sl');
const slA = PHYS.util.slider({label:'A (амплитуда)', min:0.1, max:1.0, step:0.05, value:0.7, fmt:v=>v.toFixed(2), onChange:v=>osc.setA(v)});
const slW = PHYS.util.slider({label:'ω (рад/с)', min:1, max:12, step:0.2, value:Math.round(2*Math.PI*10)/10, fmt:v=>v.toFixed(1), onChange:v=>osc.setOmega(v)});
const slPhi = PHYS.util.slider({label:'φ₀ (рад)', min:-Math.PI, max:Math.PI, step:0.1, value:0, fmt:v=>v.toFixed(1), onChange:v=>osc.setPhi(v)});
slBox.innerHTML = slA.html + slW.html + slPhi.html;
slA.wire(slBox); slW.wire(slBox); slPhi.wire(slBox);
});
runQuizInput('i1-calc', I1_CALC_ITEMS, 14);
runQuizMC('i1-prop', I1_PROP_ITEMS, 12);
const bs = loadBossState('boss-1') || { stage:0, solved:false };
makeAndBindBoss('boss-1-slot', '1', BOSS_DEFS.b1, bs,
()=>saveBossState('boss-1', bs),
()=>{ bumpProgress('p1', 40); achievement('p1_done'); });
wireReadBtn('p1');
renderMath(box);
}
/* ===== §2 ===== */
function buildP2(){
const box = document.getElementById('p2-body'); if(!box) return;
let html = '';
html += makeCard('theory', 'Пружинный маятник', '§ 2.1',
'<p><b>Пружинный маятник</b> — груз массой $m$, прикреплённый к пружине жёсткости $k$.</p>'
+ '<p>Сила упругости пропорциональна смещению: $F = -kx$. По 2-му закону Ньютона: $ma = -kx$, откуда:</p>'
+ '<p style="text-align:center;margin:6px 0">$$\\omega = \\sqrt{\\dfrac{k}{m}}, \\quad T = 2\\pi\\sqrt{\\dfrac{m}{k}}$$</p>'
+ '<p>Период <b>не зависит</b> от амплитуды (для гармонических колебаний). С ростом массы $T$ увеличивается, с ростом жёсткости — уменьшается.</p>');
html += makeCard('theory', 'Математический маятник', '§ 2.2',
'<p><b>Математический маятник</b> — точечная масса $m$ на невесомой нерастяжимой нити длиной $l$.</p>'
+ '<p>При малых углах ($\\alpha \\lesssim 10°$) период:</p>'
+ '<p style="text-align:center;margin:6px 0">$$T = 2\\pi\\sqrt{\\dfrac{l}{g}}$$</p>'
+ '<p>Период не зависит от массы груза! Зависит только от длины нити $l$ и ускорения свободного падения $g$.</p>'
+ '<p><b>Пример:</b> при $l = 1$ м, $g = 9{,}81$ м/с² период $T \\approx 2{,}01$ с — секундный маятник.</p>');
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><span class="wg-title">Пружинный и математический маятники side-by-side</span></div>'
+ '<div class="wg-help">Сравни оба маятника. Двигай ползунки $m, k, l$ — наблюдай, как меняется период.</div>'
+ '<div class="fx-row"><div class="fx-cell"><div class="fx-cell-label">Пружинный (T = 2π√(m/k))</div><div class="fx-holder" id="fx-spring"></div><div class="fx-sliders" id="fx-spring-sl"></div></div>'
+ '<div class="fx-cell"><div class="fx-cell-label">Математический (T = 2π√(l/g))</div><div class="fx-holder" id="fx-pendulum"></div><div class="fx-sliders" id="fx-pendulum-sl"></div></div></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 2</span><span class="wg-title">Расчёт периода</span></div>'
+ '<div class="wg-help">Используй $T = 2\\pi\\sqrt{m/k}$ или $T = 2\\pi\\sqrt{l/g}$. Округляй до 2 знаков. Решено: <b id="i2-calc-score">0</b> / 5.</div>'
+ '<div id="i2-calc-q" style="margin:8px 0"></div><div class="actions"><input class="tinp" id="i2-calc-inp" placeholder="ответ"><button class="btn primary" id="i2-calc-go">Проверить</button></div><div class="feedback" id="i2-calc-fb"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 3</span><span class="wg-title">Как изменится период?</span></div>'
+ '<div class="wg-help">Решено: <b id="i2-change-score">0</b> / 5.</div>'
+ '<div id="i2-change-q" style="margin:8px 0"></div><div class="opts-row" id="i2-change-opts"></div><div class="feedback" id="i2-change-fb"></div></div>';
html += '<div id="boss-2-slot"></div>';
html += readButton('p2');
html += secNavFor('p2');
box.innerHTML = html;
ensureFx(()=>{
/* Spring */
const spEl = document.getElementById('fx-spring');
const sp = new PHYS.SpringMass(spEl, {width:220, height:280, m:0.5, k:20, A:0.06});
const spSl = document.getElementById('fx-spring-sl');
const slM = PHYS.util.slider({label:'m (кг)', min:0.1, max:2.0, step:0.05, value:0.5, fmt:v=>v.toFixed(2), onChange:v=>sp.setMass(v)});
const slK = PHYS.util.slider({label:'k (Н/м)', min:5, max:80, step:1, value:20, fmt:v=>v.toFixed(0), onChange:v=>sp.setStiffness(v)});
spSl.innerHTML = slM.html + slK.html;
slM.wire(spSl); slK.wire(spSl);
/* Pendulum */
const peEl = document.getElementById('fx-pendulum');
const pe = new PHYS.Pendulum(peEl, {width:220, height:280, l:1.0, g:9.81, theta0:Math.PI/12});
const peSl = document.getElementById('fx-pendulum-sl');
const slL = PHYS.util.slider({label:'l (м)', min:0.2, max:3.0, step:0.1, value:1.0, fmt:v=>v.toFixed(1), onChange:v=>pe.setLength(v)});
const slG = PHYS.util.slider({label:'g (м/с²)', min:1.6, max:24, step:0.1, value:9.81, fmt:v=>v.toFixed(2), onChange:v=>pe.setG(v)});
peSl.innerHTML = slL.html + slG.html;
slL.wire(peSl); slG.wire(peSl);
});
runQuizInput('i2-calc', I2_CALC_ITEMS, 14);
runQuizMC('i2-change', I2_CHANGE_ITEMS, 12);
const bs = loadBossState('boss-2') || { stage:0, solved:false };
makeAndBindBoss('boss-2-slot', '2', BOSS_DEFS.b2, bs,
()=>saveBossState('boss-2', bs),
()=>{ bumpProgress('p2', 40); achievement('p2_done'); });
wireReadBtn('p2');
renderMath(box);
}
/* ===== §3 ===== */
function buildP3(){
const box = document.getElementById('p3-body'); if(!box) return;
let html = '';
html += makeCard('theory', 'Энергии при гармонических колебаниях', '§ 3.1',
'<p>При колебаниях тело обладает <b>кинетической</b> и <b>потенциальной</b> энергией. При $x = A\\cos(\\omega t + \\varphi_0)$:</p>'
+ '<p>$v = -A\\omega\\sin(\\omega t + \\varphi_0)$, поэтому:</p>'
+ '<p style="text-align:center;margin:6px 0">$$W_к = \\dfrac{mv^2}{2} = \\dfrac{1}{2}mA^2\\omega^2\\sin^2(\\omega t + \\varphi_0)$$</p>'
+ '<p>Для пружины $k = m\\omega^2$, и потенциальная энергия:</p>'
+ '<p style="text-align:center;margin:6px 0">$$W_п = \\dfrac{kx^2}{2} = \\dfrac{1}{2}mA^2\\omega^2\\cos^2(\\omega t + \\varphi_0)$$</p>');
html += makeCard('rule', 'Закон сохранения механической энергии', '§ 3.2',
'<p>Используя $\\sin^2 + \\cos^2 = 1$:</p>'
+ '<p style="text-align:center;margin:8px 0">$$W_{мех} = W_к + W_п = \\dfrac{1}{2}mA^2\\omega^2 = \\dfrac{kA^2}{2} = \\text{const}$$</p>'
+ '<p>Полная механическая энергия гармонических колебаний <b>постоянна</b> и пропорциональна <b>квадрату амплитуды</b>.</p>'
+ '<p>В положении равновесия ($x=0$): $W_к = W_{мех}$, $W_п = 0$.</p>'
+ '<p>В точках max отклонения ($x = \\pm A$): $W_к = 0$, $W_п = W_{мех}$.</p>');
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><span class="wg-title">Превращения энергии в реальном времени</span></div>'
+ '<div class="wg-help">График показывает 3 кривые: красная — $W_к$, зелёная — $W_п$, фиолетовая пунктирная — $W_{мех} = $ const. Двигай ползунки $A, \\omega$.</div>'
+ '<div class="fx-holder" id="fx-energy"></div>'
+ '<div class="fx-sliders" id="fx-energy-sl"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 2</span><span class="wg-title">Расчёт энергии</span></div>'
+ '<div class="wg-help">Используй $W_{мех} = kA^2/2$. Решено: <b id="i3-calc-score">0</b> / 5.</div>'
+ '<div id="i3-calc-q" style="margin:8px 0"></div><div class="actions"><input class="tinp" id="i3-calc-inp" placeholder="ответ (Дж)"><button class="btn primary" id="i3-calc-go">Проверить</button></div><div class="feedback" id="i3-calc-fb"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 3</span><span class="wg-title">Превращения энергии</span></div>'
+ '<div class="wg-help">Решено: <b id="i3-trans-score">0</b> / 5.</div>'
+ '<div id="i3-trans-q" style="margin:8px 0"></div><div class="opts-row" id="i3-trans-opts"></div><div class="feedback" id="i3-trans-fb"></div></div>';
html += '<div id="boss-3-slot"></div>';
html += readButton('p3');
html += secNavFor('p3');
box.innerHTML = html;
ensureFx(()=>{
const evEl = document.getElementById('fx-energy');
const ev = new PHYS.EnergyView(evEl, {width:560, height:230, A:1, omega:2*Math.PI});
const slBox = document.getElementById('fx-energy-sl');
const slA = PHYS.util.slider({label:'A (отн.)', min:0.3, max:1.0, step:0.05, value:1.0, fmt:v=>v.toFixed(2), onChange:v=>ev.setA(v)});
const slW = PHYS.util.slider({label:'ω (рад/с)', min:1, max:10, step:0.2, value:Math.round(2*Math.PI*10)/10, fmt:v=>v.toFixed(1), onChange:v=>ev.setOmega(v)});
slBox.innerHTML = slA.html + slW.html;
slA.wire(slBox); slW.wire(slBox);
});
runQuizInput('i3-calc', I3_CALC_ITEMS, 14);
runQuizMC('i3-trans', I3_TRANS_ITEMS, 12);
const bs = loadBossState('boss-3') || { stage:0, solved:false };
makeAndBindBoss('boss-3-slot', '3', BOSS_DEFS.b3, bs,
()=>saveBossState('boss-3', bs),
()=>{ bumpProgress('p3', 40); achievement('p3_done'); });
wireReadBtn('p3');
renderMath(box);
}
/* ===== §4 Резонанс ===== */
function buildP4(){
const box = document.getElementById('p4-body'); if(!box) return;
let html = '';
html += makeCard('theory', 'Свободные и вынужденные колебания', '§ 4.1',
'<p><b>Свободные колебания</b> — колебания, происходящие после однократного выведения системы из равновесия. В реальности всегда <b>затухают</b> из-за диссипации энергии (трение, сопротивление воздуха).</p>'
+ '<p><b>Вынужденные колебания</b> — колебания под действием периодической внешней силы $F = F_0\\cos(\\omega t)$.</p>'
+ '<p>В установившемся режиме система колеблется с <b>частотой вынуждающей силы</b> $\\omega$, не со своей собственной $\\omega_0$.</p>'
+ '<p>Амплитуда установившихся колебаний:</p>'
+ '<p style="text-align:center;margin:6px 0">$$A(\\omega) = \\dfrac{F_0/m}{\\sqrt{(\\omega_0^2 - \\omega^2)^2 + (2\\gamma\\omega)^2}}$$</p>'
+ '<p>где $\\gamma$ — коэффициент затухания.</p>');
html += makeCard('rule', 'Резонанс', '§ 4.2',
'<p><b>Резонанс</b> — явление резкого возрастания амплитуды вынужденных колебаний при приближении частоты вынуждающей силы к собственной частоте системы.</p>'
+ '<p>При малом затухании резонансная частота близка к $\\omega_0$:</p>'
+ '<p style="text-align:center;margin:6px 0">$$\\omega_{рез} \\approx \\omega_0 = \\sqrt{k/m}$$</p>'
+ '<p>Чем <b>меньше</b> затухание $\\gamma$, тем <b>выше</b> и <b>уже</b> резонансный пик.</p>'
+ '<p><b>Примеры:</b> качели (раскачивать в такт), Тихоокеанский мост (Tacoma Narrows, 1940), солдатский шаг по мосту (запрещён).</p>');
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><span class="wg-title">Резонансная кривая $A(\\omega)$</span></div>'
+ '<div class="wg-help">Двигай ползунок $\\gamma$ — затухание. Видно, что при $\\gamma \\to 0$ резонансный пик растёт. Двигай $\\omega$ — красная точка показывает $A$ на текущей частоте.</div>'
+ '<div class="fx-holder" id="fx-resonance"></div>'
+ '<div class="fx-sliders" id="fx-resonance-sl"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 2</span><span class="wg-title">Резонанс: верно или нет?</span></div>'
+ '<div class="wg-help">Решено: <b id="i4-tf-score">0</b> / 5.</div>'
+ '<div id="i4-tf-q" style="margin:8px 0"></div><div class="opts-row" id="i4-tf-opts"></div><div class="feedback" id="i4-tf-fb"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 3</span><span class="wg-title">Что произойдёт?</span></div>'
+ '<div class="wg-help">Решено: <b id="i4-what-score">0</b> / 5.</div>'
+ '<div id="i4-what-q" style="margin:8px 0"></div><div class="opts-row" id="i4-what-opts"></div><div class="feedback" id="i4-what-fb"></div></div>';
html += '<div id="boss-4-slot"></div>';
html += readButton('p4');
html += secNavFor('p4');
box.innerHTML = html;
ensureFx(()=>{
const rcEl = document.getElementById('fx-resonance');
const rc = new PHYS.ResonanceCurve(rcEl, {width:560, height:240, omega0:1.0, gamma:0.15, omegaCur:0.6});
const slBox = document.getElementById('fx-resonance-sl');
const slG = PHYS.util.slider({label:'γ (затухание)', min:0.03, max:0.6, step:0.01, value:0.15, fmt:v=>v.toFixed(2), onChange:v=>rc.setGamma(v)});
const slW = PHYS.util.slider({label:'ω (рад/с)', min:0.05, max:2.0, step:0.02, value:0.6, fmt:v=>v.toFixed(2), onChange:v=>rc.setOmegaCur(v)});
slBox.innerHTML = slG.html + slW.html;
slG.wire(slBox); slW.wire(slBox);
});
runQuizMC('i4-tf', I4_TF_ITEMS, 10);
runQuizMC('i4-what', I4_WHAT_ITEMS, 12);
const bs = loadBossState('boss-4') || { stage:0, solved:false };
makeAndBindBoss('boss-4-slot', '4', BOSS_DEFS.b4, bs,
()=>saveBossState('boss-4', bs),
()=>{ bumpProgress('p4', 40); achievement('p4_done'); });
wireReadBtn('p4');
renderMath(box);
}
/* ===== §5 Волны ===== */
function buildP5(){
const box = document.getElementById('p5-body'); if(!box) return;
let html = '';
html += makeCard('theory', 'Распространение колебаний', '§ 5.1',
'<p><b>Волна</b> — процесс распространения колебаний в пространстве. При этом переносится <b>энергия</b>, но <b>не вещество</b>: частицы среды лишь колеблются около положений равновесия.</p>'
+ '<p>Волны бывают двух типов:</p>'
+ '<ul>'
+ '<li><b>Поперечные</b> — частицы колеблются <b>перпендикулярно</b> направлению распространения (волна на струне, ЭМ-волны).</li>'
+ '<li><b>Продольные</b> — частицы колеблются <b>вдоль</b> направления распространения (звук в воздухе, пружина).</li>'
+ '</ul>');
html += makeCard('rule', 'Длина волны, скорость, частота', '§ 5.2',
'<p><b>Длина волны $\\lambda$</b> — расстояние между двумя ближайшими точками, колеблющимися в одной фазе.</p>'
+ '<p>За один период $T$ волна проходит расстояние, равное длине волны:</p>'
+ '<p style="text-align:center;margin:8px 0">$$\\lambda = vT = \\dfrac{v}{\\nu}$$</p>'
+ '<p>где $v$ — скорость распространения волны в среде. Эта скорость определяется <b>свойствами среды</b>, а не источника.</p>'
+ '<p>Связь циклической частоты, волнового числа и скорости: $\\omega = vk$, где $k = 2\\pi/\\lambda$.</p>');
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><span class="wg-title">Поперечная волна (струна)</span></div>'
+ '<div class="wg-help">Бегущая волна вправо. Красная точка показывает: частица среды колеблется на месте — она не движется по направлению распространения.</div>'
+ '<div class="fx-holder" id="fx-transv"></div>'
+ '<div class="fx-sliders" id="fx-transv-sl"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 2</span><span class="wg-title">Продольная волна (зоны сжатия и разрежения)</span></div>'
+ '<div class="wg-help">Молекулы колеблются вдоль направления распространения. Видны области сжатия (плотности) и разрежения. Так распространяется звук.</div>'
+ '<div class="fx-holder" id="fx-longi"></div>'
+ '<div class="fx-sliders" id="fx-longi-sl"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 3</span><span class="wg-title">Расчёт $\\lambda, v, T$</span></div>'
+ '<div class="wg-help">Используй $\\lambda = vT = v/\\nu$. Решено: <b id="i5-calc-score">0</b> / 5.</div>'
+ '<div id="i5-calc-q" style="margin:8px 0"></div><div class="actions"><input class="tinp" id="i5-calc-inp" placeholder="ответ"><button class="btn primary" id="i5-calc-go">Проверить</button></div><div class="feedback" id="i5-calc-fb"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 4</span><span class="wg-title">Тип волны и свойства</span></div>'
+ '<div class="wg-help">Решено: <b id="i5-type-score">0</b> / 5.</div>'
+ '<div id="i5-type-q" style="margin:8px 0"></div><div class="opts-row" id="i5-type-opts"></div><div class="feedback" id="i5-type-fb"></div></div>';
html += '<div id="boss-5-slot"></div>';
html += readButton('p5');
html += secNavFor('p5');
box.innerHTML = html;
ensureFx(()=>{
const twEl = document.getElementById('fx-transv');
const tw = new PHYS.TransverseWave(twEl, {width:560, height:180, A:0.5, lambda:1.5, v:1.0, markerX:0.35});
const slBox = document.getElementById('fx-transv-sl');
const slA = PHYS.util.slider({label:'A (отн.)', min:0.1, max:0.9, step:0.05, value:0.5, fmt:v=>v.toFixed(2), onChange:v=>tw.setA(v)});
const slL = PHYS.util.slider({label:'λ (отн.)', min:0.5, max:3.0, step:0.1, value:1.5, fmt:v=>v.toFixed(1), onChange:v=>tw.setLambda(v)});
const slV = PHYS.util.slider({label:'v (отн./с)', min:0.2, max:2.5, step:0.1, value:1.0, fmt:v=>v.toFixed(1), onChange:v=>tw.setV(v)});
slBox.innerHTML = slA.html + slL.html + slV.html;
slA.wire(slBox); slL.wire(slBox); slV.wire(slBox);
const lwEl = document.getElementById('fx-longi');
const lw = new PHYS.LongitudinalWave(lwEl, {width:560, height:130, A:0.6, lambda:1.5, v:1.0});
const lwSl = document.getElementById('fx-longi-sl');
const slA2 = PHYS.util.slider({label:'A (отн.)', min:0.1, max:1.0, step:0.05, value:0.6, fmt:v=>v.toFixed(2), onChange:v=>lw.setA(v)});
const slL2 = PHYS.util.slider({label:'λ (отн.)', min:0.5, max:3.0, step:0.1, value:1.5, fmt:v=>v.toFixed(1), onChange:v=>lw.setLambda(v)});
lwSl.innerHTML = slA2.html + slL2.html;
slA2.wire(lwSl); slL2.wire(lwSl);
});
runQuizInput('i5-calc', I5_CALC_ITEMS, 14);
runQuizMC('i5-type', I5_TYPE_ITEMS, 12);
const bs = loadBossState('boss-5') || { stage:0, solved:false };
makeAndBindBoss('boss-5-slot', '5', BOSS_DEFS.b5, bs,
()=>saveBossState('boss-5', bs),
()=>{ bumpProgress('p5', 40); achievement('p5_done'); });
wireReadBtn('p5');
renderMath(box);
}
/* ===== §6 Звук ===== */
function buildP6(){
const box = document.getElementById('p6-body'); if(!box) return;
let html = '';
html += makeCard('theory', 'Звуковые волны', '§ 6.1',
'<p><b>Звук</b> — продольная упругая волна, распространяющаяся в упругих средах (газах, жидкостях, твёрдых телах).</p>'
+ '<p><b>В вакууме звук не распространяется</b> — нет среды для передачи колебаний.</p>'
+ '<p>Звуковая волна — это последовательное чередование зон <b>сжатия</b> и <b>разрежения</b> в среде.</p>'
+ '<p>Скорость звука зависит от среды:</p>'
+ '<ul>'
+ '<li>В воздухе ($t = 20°$C): $v \\approx 340$ м/с</li>'
+ '<li>В воде: $v \\approx 1500$ м/с</li>'
+ '<li>В стали: $v \\approx 5000$ м/с</li>'
+ '</ul>');
html += makeCard('rule', 'Диапазоны частот', '§ 6.2',
'<p>По частоте звуковые волны делятся на три диапазона:</p>'
+ '<ul>'
+ '<li><b>Инфразвук</b>: $\\nu < 16$ Гц — не слышим, но ощущаем (землетрясения, штормы).</li>'
+ '<li><b>Слышимый звук</b>: $16 \\text{ Гц} \\le \\nu \\le 20 \\text{ кГц}$ — воспринимается ухом человека.</li>'
+ '<li><b>Ультразвук</b>: $\\nu > 20$ кГц — медицина (УЗИ), эхолокация, обработка материалов.</li>'
+ '</ul>'
+ '<p><b>Характеристики звука:</b></p>'
+ '<ul>'
+ '<li><b>Громкость</b> — связана с амплитудой звуковой волны, измеряется в децибелах (дБ).</li>'
+ '<li><b>Высота тона</b> — определяется частотой $\\nu$: чем выше $\\nu$, тем выше тон.</li>'
+ '<li><b>Тембр</b> — определяется набором обертонов, отличает голоса и инструменты.</li>'
+ '</ul>');
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Интерактив 1</span><span class="wg-title">Звук как продольная волна</span></div>'
+ '<div class="wg-help">Зелёные точки — молекулы воздуха. Изменяй частоту $\\nu$ — мысленно представляй, как звук разной высоты выглядит «изнутри» воздуха. (Звук не воспроизводится.)</div>'
+ '<div class="fx-holder" id="fx-sound"></div>'
+ '<div class="fx-sliders" id="fx-sound-sl"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 2</span><span class="wg-title">Расчёт длины звуковой волны</span></div>'
+ '<div class="wg-help">$\\lambda = v/\\nu$. Скорость звука в воздухе $v = 340$ м/с (если не указано иное). Решено: <b id="i6-calc-score">0</b> / 5.</div>'
+ '<div id="i6-calc-q" style="margin:8px 0"></div><div class="actions"><input class="tinp" id="i6-calc-inp" placeholder="ответ"><button class="btn primary" id="i6-calc-go">Проверить</button></div><div class="feedback" id="i6-calc-fb"></div></div>';
html += '<div class="wg"><div class="wg-header"><span class="wg-badge">Инт. 3</span><span class="wg-title">Свойства и характеристики звука</span></div>'
+ '<div class="wg-help">Решено: <b id="i6-prop-score">0</b> / 5.</div>'
+ '<div id="i6-prop-q" style="margin:8px 0"></div><div class="opts-row" id="i6-prop-opts"></div><div class="feedback" id="i6-prop-fb"></div></div>';
html += '<div id="boss-6-slot"></div>';
html += readButton('p6');
html += secNavFor('p6');
box.innerHTML = html;
ensureFx(()=>{
const lwEl = document.getElementById('fx-sound');
const lw = new PHYS.LongitudinalWave(lwEl, {width:560, height:130, A:0.7, lambda:1.0, v:1.0, color:'#16a34a', nDots:70});
const slBox = document.getElementById('fx-sound-sl');
const slA = PHYS.util.slider({label:'A (громкость)', min:0.1, max:1.0, step:0.05, value:0.7, fmt:v=>v.toFixed(2), onChange:v=>lw.setA(v)});
const slL = PHYS.util.slider({label:'λ (длина волны)', min:0.3, max:3.0, step:0.1, value:1.0, fmt:v=>v.toFixed(1), onChange:v=>lw.setLambda(v)});
slBox.innerHTML = slA.html + slL.html;
slA.wire(slBox); slL.wire(slBox);
});
runQuizInput('i6-calc', I6_CALC_ITEMS, 14);
runQuizMC('i6-prop', I6_PROP_ITEMS, 12);
const bs = loadBossState('boss-6') || { stage:0, solved:false };
makeAndBindBoss('boss-6-slot', '6', BOSS_DEFS.b6, bs,
()=>saveBossState('boss-6', bs),
()=>{ bumpProgress('p6', 40); achievement('p6_done'); });
wireReadBtn('p6');
renderMath(box);
}
/* ===== Финал главы 1 ===== */
function buildFinal(){
const box = document.getElementById('final-body'); if(!box) return;
let html = '';
html += '<div class="stub-note"><h3>Финальное испытание · 4 интегрированных босса</h3><p>Победи 4 финальных боссов (колебания, маятники, энергия+резонанс, волны+звук). После — ачивка <code>phys11_ch1_master</code> + 100 XP бонус.</p></div>';
html += '<div id="boss-f1-slot"></div>';
html += '<div id="boss-f2-slot"></div>';
html += '<div id="boss-f3-slot"></div>';
html += '<div id="boss-f4-slot"></div>';
html += '<div id="celebration" style="display:none;margin-top:18px"></div>';
html += secNavFor('final');
box.innerHTML = html;
['f1','f2','f3','f4'].forEach(id=>{
const def = FINAL_BOSS_DEFS[id];
const st = loadBossState('boss-'+id) || { stage:0, solved:false };
makeAndBindBoss('boss-'+id+'-slot', id, def, st,
()=>saveBossState('boss-'+id, st),
()=>{ checkFinalComplete(); });
});
checkFinalComplete();
renderMath(box);
}
function checkFinalComplete(){
const allBeat = ['f1','f2','f3','f4'].every(k=>{
const st = loadBossState('boss-'+k); return st && st.solved;
});
if(!allBeat) return;
const cel = document.getElementById('celebration');
if(!cel || cel.dataset.shown === '1') return;
cel.dataset.shown = '1'; cel.style.display = 'block';
cel.innerHTML = '<div class="boss-card solved" style="background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft));text-align:center"><div style="font-family:Unbounded,sans-serif;font-size:1.4rem;font-weight:900;color:#92400e;margin-bottom:8px">&#9733; Глава 1 пройдена! &#9733;</div><div style="color:var(--text);margin-bottom:14px">Все 4 финальных босса побеждены. Колебания и волны — освоены.</div><div style="display:inline-block;padding:8px 18px;background:linear-gradient(135deg,#f59e0b,#dc2626);color:#fff;border-radius:99px;font-family:Unbounded,sans-serif;font-weight:800;font-size:.9rem">+ 100 XP бонус + ачивка phys11_ch1_master</div></div>';
const ach = JSON.parse(localStorage.getItem('physics11_achievements')||'[]');
if(ach.indexOf('phys11_ch1_master') < 0){
ach.push('phys11_ch1_master');
localStorage.setItem('physics11_achievements', JSON.stringify(ach));
addXp(100, 'ch1-master');
achievement('ch1_done');
}
bumpProgress('final', 100);
}
/* ===== Boss state ===== */
function loadBossState(key){ try{ return JSON.parse(localStorage.getItem('physics11_ch1_'+key)||'null'); }catch(e){ return null; } }
function saveBossState(key, state){ try{ localStorage.setItem('physics11_ch1_'+key, JSON.stringify(state)); }catch(e){} }
/* ===== Quiz engines ===== */
function runQuizMC(id, items, xpReward){
const state = JSON.parse(localStorage.getItem('physics11_ch1_quiz_'+id)||'null') || { idx:0, solved:0, awarded:false };
const qEl = document.getElementById(id+'-q');
const optsEl = document.getElementById(id+'-opts');
const fbEl = document.getElementById(id+'-fb');
const scoreEl = document.getElementById(id+'-score');
function save(){ localStorage.setItem('physics11_ch1_quiz_'+id, JSON.stringify(state)); }
function render(){
if(state.solved >= items.length){
qEl.innerHTML = '<b style="color:var(--ok)">Все задания решены!</b> +'+xpReward+' XP.';
optsEl.innerHTML = ''; fbEl.style.display='none';
if(scoreEl) scoreEl.textContent = state.solved;
if(!state.awarded){ state.awarded = true; save(); addXp(xpReward, 'quiz-'+id); }
return;
}
const it = items[state.idx % items.length];
qEl.innerHTML = it.q; optsEl.innerHTML = ''; fbEl.style.display='none';
if(scoreEl) scoreEl.textContent = state.solved;
it.opts.forEach((o,i)=>{
const b = document.createElement('button'); b.className = 'opt-btn'; b.innerHTML = o;
b.addEventListener('click', ()=>{
if(i === it.correct){
b.classList.add('correct'); state.solved++; state.idx++; save();
if(scoreEl) scoreEl.textContent = state.solved;
fbEl.className='feedback ok'; fbEl.innerHTML='&#10003; Верно. '+(it.explain||''); fbEl.style.display='block'; renderMath(fbEl);
setTimeout(render, 850);
} else {
b.classList.add('wrong');
fbEl.className='feedback fail'; fbEl.innerHTML='&#10007; Не так. '+(it.explain||''); fbEl.style.display='block'; renderMath(fbEl);
}
});
optsEl.appendChild(b);
});
renderMath(qEl);
}
render();
}
function runQuizInput(id, items, xpReward){
const state = JSON.parse(localStorage.getItem('physics11_ch1_quiz_'+id)||'null') || { idx:0, solved:0, awarded:false };
const qEl = document.getElementById(id+'-q');
const inp = document.getElementById(id+'-inp');
const go = document.getElementById(id+'-go');
const fbEl = document.getElementById(id+'-fb');
const scoreEl = document.getElementById(id+'-score');
function save(){ localStorage.setItem('physics11_ch1_quiz_'+id, JSON.stringify(state)); }
function render(){
if(state.solved >= items.length){
qEl.innerHTML = '<b style="color:var(--ok)">Все задания решены!</b> +'+xpReward+' XP.';
inp.value=''; inp.disabled=true; go.disabled=true;
if(scoreEl) scoreEl.textContent = state.solved;
if(!state.awarded){ state.awarded = true; save(); addXp(xpReward, 'quiz-'+id); }
return;
}
const it = items[state.idx % items.length];
qEl.innerHTML = it.q; inp.value=''; inp.disabled=false; go.disabled=false; fbEl.style.display='none';
if(scoreEl) scoreEl.textContent = state.solved;
renderMath(qEl);
}
function check(){
const it = items[state.idx % items.length];
const v = normalizeAns(inp.value);
const ans = Array.isArray(it.answer) ? it.answer.map(normalizeAns) : [normalizeAns(it.answer)];
if(ans.indexOf(v) >= 0){
state.solved++; state.idx++; save();
if(scoreEl) scoreEl.textContent = state.solved;
fbEl.className='feedback ok'; fbEl.innerHTML='&#10003; Верно. '+(it.explain||''); fbEl.style.display='block'; renderMath(fbEl);
setTimeout(render, 850);
} else {
fbEl.className='feedback fail'; fbEl.innerHTML='&#10007; Не так. '+(it.explain||''); fbEl.style.display='block'; renderMath(fbEl);
}
}
go.addEventListener('click', check);
inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); check(); } });
render();
}
/* ===== Quiz items ===== */
const I1_CALC_ITEMS = [
{ q:'$T = 0{,}5$ с. Найди $\\nu$ (Гц).', answer:'2', explain:'$\\nu = 1/T = 1/0{,}5 = 2$ Гц.' },
{ q:'$\\nu = 4$ Гц. Найди $T$ (с).', answer:['0.25','1/4'], explain:'$T = 1/\\nu = 0{,}25$ с.' },
{ q:'За $\\Delta t = 10$ с тело совершило $N = 20$ колебаний. Период $T$ (с)?', answer:'0.5', explain:'$T = \\Delta t / N = 10/20 = 0{,}5$ с.' },
{ q:'$T = 2$ с. Цикл. частота $\\omega$ (рад/с)?', answer:['π','pi','3.14','3.1416'], explain:'$\\omega = 2\\pi/T = \\pi$ рад/с.' },
{ q:'$\\nu = 50$ Гц (промышленная частота). $\\omega$ (рад/с)?', answer:['100π','100pi','314','314.16'], explain:'$\\omega = 2\\pi\\nu = 100\\pi \\approx 314$ рад/с.' }
];
const I1_PROP_ITEMS = [
{ q:'Что такое амплитуда колебаний?', opts:['Период','Максимальное отклонение от равновесия','Число колебаний','Скорость'], correct:1, explain:'Амплитуда $A$ — максимальное отклонение от положения равновесия.' },
{ q:'Единица измерения частоты?', opts:['с','рад/с','Гц','м'], correct:2, explain:'Герц = 1/секунду.' },
{ q:'Связь $\\omega$ и $\\nu$:', opts:['$\\omega = \\nu$','$\\omega = 2\\pi\\nu$','$\\omega = \\nu/(2\\pi)$','$\\omega = \\nu^2$'], correct:1, explain:'$\\omega = 2\\pi\\nu$.' },
{ q:'При гарм. колебаниях $x(t) = $:', opts:['$A\\cos(\\omega t)$','$At$','$Ae^{-\\omega t}$','$A/t$'], correct:0, explain:'Косинусоидальный закон.' },
{ q:'Если $A$ удвоить, период $T$:', opts:['Удвоится','Уполовинится','Не изменится','Учетверится'], correct:2, explain:'Период гарм. колебаний не зависит от амплитуды!' }
];
const I2_CALC_ITEMS = [
{ q:'$l = 1$ м, $g = 9{,}81$ м/с². $T$ матем. маятника (с)?', answer:['2','2.01','2.0'], explain:'$T = 2\\pi\\sqrt{1/9{,}81} \\approx 2{,}0$ с.' },
{ q:'Пружина $k = 100$ Н/м, $m = 1$ кг. $T$ (с)?', answer:['0.63','0.628','0.6'], explain:'$T = 2\\pi\\sqrt{1/100} = 0{,}2\\pi \\approx 0{,}63$ с.' },
{ q:'$m = 2$ кг, $k = 200$ Н/м. $T$ (с)?', answer:['0.63','0.628','0.6'], explain:'$T = 2\\pi\\sqrt{2/200} = 0{,}2\\pi \\approx 0{,}63$ с.' },
{ q:'$l = 4$ м, $g = 10$ м/с². $T$ (с)?', answer:['4','4.0','3.97'], explain:'$T = 2\\pi\\sqrt{4/10} = 2\\pi\\cdot 0{,}632 \\approx 4{,}0$ с.' },
{ q:'$l = 0{,}25$ м, $g = 9{,}81$ м/с². $T$ (с)?', answer:['1','1.0','1.004'], explain:'$T = 2\\pi\\sqrt{0{,}25/9{,}81} \\approx 1$ с.' }
];
const I2_CHANGE_ITEMS = [
{ q:'Длину матем. маятника увеличили в 4 раза. $T$:', opts:['Увеличится в 4 раза','Увеличится в 2 раза','Уменьшится в 2 раза','Не изменится'], correct:1, explain:'$T \\propto \\sqrt{l}$, $\\sqrt{4} = 2$.' },
{ q:'Жёсткость пружины увеличили в 9 раз. $T$:', opts:['Увеличится в 9','Уменьшится в 9','Увеличится в 3','Уменьшится в 3'], correct:3, explain:'$T \\propto 1/\\sqrt{k}$, $\\sqrt{9} = 3$.' },
{ q:'Массу груза удвоили (пружина та же). $T$:', opts:['Увеличится в 2','Уменьшится в 2','Увеличится в $\\sqrt{2}$','Не изменится'], correct:2, explain:'$T \\propto \\sqrt{m}$.' },
{ q:'Период матем. маятника зависит от массы?', opts:['Да, линейно','Да, как $\\sqrt{m}$','Нет, не зависит','Да, как $m^2$'], correct:2, explain:'$T = 2\\pi\\sqrt{l/g}$ — массы нет.' },
{ q:'Маятник перенесли с Земли ($g=9{,}81$) на Луну ($g=1{,}62$). $T$:', opts:['Увеличится в $\\approx 2{,}5$ раза','Уменьшится','Не изменится','Увеличится в 6'], correct:0, explain:'$T \\propto 1/\\sqrt{g}$, $\\sqrt{9{,}81/1{,}62} \\approx 2{,}46$.' }
];
const I3_CALC_ITEMS = [
{ q:'$k = 200$ Н/м, $A = 0{,}1$ м. $W_{мех}$ (Дж)?', answer:'1', explain:'$W = kA^2/2 = 200 \\cdot 0{,}01 / 2 = 1$ Дж.' },
{ q:'$m = 0{,}5$ кг, $\\omega = 4$ рад/с, $A = 0{,}2$ м. $W_{мех}$ (Дж)?', answer:'0.16', explain:'$W = m\\omega^2 A^2/2 = 0{,}5 \\cdot 16 \\cdot 0{,}04 / 2 = 0{,}16$ Дж.' },
{ q:'$k = 50$ Н/м, $A = 0{,}2$ м. $W_{мех}$ (Дж)?', answer:'1', explain:'$50 \\cdot 0{,}04 / 2 = 1$ Дж.' },
{ q:'Удвоили амплитуду. Энергия станет:', answer:'4', explain:'$W \\propto A^2$, $2^2 = 4$. Энергия увеличилась в 4 раза.' },
{ q:'$W_{мех} = 2$ Дж. В точке max отклонения $W_п$ (Дж)?', answer:'2', explain:'В $x = \\pm A$: $W_к=0$, $W_п = W_{мех} = 2$ Дж.' }
];
const I3_TRANS_ITEMS = [
{ q:'В положении равновесия $x = 0$:', opts:['$W_к = 0$','$W_к = W_{мех}$','$W_п = W_{мех}$','$W_{мех} = 0$'], correct:1, explain:'$x=0$ ⇒ $W_п = 0$ ⇒ $W_к = W_{мех}$.' },
{ q:'В точке max отклонения $x = A$:', opts:['$W_к = W_{мех}$','$W_п = 0$','$W_к = 0$','$v = $ max'], correct:2, explain:'$v = 0$ в крайних точках, $W_к = 0$.' },
{ q:'$W_{мех} = $ ?', opts:['$kA/2$','$kA^2/2$','$kx^2/2$','$mv^2$'], correct:1, explain:'$W_{мех} = kA^2/2$ — пропорциональна квадрату амплитуды.' },
{ q:'При гарм. колебаниях $W_{мех}$:', opts:['Растёт со временем','Убывает','Постоянна','Колеблется'], correct:2, explain:'Без затухания $W_{мех}$ = const.' },
{ q:'$W_к$ и $W_п$:', opts:['В фазе','В противофазе','Не связаны','Растут вместе'], correct:1, explain:'Когда $W_к$ max, $W_п$ = 0 (и наоборот). Сумма = const.' }
];
const I4_TF_ITEMS = [
{ q:'Свободные колебания в реальной среде всегда затухают.', opts:['Верно','Неверно'], correct:0, explain:'Из-за диссипации (трение, сопротивление).' },
{ q:'Вынужденные колебания происходят с частотой собственной $\\omega_0$.', opts:['Верно','Неверно'], correct:1, explain:'В установив. режиме — с частотой вынуждающей силы.' },
{ q:'При резонансе амплитуда максимальна.', opts:['Верно','Неверно'], correct:0, explain:'Это и есть определение резонанса.' },
{ q:'При $\\gamma \\to 0$ резонансный пик стремится к бесконечности.', opts:['Верно','Неверно'], correct:0, explain:'Без затухания амплитуда не ограничена.' },
{ q:'Резонансная частота равна точно $\\omega_0$ при любом затухании.', opts:['Верно','Неверно'], correct:1, explain:'При большом $\\gamma$ резонанс смещается влево от $\\omega_0$.' }
];
const I4_WHAT_ITEMS = [
{ q:'Что произойдёт с амплитудой, если частота вынуждающей силы будет приближаться к $\\omega_0$?', opts:['Уменьшится','Возрастёт','Не изменится','Станет нулевой'], correct:1, explain:'Резонанс.' },
{ q:'Раскачивание качелей — пример:', opts:['Свободных колеб.','Вынужденных колеб.','Затухающих','Резонанса'], correct:3, explain:'Подталкивая в такт собственной частоте — резонанс.' },
{ q:'Чтобы избежать резонанса моста под марширующим строем, солдатам приказывают:', opts:['Маршировать в такт','Сбить шаг','Бежать','Тише'], correct:1, explain:'Сбить шаг = не дать частоте совпасть с собственной.' },
{ q:'При большом затухании пик резонансной кривой:', opts:['Острый и высокий','Низкий и широкий','Не существует','Идеально симметричный'], correct:1, explain:'Затухание сглаживает пик.' },
{ q:'Свободные колебания идеализированного маятника без трения:', opts:['Затухают','Не затухают','Усиливаются','Случайны'], correct:1, explain:'Без диссипации энергии — не затухают (идеализация).' }
];
const I5_CALC_ITEMS = [
{ q:'$v = 340$ м/с, $\\nu = 170$ Гц. $\\lambda$ (м)?', answer:'2', explain:'$\\lambda = v/\\nu = 340/170 = 2$ м.' },
{ q:'$\\lambda = 0{,}5$ м, $T = 0{,}01$ с. $v$ (м/с)?', answer:'50', explain:'$v = \\lambda/T = 0{,}5/0{,}01 = 50$ м/с.' },
{ q:'$v = 1500$ м/с (вода), $\\nu = 300$ Гц. $\\lambda$ (м)?', answer:'5', explain:'$\\lambda = 1500/300 = 5$ м.' },
{ q:'$\\lambda = 2$ м, $v = 8$ м/с. $\\nu$ (Гц)?', answer:'4', explain:'$\\nu = v/\\lambda = 8/2 = 4$ Гц.' },
{ q:'$T = 0{,}5$ с, $v = 4$ м/с. $\\lambda$ (м)?', answer:'2', explain:'$\\lambda = vT = 2$ м.' }
];
const I5_TYPE_ITEMS = [
{ q:'Волна, в которой частицы колеблются $\\perp$ направлению распространения, — это:', opts:['Продольная','Поперечная','Стоячая','Бегущая'], correct:1, explain:'Поперечная.' },
{ q:'Звук в воздухе — это волна:', opts:['Поперечная','Продольная','Стоячая','Сферическая'], correct:1, explain:'Молекулы воздуха колеблются вдоль распространения.' },
{ q:'Свет — это:', opts:['Продольная упругая','Поперечная ЭМ-волна','Продольная ЭМ','Стоячая'], correct:1, explain:'ЭМ-волны — поперечные.' },
{ q:'Волна переносит:', opts:['Вещество','Энергию','Массу','Скорость'], correct:1, explain:'Энергию, но не вещество.' },
{ q:'Скорость волны определяется:', opts:['Источником','Свойствами среды','Амплитудой','Длиной волны'], correct:1, explain:'$v$ зависит от среды, $\\lambda = vT$.' }
];
const I6_CALC_ITEMS = [
{ q:'$\\nu = 340$ Гц, воздух. $\\lambda$ (м)?', answer:'1', explain:'$\\lambda = 340/340 = 1$ м.' },
{ q:'$\\nu = 1000$ Гц, воздух. $\\lambda$ (м)?', answer:'0.34', explain:'$\\lambda = 340/1000 = 0{,}34$ м.' },
{ q:'Молния увидена за 3 с до грома. Расстояние до неё (м)?', answer:['1020','1000'], explain:'$L = v \\cdot t = 340 \\cdot 3 \\approx 1020$ м.' },
{ q:'$\\nu = 100$ Гц в воде ($v=1500$ м/с). $\\lambda$ (м)?', answer:'15', explain:'$\\lambda = 1500/100 = 15$ м.' },
{ q:'Слышимая частота $\\nu = 20$ Гц — это верхняя граница диапазона:', answer:['16','17','15'], explain:'Слышимый: 16-20000 Гц; нижняя граница ~16 Гц.' }
];
const I6_PROP_ITEMS = [
{ q:'Звук — это волна:', opts:['Поперечная ЭМ','Продольная упругая','Стоячая','Поверхностная'], correct:1, explain:'Продольная упругая.' },
{ q:'В вакууме звук:', opts:['Распространяется быстрее','Распространяется медленнее','Не распространяется','Преломляется'], correct:2, explain:'Нет среды — нет звука.' },
{ q:'Громкость связана с:', opts:['Частотой','Амплитудой','Скоростью','Длиной волны'], correct:1, explain:'Амплитудой.' },
{ q:'Высота тона зависит от:', opts:['Амплитуды','Частоты','Скорости','Тембра'], correct:1, explain:'Частоты.' },
{ q:'Ультразвук — это:', opts:['$\\nu < 16$ Гц','$\\nu > 20$ кГц','Слышимый','Любой громкий звук'], correct:1, explain:'Выше слышимого диапазона.' }
];
/* ===== Boss defs ===== */
const BOSS_DEFS = {
b1: { title:'Босс §1 — Гарм. колебания', tag:'§1', xp:65, stages:[
{ q:'$T = 0{,}1$ с. $\\nu$ (Гц)?', type:'input', a:'10', explain:'$\\nu = 1/T = 10$ Гц.' },
{ q:'$\\omega = 4\\pi$ рад/с. $T$ (с)?', type:'input', a:'0.5', explain:'$T = 2\\pi/\\omega = 0{,}5$ с.' },
{ q:'Уравнение гарм. колеб. — это:', type:'mc', opts:['$x = At$','$x = A\\cos(\\omega t + \\varphi_0)$','$x = Ae^{-t}$','$x = A/t$'], correct:1, explain:'Косинусоидальный закон.' },
{ q:'За 5 с тело совершило 25 колебаний. $T$ (с)?', type:'input', a:'0.2', explain:'$T = 5/25 = 0{,}2$ с.' },
{ q:'Если $A$ утроить, период:', type:'mc', opts:['Утроится','Уменьшится в 3','Не изменится','Увеличится в 9'], correct:2, explain:'Период не зависит от $A$.' }
]},
b2: { title:'Босс §2 — Маятники', tag:'§2', xp:70, stages:[
{ q:'$l = 1{,}0$ м, $g = 9{,}81$ м/с². $T$ (с)?', type:'input', a:['2','2.0','2.01'], explain:'$T \\approx 2{,}0$ с.' },
{ q:'$m = 0{,}1$ кг, $k = 10$ Н/м. $T$ (с)?', type:'input', a:['0.63','0.628','0.6'], explain:'$T = 2\\pi\\sqrt{0{,}01} = 0{,}2\\pi \\approx 0{,}63$ с.' },
{ q:'$T$ матем. маятника зависит от:', type:'mc', opts:['Массы','Амплитуды','Длины и $g$','Жёсткости'], correct:2, explain:'$T = 2\\pi\\sqrt{l/g}$.' },
{ q:'$T$ пружинного зависит от:', type:'mc', opts:['$m, k$','$l, g$','$m, l$','Амплитуды'], correct:0, explain:'$T = 2\\pi\\sqrt{m/k}$.' },
{ q:'Длину матем. маятника увеличили в 9 раз. $T$:', type:'mc', opts:['Увеличится в 9','Увеличится в 3','Не изменится','Уменьшится в 3'], correct:1, explain:'$\\sqrt{9} = 3$.' }
]},
b3: { title:'Босс §3 — Превращения энергии', tag:'§3', xp:65, stages:[
{ q:'$k = 100$ Н/м, $A = 0{,}2$ м. $W_{мех}$ (Дж)?', type:'input', a:'2', explain:'$W = kA^2/2 = 100 \\cdot 0{,}04 / 2 = 2$ Дж.' },
{ q:'$W_{мех} = $ ?', type:'mc', opts:['$kA/2$','$kA^2/2$','$mv$','$\\omega A$'], correct:1, explain:'$kA^2/2$.' },
{ q:'В точке $x = 0$:', type:'mc', opts:['$W_п = $ max','$W_к = $ max','$v = 0$','$W_{мех} = 0$'], correct:1, explain:'$x=0 \\Rightarrow W_п=0 \\Rightarrow W_к = $ max.' },
{ q:'Удвоили $A$. Во сколько раз изменится $W_{мех}$?', type:'input', a:'4', explain:'$W \\propto A^2$.' },
{ q:'При гарм. колебаниях $W_к + W_п = $ ?', type:'mc', opts:['$0$','$\\text{const}$','Зависит от $t$','$kA$'], correct:1, explain:'Сохранение полной механической энергии.' }
]},
b4: { title:'Босс §4 — Резонанс', tag:'§4', xp:70, stages:[
{ q:'Резонанс — это:', type:'mc', opts:['Затухание','Рост амплитуды при $\\omega \\to \\omega_0$','Спонтанные колеб.','Свободные колеб.'], correct:1, explain:'При совпадении частот.' },
{ q:'Реальные свободные колеб. всегда:', type:'mc', opts:['Растут','Затухают','Постоянны','Резонируют'], correct:1, explain:'Диссипация энергии.' },
{ q:'$\\omega_{рез} \\approx ?$ (при малом $\\gamma$)', type:'mc', opts:['$0$','$\\omega_0$','$2\\omega_0$','Бесконечно'], correct:1, explain:'$\\omega_{рез} \\approx \\omega_0 = \\sqrt{k/m}$.' },
{ q:'При $\\gamma \\to 0$ пик кривой $A(\\omega)$:', type:'mc', opts:['Низкий','Бесконечно высокий и узкий','Сглаживается','Двойной'], correct:1, explain:'Без затухания амплитуда неограничена.' },
{ q:'Вынужденные колеб. в устан. режиме идут с частотой:', type:'mc', opts:['Собственной $\\omega_0$','Вынуждающей $\\omega$','Любой','Двойной'], correct:1, explain:'Частота вынуждающей силы.' }
]},
b5: { title:'Босс §5 — Волны', tag:'§5', xp:70, stages:[
{ q:'$v = 340$ м/с, $\\nu = 1700$ Гц. $\\lambda$ (м)?', type:'input', a:'0.2', explain:'$\\lambda = 340/1700 = 0{,}2$ м.' },
{ q:'Звук в воздухе — волна:', type:'mc', opts:['Поперечная','Продольная','Стоячая','ЭМ'], correct:1, explain:'Продольная упругая.' },
{ q:'Свет — волна:', type:'mc', opts:['Продольная','Поперечная','Стоячая','Акустическая'], correct:1, explain:'Поперечная ЭМ.' },
{ q:'Волна переносит:', type:'mc', opts:['Вещество','Энергию','Массу','Импульс среды'], correct:1, explain:'Энергию.' },
{ q:'$T = 0{,}25$ с, $v = 4$ м/с. $\\lambda$ (м)?', type:'input', a:'1', explain:'$\\lambda = vT = 1$ м.' }
]},
b6: { title:'Босс §6 — Звук', tag:'§6', xp:65, stages:[
{ q:'$\\nu = 680$ Гц в воздухе. $\\lambda$ (м)?', type:'input', a:'0.5', explain:'$\\lambda = 340/680 = 0{,}5$ м.' },
{ q:'$v$ звука в воздухе $\\approx$ (м/с)?', type:'input', a:'340', explain:'340 м/с при $t = 20°$C.' },
{ q:'Ультразвук это $\\nu$:', type:'mc', opts:['$< 16$ Гц','16-20000 Гц','$> 20$ кГц','Любая'], correct:2, explain:'Выше слышимого.' },
{ q:'В вакууме звук:', type:'mc', opts:['Распространяется','Не распространяется','Усиливается','Преломляется'], correct:1, explain:'Нет среды.' },
{ q:'Высота тона зависит от:', type:'mc', opts:['Амплитуды','Частоты','Скорости','Тембра'], correct:1, explain:'Частоты.' }
]}
};
const FINAL_BOSS_DEFS = {
f1: { title:'Финал · Колебания', tag:'Финал гл.1', xp:30, stages:[
{ q:'$T = 0{,}2$ с. $\\omega$ (рад/с, через $\\pi$)?', type:'input', a:['10π','10pi','31.4','31.42'], explain:'$\\omega = 2\\pi/T = 10\\pi$ рад/с.' },
{ q:'Уравнение гарм. колеб.:', type:'mc', opts:['$A/t$','$A\\cos(\\omega t + \\varphi_0)$','$At$','$Ae^{\\omega t}$'], correct:1, explain:'Косинусоидальный закон.' },
{ q:'Период зависит от амплитуды?', type:'mc', opts:['Да','Нет','Иногда'], correct:1, explain:'Для гарм. — нет.' },
{ q:'$\\nu = 25$ Гц. $T$ (с)?', type:'input', a:'0.04', explain:'$T = 1/25 = 0{,}04$ с.' }
]},
f2: { title:'Финал · Маятники + энергия', tag:'Финал гл.1', xp:35, stages:[
{ q:'$l = 9{,}81$ м, $g = 9{,}81$ м/с². $T$ (с)?', type:'input', a:['2π','2pi','6.28','6.3'], explain:'$T = 2\\pi\\sqrt{l/g} = 2\\pi$ с.' },
{ q:'$T$ пружинного зависит от:', type:'mc', opts:['$l, g$','$m, k$','$A$','$\\nu$'], correct:1, explain:'$2\\pi\\sqrt{m/k}$.' },
{ q:'$k = 200$ Н/м, $A = 0{,}1$ м. $W_{мех}$ (Дж)?', type:'input', a:'1', explain:'$200 \\cdot 0{,}01 / 2 = 1$ Дж.' },
{ q:'$W_к + W_п = $ ?', type:'mc', opts:['$0$','const','$kx$','Зависит от $t$'], correct:1, explain:'Сохранение полной энергии.' }
]},
f3: { title:'Финал · Резонанс', tag:'Финал гл.1', xp:30, stages:[
{ q:'Резонанс наступает при $\\omega = $ ?', type:'mc', opts:['$2\\omega_0$','$\\omega_0$','$0$','Любое'], correct:1, explain:'При совпадении вынуждающей и собственной частот.' },
{ q:'Свободные колеб. в реальности:', type:'mc', opts:['Растут','Затухают','Постоянны'], correct:1, explain:'Диссипация.' },
{ q:'При $\\gamma \\to 0$ резонансная амплитуда:', type:'mc', opts:['$\\to 0$','$\\to \\infty$','$\\to \\omega_0$','Не меняется'], correct:1, explain:'Без затухания неограничена.' },
{ q:'Раскачивание качелей — пример:', type:'mc', opts:['Свободных','Затухающих','Резонанса','Стоячих'], correct:2, explain:'Подталкиваем в такт.' }
]},
f4: { title:'Финал · Волны и звук', tag:'Финал гл.1', xp:45, stages:[
{ q:'$\\lambda = ?$ через $v, T$', type:'mc', opts:['$vT$','$v/T$','$v^2 T$','$\\sqrt{vT}$'], correct:0, explain:'$\\lambda = vT$.' },
{ q:'Поперечная волна — частицы колеб.:', type:'mc', opts:['$\\parallel$ распр.','$\\perp$ распр.','Случайно','По окружности'], correct:1, explain:'Перпендикулярно.' },
{ q:'$\\nu = 680$ Гц, воздух. $\\lambda$ (м)?', type:'input', a:'0.5', explain:'$340/680 = 0{,}5$.' },
{ q:'В вакууме звук:', type:'mc', opts:['Распространяется','Не распространяется','Зависит'], correct:1, explain:'Нет среды.' },
{ q:'Молния — гром через 5 с. Расстояние (м)?', type:'input', a:['1700','1700.0'], explain:'$340 \\cdot 5 = 1700$ м.' }
]}
};
/* ===== Init ===== */
function init(){
loadProgress();
initTheme();
buildParaSelector();
goTo('p1');
refreshProgressUI();
if(!STATE.achievements.has('start')) achievement('start');
}
if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
else init();
</script>
</body>
</html>