diff --git a/frontend/js/phys-fx.js b/frontend/js/phys-fx.js
index 5a53f6e..43953d0 100644
--- a/frontend/js/phys-fx.js
+++ b/frontend/js/phys-fx.js
@@ -389,4 +389,210 @@ class EnergyView {
}
P.EnergyView = EnergyView;
+/* ============================================================ */
+/* ResonanceCurve — резонансная кривая A(ω) при разных γ */
+/* ============================================================ */
+
+class ResonanceCurve {
+ constructor(container, opts){
+ opts = opts || {};
+ this.el = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.W = opts.width || 540;
+ this.H = opts.height || 240;
+ this.pad = opts.pad || 40;
+ this.omega0 = opts.omega0 || 1.0; /* собственная частота (норм.) */
+ this.gamma = opts.gamma !== undefined ? opts.gamma : 0.15;
+ this.omegaCur = opts.omegaCur !== undefined ? opts.omegaCur : 0.6;
+ this.color = opts.color || '#7c3aed';
+ this.paused = false;
+ this.render();
+ }
+ setGamma(g){ this.gamma = Math.max(0.02, g); this.render(); }
+ setOmegaCur(w){ this.omegaCur = Math.max(0.02, w); this.render(); }
+ /* update не нужен — статический график, обновляется по setter */
+ update(){}
+ render(){
+ if (!this.el) return;
+ const W = this.W, H = this.H, pad = this.pad;
+ const wMin = 0, wMax = 2 * this.omega0;
+ /* Подсчитаем все амплитуды чтобы знать max */
+ function amp(w, g, w0){
+ const dw2 = (w0 * w0 - w * w);
+ const denom = Math.sqrt(dw2 * dw2 + (2 * g * w) * (2 * g * w));
+ return 1 / Math.max(denom, 1e-6);
+ }
+ const gMin = 0.05;
+ const ampMax = amp(this.omega0, gMin, this.omega0) * 1.1;
+ /* Сетка */
+ const left = pad, right = W - pad, top = pad, bot = H - pad;
+ const ux = (right - left) / (wMax - wMin);
+ const uy = (bot - top) / ampMax;
+ function toX(w){ return left + (w - wMin) * ux; }
+ function toY(a){ return bot - a * uy; }
+ let svg = util.svgFrame(W, H);
+ /* Линии сетки */
+ svg += '';
+ for (let i = 0; i <= 4; i++){
+ const w = wMin + (wMax - wMin) * i / 4;
+ svg += ' ';
+ }
+ for (let i = 0; i <= 4; i++){
+ svg += ' ';
+ }
+ svg += ' ';
+ /* Оси */
+ svg += ' ';
+ svg += ' ';
+ /* Подписи осей */
+ svg += 'ω ';
+ svg += 'A ';
+ /* Линия ω₀ — собственная частота */
+ svg += ' ';
+ svg += 'ω₀ ';
+ /* Кривая A(ω) */
+ let path = 'M ';
+ const N = 200;
+ for (let i = 0; i <= N; i++){
+ const w = wMin + (wMax - wMin) * i / N;
+ const a = amp(w, this.gamma, this.omega0);
+ path += toX(w).toFixed(1) + ',' + toY(Math.min(a, ampMax)).toFixed(1);
+ if (i < N) path += ' L ';
+ }
+ svg += ' ';
+ /* Точка-маркер на текущей ω */
+ const aCur = Math.min(amp(this.omegaCur, this.gamma, this.omega0), ampMax);
+ svg += ' ';
+ svg += ' ';
+ /* Подпись γ */
+ svg += 'γ = ' + this.gamma.toFixed(2) + ' ';
+ svg += 'ω = ' + this.omegaCur.toFixed(2) + ' · A = ' + aCur.toFixed(2) + ' ';
+ svg += '';
+ this.el.innerHTML = svg;
+ }
+}
+P.ResonanceCurve = ResonanceCurve;
+
+/* ============================================================ */
+/* TransverseWave — поперечная волна на струне */
+/* y(x, t) = A sin(kx - ωt + φ) */
+/* ============================================================ */
+
+class TransverseWave {
+ constructor(container, opts){
+ opts = opts || {};
+ this.el = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.W = opts.width || 560;
+ this.H = opts.height || 180;
+ this.A = opts.A !== undefined ? opts.A : 0.4; /* отн. амплитуда (0..1) */
+ this.lambda = opts.lambda !== undefined ? opts.lambda : 1.0; /* отн. длина волны */
+ this.v = opts.v !== undefined ? opts.v : 0.8; /* скорость распространения (отн./с) */
+ this.color = opts.color || '#0891b2';
+ this.markerX = opts.markerX !== undefined ? opts.markerX : 0.4; /* пол. красной точки (0..1 от ширины) */
+ this.paused = false;
+ this.t = 0;
+ util.subscribe(this);
+ util.observe(this);
+ this.render();
+ }
+ setA(v){ this.A = v; }
+ setLambda(v){ this.lambda = Math.max(0.1, v); }
+ setV(v){ this.v = v; }
+ update(dt){ this.t += dt; }
+ render(){
+ if (!this.el) return;
+ const W = this.W, H = this.H;
+ const yCenter = H / 2;
+ const amp = this.A * (H / 2 - 18);
+ const k = 2 * Math.PI / this.lambda;
+ const omega = k * this.v;
+ /* SVG: горизонтальная ось + волна как polyline */
+ let svg = util.svgFrame(W, H, {bg:'#f8fafc'});
+ /* Ось */
+ svg += ' ';
+ /* Кривая */
+ const N = 180;
+ let path = 'M ';
+ for (let i = 0; i <= N; i++){
+ const px = (W * i / N);
+ /* Реальное x в относительных единицах (1 длина волны на ~120px) */
+ const x = px / 120;
+ const y = yCenter - amp * Math.sin(k * x - omega * this.t);
+ path += px.toFixed(1) + ',' + y.toFixed(1);
+ if (i < N) path += ' L ';
+ }
+ svg += ' ';
+ /* Красный маркер — колеблющаяся точка */
+ const mPx = this.markerX * W;
+ const mX = mPx / 120;
+ const mY = yCenter - amp * Math.sin(k * mX - omega * this.t);
+ svg += ' ';
+ svg += ' ';
+ /* Метка λ — горизонтальная скобка над волной */
+ const lambdaPx = 120 * this.lambda;
+ if (lambdaPx < W - 60){
+ const lxStart = 20, lxEnd = lxStart + lambdaPx;
+ svg += ' ';
+ svg += ' ';
+ svg += ' ';
+ svg += 'λ ';
+ }
+ svg += '';
+ this.el.innerHTML = svg;
+ }
+}
+P.TransverseWave = TransverseWave;
+
+/* ============================================================ */
+/* LongitudinalWave — продольная волна (сжатия/разрежения) */
+/* ============================================================ */
+
+class LongitudinalWave {
+ constructor(container, opts){
+ opts = opts || {};
+ this.el = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.W = opts.width || 560;
+ this.H = opts.height || 130;
+ this.A = opts.A !== undefined ? opts.A : 0.5; /* амплитуда (0..1) */
+ this.lambda = opts.lambda !== undefined ? opts.lambda : 1.0;
+ this.v = opts.v !== undefined ? opts.v : 0.8;
+ this.color = opts.color || '#0891b2';
+ this.nDots = opts.nDots || 60;
+ this.paused = false;
+ this.t = 0;
+ util.subscribe(this);
+ util.observe(this);
+ this.render();
+ }
+ setA(v){ this.A = v; }
+ setLambda(v){ this.lambda = Math.max(0.1, v); }
+ setV(v){ this.v = v; }
+ update(dt){ this.t += dt; }
+ render(){
+ if (!this.el) return;
+ const W = this.W, H = this.H;
+ const yC = H / 2;
+ const k = 2 * Math.PI / this.lambda;
+ const omega = k * this.v;
+ const xScale = 120; /* px на 1 ед. */
+ const amp = this.A * 10; /* px смещения */
+ const margin = 20;
+ let svg = util.svgFrame(W, H, {bg:'#f8fafc'});
+ /* Точки-молекулы */
+ let dots = '';
+ for (let i = 0; i < this.nDots; i++){
+ const x0 = margin + (W - 2 * margin) * i / (this.nDots - 1);
+ const xRel = x0 / xScale;
+ const disp = amp * Math.sin(k * xRel - omega * this.t);
+ const x = x0 + disp;
+ dots += ' ';
+ }
+ svg += dots;
+ /* Подписи зон сжатия / разрежения */
+ svg += 'сжатие ↔ разрежение ';
+ svg += '';
+ this.el.innerHTML = svg;
+ }
+}
+P.LongitudinalWave = LongitudinalWave;
+
})();
diff --git a/frontend/textbooks/physics_11_ch1.html b/frontend/textbooks/physics_11_ch1.html
index ed7f588..e403e07 100644
--- a/frontend/textbooks/physics_11_ch1.html
+++ b/frontend/textbooks/physics_11_ch1.html
@@ -229,10 +229,10 @@ 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:'Будет в W2', built:false },
- { id:'p5', num:'§ 5', name:'Волны', sub:'Будет в W2', built:false },
- { id:'p6', num:'§ 6', name:'Звук', sub:'Будет в W2', built:false },
- { id:'final', num:'★', name:'Финал главы', sub:'4 босса · W2', final:true, built:false }
+ { 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; });
@@ -243,7 +243,11 @@ const ACH_LABELS = {
p1_done:'§1 — гармонические колебания освоены',
p2_done:'§2 — маятники освоены',
p3_done:'§3 — превращения энергии освоены',
- start:'Начало главы 1!'
+ p4_done:'§4 — резонанс освоен',
+ p5_done:'§5 — волны освоены',
+ p6_done:'§6 — звук освоен',
+ start:'Начало главы 1!',
+ ch1_done:'Глава 1 пройдена — колебания и волны!'
};
function loadProgress(){
@@ -322,7 +326,7 @@ function buildParaSelector(){
}
const BUILT=new Set();
-const BUILDERS = { p1:()=>buildP1(), p2:()=>buildP2(), p3:()=>buildP3(), p4:()=>buildStubP('p4','§ 4','§4 в разработке (W2)'), p5:()=>buildStubP('p5','§ 5','§5 в разработке (W2)'), p6:()=>buildStubP('p6','§ 6','§6 в разработке (W2)'), final:()=>buildStubP('final','Финал','Финал главы 1 — в волне W2') };
+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);
@@ -340,20 +344,20 @@ 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:[['Тема','Резонанс'],['Статус','В разработке (W2)']]},
- p5:{title:'§ 5', rows:[['Тема','Волны'],['Статус','В разработке (W2)']]},
- p6:{title:'§ 6', rows:[['Тема','Звук'],['Статус','В разработке (W2)']]},
- final:{title:'Финал главы 1', rows:[['Статус','В разработке (W2)'],['Боссов','4 интегрированных'],['Награда','+100 XP + ачивка']]}
+ 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$. Амплитуда не входит !'},
{sec:'p3',html:'§ 3 — пока $W_к$ растёт, $W_п$ убывает. Сумма постоянна: $W_{мех} = kA^2/2$.'},
- {sec:'p4',html:'§ 4 — в разработке (W2).'},
- {sec:'p5',html:'§ 5 — в разработке (W2).'},
- {sec:'p6',html:'§ 6 — в разработке (W2).'},
- {sec:'final',html:'Финал главы 1 — в разработке (W2).'}
+ {sec:'p4',html:'§ 4 — двигай ползунок $\\gamma$ (затухание). При $\\gamma \\to 0$ резонансный пик становится бесконечно острым.'},
+ {sec:'p5',html:'§ 5 — $\\lambda = vT$ — главная формула. Поперечные: волна на струне. Продольные: звук.'},
+ {sec:'p6',html:'§ 6 — звук = продольная упругая волна. В вакууме не распространяется ! $v_{зв}^{возд} \\approx 340$ м/с.'},
+ {sec:'final',html:'Финал главы 1 — 4 интегральных босса на все темы главы. Победа = ачивка ch1_done + 100 XP.'}
];
function buildSidebar(id){
@@ -718,12 +722,252 @@ function buildP3(){
renderMath(box);
}
-/* ===== Stubs §4-§6, Final ===== */
-function buildStubP(id, label, message){
- const box = document.getElementById(id + '-body'); if(!box) return;
- let html = '
' + label + ' — в разработке ' + message + '
';
- html += secNavFor(id);
+/* ===== §4 Резонанс ===== */
+function buildP4(){
+ const box = document.getElementById('p4-body'); if(!box) return;
+ let html = '';
+
+ html += makeCard('theory', 'Свободные и вынужденные колебания', '§ 4.1',
+ 'Свободные колебания — колебания, происходящие после однократного выведения системы из равновесия. В реальности всегда затухают из-за диссипации энергии (трение, сопротивление воздуха).
'
+ + 'Вынужденные колебания — колебания под действием периодической внешней силы $F = F_0\\cos(\\omega t)$.
'
+ + 'В установившемся режиме система колеблется с частотой вынуждающей силы $\\omega$, не со своей собственной $\\omega_0$.
'
+ + 'Амплитуда установившихся колебаний:
'
+ + '$$A(\\omega) = \\dfrac{F_0/m}{\\sqrt{(\\omega_0^2 - \\omega^2)^2 + (2\\gamma\\omega)^2}}$$
'
+ + 'где $\\gamma$ — коэффициент затухания.
');
+
+ html += makeCard('rule', 'Резонанс', '§ 4.2',
+ 'Резонанс — явление резкого возрастания амплитуды вынужденных колебаний при приближении частоты вынуждающей силы к собственной частоте системы.
'
+ + 'При малом затухании резонансная частота близка к $\\omega_0$:
'
+ + '$$\\omega_{рез} \\approx \\omega_0 = \\sqrt{k/m}$$
'
+ + 'Чем меньше затухание $\\gamma$, тем выше и уже резонансный пик.
'
+ + 'Примеры: качели (раскачивать в такт), Тихоокеанский мост (Tacoma Narrows, 1940), солдатский шаг по мосту (запрещён).
');
+
+ html += ''
+ + '
Двигай ползунок $\\gamma$ — затухание. Видно, что при $\\gamma \\to 0$ резонансный пик растёт. Двигай $\\omega$ — красная точка показывает $A$ на текущей частоте.
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += '
';
+ 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',
+ 'Волна — процесс распространения колебаний в пространстве. При этом переносится энергия , но не вещество : частицы среды лишь колеблются около положений равновесия.
'
+ + 'Волны бывают двух типов:
'
+ + ''
+ + 'Поперечные — частицы колеблются перпендикулярно направлению распространения (волна на струне, ЭМ-волны). '
+ + 'Продольные — частицы колеблются вдоль направления распространения (звук в воздухе, пружина). '
+ + ' ');
+
+ html += makeCard('rule', 'Длина волны, скорость, частота', '§ 5.2',
+ 'Длина волны $\\lambda$ — расстояние между двумя ближайшими точками, колеблющимися в одной фазе.
'
+ + 'За один период $T$ волна проходит расстояние, равное длине волны:
'
+ + '$$\\lambda = vT = \\dfrac{v}{\\nu}$$
'
+ + 'где $v$ — скорость распространения волны в среде. Эта скорость определяется свойствами среды , а не источника.
'
+ + 'Связь циклической частоты, волнового числа и скорости: $\\omega = vk$, где $k = 2\\pi/\\lambda$.
');
+
+ html += ''
+ + '
Бегущая волна вправо. Красная точка показывает: частица среды колеблется на месте — она не движется по направлению распространения.
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
Молекулы колеблются вдоль направления распространения. Видны области сжатия (плотности) и разрежения. Так распространяется звук.
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
Используй $\\lambda = vT = v/\\nu$. Решено: 0 / 5.
'
+ + '
Проверить
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += '
';
+ 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',
+ 'Звук — продольная упругая волна, распространяющаяся в упругих средах (газах, жидкостях, твёрдых телах).
'
+ + 'В вакууме звук не распространяется — нет среды для передачи колебаний.
'
+ + 'Звуковая волна — это последовательное чередование зон сжатия и разрежения в среде.
'
+ + 'Скорость звука зависит от среды:
'
+ + ''
+ + 'В воздухе ($t = 20°$C): $v \\approx 340$ м/с '
+ + 'В воде: $v \\approx 1500$ м/с '
+ + 'В стали: $v \\approx 5000$ м/с '
+ + ' ');
+
+ html += makeCard('rule', 'Диапазоны частот', '§ 6.2',
+ 'По частоте звуковые волны делятся на три диапазона:
'
+ + ''
+ + 'Инфразвук : $\\nu < 16$ Гц — не слышим, но ощущаем (землетрясения, штормы). '
+ + 'Слышимый звук : $16 \\text{ Гц} \\le \\nu \\le 20 \\text{ кГц}$ — воспринимается ухом человека. '
+ + 'Ультразвук : $\\nu > 20$ кГц — медицина (УЗИ), эхолокация, обработка материалов. '
+ + ' '
+ + 'Характеристики звука:
'
+ + ''
+ + 'Громкость — связана с амплитудой звуковой волны, измеряется в децибелах (дБ). '
+ + 'Высота тона — определяется частотой $\\nu$: чем выше $\\nu$, тем выше тон. '
+ + 'Тембр — определяется набором обертонов, отличает голоса и инструменты. '
+ + ' ');
+
+ html += ''
+ + '
Зелёные точки — молекулы воздуха. Изменяй частоту $\\nu$ — мысленно представляй, как звук разной высоты выглядит «изнутри» воздуха. (Звук не воспроизводится.)
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
$\\lambda = v/\\nu$. Скорость звука в воздухе $v = 340$ м/с (если не указано иное). Решено: 0 / 5.
'
+ + '
Проверить
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += '
';
+ 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 += 'Финальное испытание · 4 интегрированных босса Победи 4 финальных боссов (колебания, маятники, энергия+резонанс, волны+звук). После — ачивка phys11_ch1_master + 100 XP бонус.
';
+ html += '
';
+ html += '
';
+ html += '
';
+ html += '
';
+ html += '
';
+ 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 = '★ Глава 1 пройдена! ★
Все 4 финальных босса побеждены. Колебания и волны — освоены.
+ 100 XP бонус + ачивка phys11_ch1_master
';
+
+ 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 ===== */
@@ -857,6 +1101,54 @@ const I3_TRANS_ITEMS = [
{ 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:[
@@ -879,6 +1171,55 @@ const BOSS_DEFS = {
{ 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$ м.' }
]}
};