diff --git a/frontend/js/phys-fx.js b/frontend/js/phys-fx.js
index 317a209..21f10c2 100644
--- a/frontend/js/phys-fx.js
+++ b/frontend/js/phys-fx.js
@@ -1033,4 +1033,300 @@ class FlatMirror {
}
P.FlatMirror = FlatMirror;
+/* ============================================================ */
+/* SphericalMirror — вогнутое / выпуклое зеркало */
+/* ============================================================ */
+
+class SphericalMirror {
+ constructor(container, opts){
+ opts = opts || {};
+ this.el = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.W = opts.width || 620;
+ this.H = opts.height || 280;
+ this.F = opts.F !== undefined ? opts.F : 80; /* фокусное расстояние в px */
+ this.d = opts.d !== undefined ? opts.d : 180; /* расстояние до объекта в px */
+ this.objH = opts.objH !== undefined ? opts.objH : 50; /* высота объекта в px */
+ this.mode = opts.mode || 'concave'; /* 'concave' | 'convex' */
+ this.color = opts.color || '#d97706';
+ this.paused = true;
+ this.render();
+ }
+ setF(v){ this.F = Math.max(20, v); this.render(); }
+ setD(v){ this.d = Math.max(20, v); this.render(); }
+ setMode(m){ this.mode = m; this.render(); }
+ update(){}
+ render(){
+ if (!this.el) return;
+ const W = this.W, H = this.H;
+ const cy = H / 2;
+ const mirrorX = W - 80; /* зеркало справа */
+ const F = (this.mode === 'concave') ? this.F : -this.F;
+ const focusX = mirrorX - F;
+ const centerX = mirrorX - 2 * F;
+ const d = this.d;
+ const objX = mirrorX - d;
+ /* Формула 1/d + 1/f = 1/F → f = 1/(1/F - 1/d) */
+ let f;
+ if (Math.abs(1/F - 1/d) < 1e-6) f = 1e9;
+ else f = 1 / (1/F - 1/d);
+ const imgX = mirrorX - f;
+ /* Линейное увеличение Γ = -f/d (мнимое: f<0 → прямое, действ.: f>0 → перевёрнутое) */
+ const G = -f / d;
+ const imgH = this.objH * G;
+ let svg = util.svgFrame(W, H, {bg:'#f8fafc'});
+ /* Главная оптическая ось */
+ svg += ' ';
+ /* Зеркало (дуга) */
+ const R = 2 * Math.abs(F);
+ if (this.mode === 'concave'){
+ svg += ' ';
+ } else {
+ svg += ' ';
+ }
+ /* Штриховка зеркала */
+ for (let i = 0; i < 8; i++){
+ const y = cy - 90 + i * 22;
+ const dx = this.mode === 'concave' ? 8 : -8;
+ svg += ' ';
+ }
+ /* Точки F и C */
+ svg += ' ';
+ svg += 'F ';
+ if (this.mode === 'concave'){
+ svg += ' ';
+ svg += '2F ';
+ }
+ /* Объект — красная стрелка вверх */
+ const objTopY = cy - this.objH;
+ svg += ' ';
+ svg += ' ';
+ /* Лучи (3 канонических) */
+ /* Луч 1: параллельный оптической оси → отражается через F */
+ svg += ' ';
+ if (this.mode === 'concave'){
+ svg += ' ';
+ /* Продолжение до изображения */
+ const slope1 = (cy - objTopY) / (focusX - mirrorX);
+ const x2 = imgX, y2 = cy + slope1 * (x2 - focusX);
+ svg += ' ';
+ } else {
+ /* Выпуклое: отражается так, словно вышел из мнимого F справа */
+ const slope = (objTopY - cy) / (mirrorX - focusX);
+ svg += ' ';
+ svg += ' ';
+ }
+ /* Луч 2: через F → отражается параллельно оси (только вогнутое) */
+ if (this.mode === 'concave' && objX !== focusX){
+ const slope2 = (cy - objTopY) / (focusX - objX);
+ const hitY = objTopY + slope2 * (mirrorX - objX);
+ svg += ' ';
+ svg += ' ';
+ }
+ /* Изображение */
+ if (Math.abs(imgX) < 1e8 && imgX > 20 && imgX < mirrorX){
+ const imgTopY = cy - imgH;
+ const dashed = (this.mode === 'convex' || imgH > 0); /* мнимое = пунктир */
+ const isVirtual = (this.mode === 'convex') || (f < 0);
+ const sd = isVirtual ? ' stroke-dasharray="4 3"' : '';
+ const op = isVirtual ? 0.7 : 1.0;
+ svg += ' ';
+ svg += ' ';
+ }
+ /* Подпись параметров */
+ const Glabel = isFinite(G) ? G.toFixed(2) : '—';
+ svg += '1/d + 1/f = 1/F · Γ = -f/d = ' + Glabel + ' ';
+ svg += '' + (this.mode==='concave'?'вогнутое':'выпуклое') + ' · F=' + Math.abs(F).toFixed(0) + 'px · d=' + d.toFixed(0) + 'px ';
+ svg += '';
+ this.el.innerHTML = svg;
+ }
+}
+P.SphericalMirror = SphericalMirror;
+
+/* ============================================================ */
+/* RefractionLab — преломление на границе двух сред (Снелл) */
+/* ============================================================ */
+
+class RefractionLab {
+ constructor(container, opts){
+ opts = opts || {};
+ this.el = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.W = opts.width || 540;
+ this.H = opts.height || 320;
+ this.n1 = opts.n1 !== undefined ? opts.n1 : 1.0; /* воздух */
+ this.n2 = opts.n2 !== undefined ? opts.n2 : 1.5; /* стекло */
+ this.alpha = opts.alpha !== undefined ? opts.alpha : 35; /* градусов */
+ this.color = opts.color || '#d97706';
+ this.paused = true;
+ this.render();
+ }
+ setN1(v){ this.n1 = Math.max(1, v); this.render(); }
+ setN2(v){ this.n2 = Math.max(1, v); this.render(); }
+ setAlpha(v){ this.alpha = Math.max(0, Math.min(89, v)); this.render(); }
+ update(){}
+ render(){
+ if (!this.el) return;
+ const W = this.W, H = this.H;
+ const cx = W / 2, cy = H / 2;
+ /* Углы (рад) */
+ const a = this.alpha * Math.PI / 180;
+ const sinB = this.n1 / this.n2 * Math.sin(a);
+ const totalInternal = Math.abs(sinB) > 1;
+ const b = totalInternal ? null : Math.asin(sinB);
+ /* Критический угол n1>n2 */
+ let critDeg = null;
+ if (this.n1 > this.n2) critDeg = Math.asin(this.n2 / this.n1) * 180 / Math.PI;
+ let svg = util.svgFrame(W, H, {bg:'#f8fafc'});
+ /* Среда 1 (верх) */
+ svg += ' ';
+ /* Среда 2 (низ) */
+ svg += ' ';
+ /* Граница */
+ svg += ' ';
+ /* Нормаль (пунктир) */
+ svg += ' ';
+ svg += 'нормаль ';
+ /* Падающий луч (из верхней-левой области) */
+ const L = 130;
+ const ix = cx - L * Math.sin(a), iy = cy - L * Math.cos(a);
+ svg += ' ';
+ /* Стрелка падающего */
+ const ang_i = Math.atan2(cy - iy, cx - ix);
+ const arrPx = cx - 30 * Math.cos(ang_i), arrPy = cy - 30 * Math.sin(ang_i);
+ svg += ' ';
+ /* Дуга угла падения */
+ svg += ' ';
+ svg += 'α ';
+ /* Отражённый луч */
+ const rx = cx + L * Math.sin(a), ry = cy - L * Math.cos(a);
+ svg += ' ';
+ svg += 'отраж. ';
+ /* Преломлённый луч или полное отражение */
+ if (totalInternal){
+ svg += 'полное внутреннее отражение ';
+ } else {
+ const tx = cx + L * Math.sin(b), ty = cy + L * Math.cos(b);
+ svg += ' ';
+ const ang_t = Math.atan2(ty - cy, tx - cx);
+ const apx = cx + 30 * Math.cos(ang_t), apy = cy + 30 * Math.sin(ang_t);
+ svg += ' ';
+ svg += ' ';
+ svg += 'β ';
+ }
+ /* Подписи сред */
+ svg += 'n₁ = ' + this.n1.toFixed(2) + ' ';
+ svg += 'n₂ = ' + this.n2.toFixed(2) + ' ';
+ /* Формула + углы */
+ const bDeg = totalInternal ? '—' : (b * 180 / Math.PI).toFixed(1);
+ svg += 'n₁ sin α = n₂ sin β ';
+ svg += 'α=' + this.alpha.toFixed(0) + '° · β=' + bDeg + '°' + (critDeg!==null?' · αкр=' + critDeg.toFixed(1) + '°':'') + ' ';
+ svg += '';
+ this.el.innerHTML = svg;
+ }
+}
+P.RefractionLab = RefractionLab;
+
+/* ============================================================ */
+/* PrismSpectrum — призма, дисперсия белого света */
+/* ============================================================ */
+
+class PrismSpectrum {
+ constructor(container, opts){
+ opts = opts || {};
+ this.el = (typeof container === 'string') ? document.querySelector(container) : container;
+ this.W = opts.width || 580;
+ this.H = opts.height || 260;
+ this.alpha = opts.alpha !== undefined ? opts.alpha : 50; /* угол падения, градусы */
+ this.paused = true;
+ this.render();
+ }
+ setAlpha(v){ this.alpha = Math.max(20, Math.min(75, v)); this.render(); }
+ update(){}
+ /* Показатели преломления стекла для разных длин волн (упрощённая модель Коши) */
+ nForColor(lamNm){
+ return 1.5 + 6500 / (lamNm * lamNm); /* красный ~1.518, фиолет ~1.530 */
+ }
+ render(){
+ if (!this.el) return;
+ const W = this.W, H = this.H;
+ /* Геометрия равностороннего треугольника-призмы */
+ const cx = W / 2, cy = H / 2 + 10;
+ const side = 140;
+ const h = side * Math.sqrt(3) / 2;
+ const A = { x: cx, y: cy - h * 2/3 }; /* верхняя вершина */
+ const B = { x: cx - side/2, y: cy + h/3 }; /* нижняя левая */
+ const C = { x: cx + side/2, y: cy + h/3 }; /* нижняя правая */
+ let svg = util.svgFrame(W, H, {bg:'#0f172a'});
+ /* Призма (полупрозрачная) */
+ svg += ' ';
+ /* Падающий белый луч на грань AB */
+ const a = this.alpha * Math.PI / 180;
+ /* Точка входа — середина грани AB */
+ const Pin = { x: (A.x + B.x) / 2, y: (A.y + B.y) / 2 };
+ /* Нормаль к AB (наружу, влево-вверх) */
+ const ABx = B.x - A.x, ABy = B.y - A.y;
+ const Lab = Math.hypot(ABx, ABy);
+ const nABx = -ABy / Lab, nABy = ABx / Lab; /* перпендикуляр */
+ /* Источник падающего луча */
+ const inLen = 160;
+ const inx = Pin.x + inLen * (nABx * Math.cos(a) - (ABx/Lab) * Math.sin(a));
+ const iny = Pin.y + inLen * (nABy * Math.cos(a) - (ABy/Lab) * Math.sin(a));
+ svg += ' ';
+ svg += 'белый ';
+ /* 7 цветов спектра — каждый со своим n и углом преломления */
+ const colors = [
+ { lam: 700, c: '#dc2626' }, /* красный */
+ { lam: 620, c: '#ea580c' }, /* оранжевый */
+ { lam: 580, c: '#facc15' }, /* жёлтый */
+ { lam: 520, c: '#16a34a' }, /* зелёный */
+ { lam: 480, c: '#06b6d4' }, /* голубой */
+ { lam: 450, c: '#1d4ed8' }, /* синий */
+ { lam: 420, c: '#7c3aed' } /* фиолетовый */
+ ];
+ /* Нормаль к BC (наружу, вправо-вниз) */
+ const BCx = C.x - B.x, BCy = C.y - B.y;
+ const Lbc = Math.hypot(BCx, BCy);
+ const nBCx = BCy / Lbc, nBCy = -BCx / Lbc;
+ /* Точки выхода — равномерно по грани BC */
+ const outLen = 180;
+ for (let i = 0; i < colors.length; i++){
+ const co = colors[i];
+ const n = this.nForColor(co.lam);
+ /* Преломление при входе: sin β = sin α / n */
+ const sinB = Math.sin(a) / n;
+ if (Math.abs(sinB) > 1) continue;
+ const beta = Math.asin(sinB);
+ /* Внутри призмы луч идёт от Pin под углом beta от нормали к AB, в сторону BC */
+ /* Направление внутри: поворот нормали-в-стекло (-nAB) на beta */
+ const dirX = -nABx * Math.cos(beta) + (ABx/Lab) * Math.sin(beta);
+ const dirY = -nABy * Math.cos(beta) + (ABy/Lab) * Math.sin(beta);
+ /* Найти точку выхода на BC (параметрический луч / линия BC) */
+ const denom = dirX * (-(C.y - B.y)) + dirY * (C.x - B.x);
+ if (Math.abs(denom) < 1e-6) continue;
+ const t = ((B.x - Pin.x) * (-(C.y - B.y)) + (B.y - Pin.y) * (C.x - B.x)) / denom;
+ const Pout = { x: Pin.x + t * dirX, y: Pin.y + t * dirY };
+ /* Луч внутри */
+ svg += ' ';
+ /* Преломление при выходе: угол к нормали BC внутри */
+ const cosIn = -(dirX * nBCx + dirY * nBCy); /* направление к внешней нормали */
+ const sinIn = Math.sqrt(Math.max(0, 1 - cosIn * cosIn));
+ const sinOut = sinIn * n;
+ if (sinOut > 1) continue;
+ const cosOut = Math.sqrt(1 - sinOut * sinOut);
+ /* Тангенциальная составляющая (вдоль BC) */
+ const tBCx = BCx / Lbc, tBCy = BCy / Lbc;
+ const tanSign = (dirX * tBCx + dirY * tBCy) >= 0 ? 1 : -1;
+ const outX = nBCx * cosOut + tBCx * sinOut * tanSign;
+ const outY = nBCy * cosOut + tBCy * sinOut * tanSign;
+ const Pend = { x: Pout.x + outLen * outX, y: Pout.y + outLen * outY };
+ svg += ' ';
+ }
+ /* Подпись */
+ svg += 'дисперсия: n(λ) растёт при уменьшении λ → фиолетовый отклоняется сильнее красного ';
+ svg += 'α = ' + this.alpha.toFixed(0) + '° · стекло (модель Коши) ';
+ svg += '';
+ this.el.innerHTML = svg;
+ }
+}
+P.PrismSpectrum = PrismSpectrum;
+
})();
diff --git a/frontend/textbooks/physics_11_ch3.html b/frontend/textbooks/physics_11_ch3.html
index a3e8bce..4765e5d 100644
--- a/frontend/textbooks/physics_11_ch3.html
+++ b/frontend/textbooks/physics_11_ch3.html
@@ -229,9 +229,9 @@ const PARAS = [
{ id:'p2', num:'§ 15', name:'Интерференция', sub:'$\\Delta = k\\lambda$', built:true },
{ id:'p3', num:'§ 16', name:'Дифракция', sub:'$d\\sin\\varphi = k\\lambda$', built:true },
{ id:'p4', num:'§ 17', name:'Отражение, зеркала', sub:'$\\angle_{пад} = \\angle_{отр}$', built:true },
- { id:'p5', num:'§ 18', name:'Сферические зеркала', sub:'Будет в W6', built:false },
- { id:'p6', num:'§ 19', name:'Преломление', sub:'Будет в W6', built:false },
- { id:'p7', num:'§ 20', name:'Опт. элементы', sub:'Будет в W6', built:false },
+ { id:'p5', num:'§ 18', name:'Сферические зеркала', sub:'$1/d + 1/f = 1/F$', built:true },
+ { id:'p6', num:'§ 19', name:'Преломление', sub:'$n_1\\sin\\alpha = n_2\\sin\\beta$', built:true },
+ { id:'p7', num:'§ 20', name:'Опт. элементы', sub:'Призма, оптоволокно', built:true },
{ id:'p8', num:'§ 21', name:'Тонкая линза', sub:'Будет в W7', built:false },
{ id:'p9', num:'§ 22', name:'Действ. изображения', sub:'Будет в W7', built:false },
{ id:'p10', num:'§ 23', name:'Угол зрения', sub:'Будет в W7', built:false },
@@ -247,6 +247,9 @@ const ACH_LABELS = {
p2_done:'§15 — интерференция освоена',
p3_done:'§16 — дифракция освоена',
p4_done:'§17 — отражение и зеркала освоены',
+ p5_done:'§18 — сферические зеркала освоены',
+ p6_done:'§19 — закон Снелла освоен',
+ p7_done:'§20 — призма и оптоволокно освоены',
start:'Начало главы 3!',
ch3_done:'Глава 3 пройдена — Оптика!'
};
@@ -329,9 +332,7 @@ function buildParaSelector(){
const BUILT=new Set();
const BUILDERS = {
p1:()=>buildP1(), p2:()=>buildP2(), p3:()=>buildP3(), p4:()=>buildP4(),
- p5:()=>buildStubP('p5','§ 18','§18 в разработке (W6) — вогнутые и выпуклые сферические зеркала, фокус $F = R/2$, построение изображений.'),
- p6:()=>buildStubP('p6','§ 19','§19 в разработке (W6) — закон Снелла $n_1\\sin\\alpha = n_2\\sin\\beta$, полное внутреннее отражение.'),
- p7:()=>buildStubP('p7','§ 20','§20 в разработке (W6) — призмы, плоскопараллельные пластинки, оптоволокно.'),
+ p5:()=>buildP5(), p6:()=>buildP6(), p7:()=>buildP7(),
p8:()=>buildStubP('p8','§ 21','§21 в разработке (W7) — тонкая линза, формула $1/F = 1/d + 1/f$, оптическая сила $D = 1/F$.'),
p9:()=>buildStubP('p9','§ 22','§22 в разработке (W7) — фотоаппарат, проектор.'),
p10:()=>buildStubP('p10','§ 23','§23 в разработке (W7) — лупа, микроскоп, телескоп.'),
@@ -355,9 +356,9 @@ const SIDEBARS = {
p2:{title:'Шпаргалка § 15', rows:[['Условие max','$\\Delta = k\\lambda$'],['Условие min','$\\Delta = (2k+1)\\lambda/2$'],['Когерентность','$\\omega$ и $\\Delta\\varphi$ = const'],['Опыт Юнга','2 щели → полосы'],['Кольца Ньютона','тонкие плёнки']]},
p3:{title:'Шпаргалка § 16', rows:[['Гюйгенс','каждая точка фронта — источник'],['Френель','+ интерференция вторичных'],['Решётка','$d\\sin\\varphi = k\\lambda$'],['$k$','порядок'],['$d$','период решётки']]},
p4:{title:'Шпаргалка § 17', rows:[['Прямолинейное','тени'],['Закон отражения','$\\angle_{пад} = \\angle_{отр}$'],['Плоское зеркало','мнимое, прямое, равное'],['Симметрия','$d_{объект} = d_{изобр}$ от зеркала']]},
- p5:{title:'§ 18', rows:[['Тема','Сферические зеркала'],['Статус','В разработке (W6)']]},
- p6:{title:'§ 19', rows:[['Тема','Преломление'],['Статус','В разработке (W6)']]},
- p7:{title:'§ 20', rows:[['Тема','Опт. элементы'],['Статус','В разработке (W6)']]},
+ p5:{title:'§ 18 — Сферические зеркала', rows:[['Формула','$\\dfrac{1}{d}+\\dfrac{1}{f}=\\dfrac{1}{F}$'],['Фокус','$F = R/2$'],['Увелич.','$\\Gamma = -f/d$']]},
+ p6:{title:'§ 19 — Преломление', rows:[['Закон','$n_1\\sin\\alpha = n_2\\sin\\beta$'],['Пок. прелом.','$n = c/v$'],['ПВО','$\\sin\\alpha_{кр}=n_2/n_1$ (если $n_1>n_2$)']]},
+ p7:{title:'§ 20 — Опт. элементы', rows:[['Призма','дисперсия $n(\\lambda)$'],['Пластинка','параллельный сдвиг'],['Оптоволокно','полное внутр. отражение']]},
p8:{title:'§ 21', rows:[['Тема','Тонкая линза'],['Статус','В разработке (W7)']]},
p9:{title:'§ 22', rows:[['Тема','Действ. изобр.'],['Статус','В разработке (W7)']]},
p10:{title:'§ 23', rows:[['Тема','Угол зрения'],['Статус','В разработке (W7)']]},
@@ -369,9 +370,9 @@ const TIPS=[
{sec:'p2',html:'§ 15 — интерференция = наложение когерентных волн. Условие max: $\\Delta = k\\lambda$. Опыт Юнга с двумя щелями.'},
{sec:'p3',html:'§ 16 — двигай $d$ и $\\lambda$. Чем меньше $d$, тем шире разлёт спектров. Главный max — $k=0$ (прямо).'},
{sec:'p4',html:'§ 17 — закон отражения: угол падения = углу отражения. Изображение в плоском зеркале — мнимое, симметричное.'},
- {sec:'p5',html:'§ 18 — в разработке (W6).'},
- {sec:'p6',html:'§ 19 — в разработке (W6).'},
- {sec:'p7',html:'§ 20 — в разработке (W6).'},
+ {sec:'p5',html:'§ 18 — фокус сферического зеркала $F = R/2$. Формула $1/d + 1/f = 1/F$ работает для любого зеркала. Если $f<0$ — изображение мнимое (за зеркалом).'},
+ {sec:'p6',html:'§ 19 — закон Снелла $n_1\\sin\\alpha = n_2\\sin\\beta$. Если идём из плотной среды в менее плотную и $\\alpha > \\alpha_{кр}$ — полное внутреннее отражение.'},
+ {sec:'p7',html:'§ 20 — призма разлагает белый свет в спектр, потому что $n(\\lambda)$ для разных $\\lambda$ разный. Оптоволокно работает за счёт ПВО.'},
{sec:'p8',html:'§ 21 — в разработке (W7).'},
{sec:'p9',html:'§ 22 — в разработке (W7).'},
{sec:'p10',html:'§ 23 — в разработке (W7).'},
@@ -777,7 +778,233 @@ function buildP4(){
renderMath(box);
}
-/* ===== Stubs §18-§23 + Final ===== */
+/* ===== §18 Сферические зеркала ===== */
+function buildP5(){
+ const box = document.getElementById('p5-body'); if(!box) return;
+ let html = '';
+
+ html += makeCard('theory', 'Сферические зеркала', '§ 18.1',
+ '
Сферическое зеркало — отполированная часть сферической поверхности. Бывают двух типов:
'
+ + ''
+ + 'Вогнутое (собирающее) — отражающая поверхность с внутренней стороны сферы. '
+ + 'Выпуклое (рассеивающее) — отражающая поверхность с наружной стороны. '
+ + ' '
+ + 'Основные точки зеркала: оптический центр $O$ (середина зеркала), центр сферы $C$, главный фокус $F$. Прямая, проходящая через $O$ и $C$, — главная оптическая ось .
'
+ + 'Главный фокус $F$ — точка, в которой пересекаются (или кажутся пересекающимися) отражённые лучи, параллельные главной оси.
'
+ + '$$F = \\dfrac{R}{2}$$
'
+ + 'где $R$ — радиус кривизны зеркала. Для выпуклого зеркала $F < 0$ (мнимый фокус).
');
+
+ html += makeCard('rule', 'Формула зеркала и увеличение', '§ 18.2',
+ 'Формула сферического зеркала связывает расстояние до объекта $d$, расстояние до изображения $f$ и фокусное расстояние $F$:
'
+ + '$$\\dfrac{1}{d} + \\dfrac{1}{f} = \\dfrac{1}{F}$$
'
+ + 'Линейное увеличение :
'
+ + '$$\\Gamma = \\dfrac{h_{изобр}}{h_{объект}} = -\\dfrac{f}{d}$$
'
+ + 'Знаки:
'
+ + ''
+ + '$f > 0$ — действительное изображение (перед зеркалом). '
+ + '$f < 0$ — мнимое (за зеркалом). '
+ + '$\\Gamma < 0$ — перевёрнутое; $\\Gamma > 0$ — прямое. '
+ + ' ');
+
+ html += makeCard('algo', 'Построение изображения — 3 луча', '§ 18.3',
+ 'Чтобы найти изображение объекта в сферическом зеркале, используют три характерных луча от верхней точки объекта:
'
+ + ''
+ + 'Параллельный главной оси → отражается через фокус $F$. '
+ + 'Через фокус $F$ → отражается параллельно главной оси. '
+ + 'Через центр сферы $C$ → отражается обратно по тому же пути (нормаль к поверхности). '
+ + ' '
+ + 'Точка пересечения отражённых лучей — изображение верха объекта. Достаточно двух любых из трёх лучей.
');
+
+ html += ''
+ + '
Двигай ползунки: F — фокусное расстояние, d — расстояние до объекта. Переключай тип зеркала. Зелёный луч — параллельный, синий — через фокус. Тёмно-коричневая стрелка — изображение (пунктир = мнимое).
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
$1/d + 1/f = 1/F$. Решено: 0 / 5.
'
+ + '
Проверить
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += '
';
+ html += readButton('p5');
+ html += secNavFor('p5');
+ box.innerHTML = html;
+
+ ensureFx(()=>{
+ const el = document.getElementById('fx-mir2');
+ const m = new PHYS.SphericalMirror(el, {width:620, height:280, F:80, d:180, objH:50, mode:'concave'});
+ const slBox = document.getElementById('fx-mir2-sl');
+ const slMode = ''
+ + 'Тип зеркала '
+ + ''
+ + 'Вогнутое Выпуклое '
+ + ' ';
+ const slF = PHYS.util.slider({label:'F (px)', min:30, max:140, step:5, value:80, fmt:v=>v.toFixed(0), onChange:v=>m.setF(v)});
+ const slD = PHYS.util.slider({label:'d (px)', min:40, max:280, step:10, value:180, fmt:v=>v.toFixed(0), onChange:v=>m.setD(v)});
+ slBox.innerHTML = slMode + slF.html + slD.html;
+ document.getElementById('fx-mir2-mode').addEventListener('change', e => m.setMode(e.target.value));
+ slF.wire(slBox); slD.wire(slBox);
+ });
+
+ runQuizInput('i5-calc', I5_CALC_ITEMS, 16);
+ runQuizMC('i5-th', I5_TH_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);
+}
+
+/* ===== §19 Преломление света ===== */
+function buildP6(){
+ const box = document.getElementById('p6-body'); if(!box) return;
+ let html = '';
+
+ html += makeCard('theory', 'Показатель преломления', '§ 19.1',
+ 'При переходе света из одной прозрачной среды в другую на границе луч преломляется — изменяет направление. Причина — разная скорость света в средах.
'
+ + 'Абсолютный показатель преломления среды:
'
+ + '$$n = \\dfrac{c}{v}$$
'
+ + 'где $c$ — скорость света в вакууме, $v$ — в данной среде. Поскольку $v < c$, всегда $n > 1$.
'
+ + 'Типичные значения: воздух $\\approx 1{,}00$ (≈ вакуум), вода 1,33, стекло 1,5, алмаз 2,42.
'
+ + 'Относительный показатель для перехода из среды 1 в среду 2:
'
+ + '$$n_{21} = \\dfrac{n_2}{n_1} = \\dfrac{v_1}{v_2}$$
');
+
+ html += makeCard('rule', 'Закон преломления (Снелл)', '§ 19.2',
+ 'Закон преломления света (Снелла – Декарта):
'
+ + ''
+ + 'Луч падающий, преломлённый и нормаль к границе в точке падения лежат в одной плоскости. '
+ + 'Отношение синуса угла падения к синусу угла преломления равно отношению показателей преломления: '
+ + ' '
+ + '$$n_1 \\sin\\alpha = n_2 \\sin\\beta$$
'
+ + 'или эквивалентно: $\\dfrac{\\sin\\alpha}{\\sin\\beta} = n_{21} = \\dfrac{n_2}{n_1}$.
'
+ + 'Запоминалка: луч «прижимается» к нормали при переходе в более плотную среду ($n_2 > n_1$ ⇒ $\\beta < \\alpha$).
');
+
+ html += makeCard('example', 'Полное внутреннее отражение', '§ 19.3',
+ 'Если свет идёт из более плотной среды в менее плотную ($n_1 > n_2$), угол преломления $\\beta > \\alpha$. При некотором угле падения $\\beta = 90°$ — луч скользит по границе.
'
+ + 'Критический угол $\\alpha_{кр}$ (предельный угол ПВО):
'
+ + '$$\\sin\\alpha_{кр} = \\dfrac{n_2}{n_1}$$
'
+ + 'При $\\alpha > \\alpha_{кр}$ преломление отсутствует — весь свет отражается обратно. Это полное внутреннее отражение (ПВО) .
'
+ + 'Применения: оптоволокно, перископы, бинокли, призмы оборачивающие.
'
+ + 'Пример: вода → воздух ($n_1=1{,}33$, $n_2=1$): $\\sin\\alpha_{кр} = 1/1{,}33 \\approx 0{,}75$, $\\alpha_{кр} \\approx 48{,}6°$.
');
+
+ html += ''
+ + '
Меняй угол падения $\\alpha$ и показатели сред. Красный — падающий, зелёный — преломлённый, пунктир — отражённый. При $n_1 > n_2$ можно поймать полное внутреннее отражение.
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
$n_1\\sin\\alpha = n_2\\sin\\beta$. Решено: 0 / 5.
'
+ + '
Проверить
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += '
';
+ html += readButton('p6');
+ html += secNavFor('p6');
+ box.innerHTML = html;
+
+ ensureFx(()=>{
+ const el = document.getElementById('fx-ref');
+ const r = new PHYS.RefractionLab(el, {width:540, height:320, n1:1, n2:1.5, alpha:35});
+ const slBox = document.getElementById('fx-ref-sl');
+ const slA = PHYS.util.slider({label:'α (град)', min:0, max:89, step:1, value:35, fmt:v=>v.toFixed(0), onChange:v=>r.setAlpha(v)});
+ const slN2 = PHYS.util.slider({label:'n₂', min:0.5, max:2.5, step:0.05, value:1.5, fmt:v=>v.toFixed(2), onChange:v=>r.setN2(v)});
+ const slN1 = PHYS.util.slider({label:'n₁', min:1, max:2.5, step:0.05, value:1, fmt:v=>v.toFixed(2), onChange:v=>r.setN1(v)});
+ slBox.innerHTML = slA.html + slN1.html + slN2.html;
+ slA.wire(slBox); slN1.wire(slBox); slN2.wire(slBox);
+ });
+
+ runQuizInput('i6-calc', I6_CALC_ITEMS, 16);
+ runQuizMC('i6-th', I6_TH_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);
+}
+
+/* ===== §20 Оптические элементы ===== */
+function buildP7(){
+ const box = document.getElementById('p7-body'); if(!box) return;
+ let html = '';
+
+ html += makeCard('theory', 'Призма и дисперсия', '§ 20.1',
+ 'Призма — прозрачное тело с двумя плоскими преломляющими гранями, образующими двугранный угол $A$ (преломляющий угол призмы).
'
+ + 'Луч, проходя через призму, преломляется на обеих гранях и отклоняется от исходного направления на угол отклонения $\\delta$.
'
+ + 'Дисперсия света — зависимость показателя преломления от длины волны (частоты): $n = n(\\lambda)$.
'
+ + 'Для большинства прозрачных сред $n$ растёт с уменьшением $\\lambda$ : фиолетовый свет ($\\lambda\\approx 400$ нм) преломляется сильнее красного ($\\lambda\\approx 700$ нм).
'
+ + 'Поэтому призма разлагает белый свет в спектр — Ньютон (1666).
'
+ + 'Радуга — природный пример дисперсии: капля воды работает как призма + зеркало (внутреннее отражение).
');
+
+ html += makeCard('rule', 'Плоскопараллельная пластинка', '§ 20.2',
+ 'Плоскопараллельная пластинка — стекло с двумя параллельными гранями.
'
+ + 'Луч, проходящий через пластинку, выходит параллельно падающему, но смещённым в сторону. Смещение:
'
+ + '$$x = h \\cdot \\dfrac{\\sin(\\alpha - \\beta)}{\\cos\\beta}$$
'
+ + 'где $h$ — толщина пластинки, $\\alpha$ — угол падения, $\\beta$ — угол преломления внутри.
'
+ + 'При $\\alpha = 0$ смещения нет — луч идёт перпендикулярно.
');
+
+ html += makeCard('example', 'Оптоволокно — полное внутреннее отражение', '§ 20.3',
+ 'Оптоволокно — тонкая стеклянная или пластиковая нить, передающая свет на большие расстояния благодаря многократному полному внутреннему отражению .
'
+ + 'Строение: сердцевина (core) с показателем $n_1$ и оболочка (cladding) с $n_2 < n_1$. Свет, попавший в сердцевину под углом $\\alpha > \\alpha_{кр}$, отражается от границы без потерь и распространяется вдоль волокна.
'
+ + 'Применения:
'
+ + ''
+ + 'Интернет и телефонная связь (магистральные сети). '
+ + 'Эндоскопы в медицине. '
+ + 'Освещение в зданиях, декоративные подсветки. '
+ + ' '
+ + 'Потери в современных волокнах — менее 0,2 дБ/км, что позволяет передавать сигнал на сотни километров без усиления.
');
+
+ html += ''
+ + '
Белый луч слева попадает на грань стеклянной призмы. Из-за дисперсии $n(\\lambda)$ цвета преломляются под разными углами. Двигай ползунок угла падения — наблюдай, как меняется спектр.
'
+ + '
'
+ + '
';
+
+ html += ''
+ + '
$\\sin\\alpha_{кр} = n_2/n_1$ (если $n_1 > n_2$). Решено: 0 / 5.
'
+ + '
Проверить
';
+
+ html += ''
+ + '
Решено: 0 / 5.
'
+ + '
';
+
+ html += '
';
+ html += readButton('p7');
+ html += secNavFor('p7');
+ box.innerHTML = html;
+
+ ensureFx(()=>{
+ const el = document.getElementById('fx-pr');
+ const p = new PHYS.PrismSpectrum(el, {width:580, height:260, alpha:50});
+ const slBox = document.getElementById('fx-pr-sl');
+ const slA = PHYS.util.slider({label:'α (град)', min:20, max:75, step:1, value:50, fmt:v=>v.toFixed(0), onChange:v=>p.setAlpha(v)});
+ slBox.innerHTML = slA.html;
+ slA.wire(slBox);
+ });
+
+ runQuizInput('i7-calc', I7_CALC_ITEMS, 16);
+ runQuizMC('i7-th', I7_TH_ITEMS, 12);
+
+ const bs = loadBossState('boss-7') || { stage:0, solved:false };
+ makeAndBindBoss('boss-7-slot', '7', BOSS_DEFS.b7, bs,
+ ()=>saveBossState('boss-7', bs),
+ ()=>{ bumpProgress('p7', 40); achievement('p7_done'); });
+
+ wireReadBtn('p7');
+ renderMath(box);
+}
+
+/* ===== Stubs §21-§23 + Final ===== */
function buildStubP(id, label, message){
const box = document.getElementById(id + '-body'); if(!box) return;
let html = '' + label + ' — в разработке ' + message + '
';
@@ -931,6 +1158,54 @@ const I4_IMG_ITEMS = [
{ q:'Угол падения отсчитывается от:', opts:['Поверхности','Нормали','Любого направления','Зеркала'], correct:1, explain:'От перпендикуляра к поверхности.' }
];
+const I5_CALC_ITEMS = [
+ { q:'$R = 40$ см. Фокус $F$ (см)?', answer:'20', explain:'$F = R/2 = 20$ см.' },
+ { q:'$F = 10$ см, $d = 30$ см. $f$ (см)?', answer:'15', explain:'$1/f = 1/10 - 1/30 = 2/30 \\Rightarrow f = 15$ см.' },
+ { q:'$F = 20$ см, $d = 60$ см. $\\Gamma$?', answer:['-0.5','-1/2'], explain:'$1/f = 1/20 - 1/60 = 1/30 \\Rightarrow f=30$; $\\Gamma = -30/60 = -0{,}5$.' },
+ { q:'$F = 15$ см, $d = 10$ см. $f$ (см)?', answer:['-30','-30см'], explain:'$1/f = 1/15 - 1/10 = -1/30 \\Rightarrow f = -30$ (мнимое).' },
+ { q:'$d = 2F$. $f$ относительно $F$?', answer:['2f','2','2*f'], explain:'$1/f = 1/F - 1/(2F) = 1/(2F) \\Rightarrow f = 2F$.' }
+];
+
+const I5_TH_ITEMS = [
+ { q:'Фокусное расстояние сферического зеркала:', opts:['$F = R$','$F = R/2$','$F = 2R$','$F = R^2$'], correct:1, explain:'$F = R/2$.' },
+ { q:'Выпуклое зеркало даёт изображение:', opts:['Действительное, перевёрнутое','Мнимое, прямое, уменьшенное','Действительное, увеличенное','Точечное'], correct:1, explain:'Мнимое за зеркалом.' },
+ { q:'Луч через центр сферы $C$:', opts:['Отражается обратно','Параллельно оси','Через фокус','Поглощается'], correct:0, explain:'По нормали — обратно.' },
+ { q:'Если объект между $F$ и зеркалом (вогнутое), изображение:', opts:['Действительное','Мнимое, увеличенное, прямое','Уменьшенное','Не образуется'], correct:1, explain:'Лупа — мнимое прямое.' },
+ { q:'$\\Gamma = -2$ означает:', opts:['Уменьшенное прямое','Увеличенное прямое','Увеличенное перевёрнутое в 2 раза','Без увеличения'], correct:2, explain:'$|\\Gamma|=2$, минус = перевёрнутое.' }
+];
+
+const I6_CALC_ITEMS = [
+ { q:'$n_1 = 1$, $\\alpha = 30°$, $n_2 = 1{,}5$. $\\sin\\beta$?', answer:['1/3','0.333','0.33'], explain:'$\\sin\\beta = \\sin 30°/1{,}5 = 0{,}5/1{,}5 = 1/3$.' },
+ { q:'Вода → воздух ($n_1=1{,}33$). $\\sin\\alpha_{кр}$?', answer:['0.75','3/4'], explain:'$\\sin\\alpha_{кр} = 1/1{,}33 \\approx 0{,}75$.' },
+ { q:'Алмаз $n = 2{,}42$, $\\sin\\alpha_{кр}$?', answer:['0.41','0.413'], explain:'$1/2{,}42 \\approx 0{,}413$ ⇒ $\\alpha_{кр} \\approx 24{,}4°$.' },
+ { q:'$n_{ст} = 1{,}5$. $v$ в стекле (м/с)?', answer:['2e8','2·10⁸','200000000'], explain:'$v = c/n = 3 \\cdot 10^8/1{,}5 = 2 \\cdot 10^8$.' },
+ { q:'$\\alpha = 60°$, $n_2/n_1 = 1{,}5$. $\\sin\\beta$?', answer:['0.577','√3/3','0.58'], explain:'$\\sin\\beta = \\sin 60°/1{,}5 = (\\sqrt 3/2)/1{,}5 \\approx 0{,}577$.' }
+];
+
+const I6_TH_ITEMS = [
+ { q:'Закон Снелла:', opts:['$n_1 \\sin\\alpha = n_2 \\sin\\beta$','$n_1 \\cos\\alpha = n_2 \\cos\\beta$','$n_1/\\alpha = n_2/\\beta$','$n_1 + n_2 = const$'], correct:0, explain:'Закон Снелла.' },
+ { q:'$n = c/v$ означает: в среде свет идёт:', opts:['Быстрее $c$','Медленнее $c$','С такой же скоростью','Не движется'], correct:1, explain:'$v = c/n < c$ при $n>1$.' },
+ { q:'ПВО возможно при переходе:', opts:['Воздух → стекло','Стекло → воздух','Вода → стекло','Никогда'], correct:1, explain:'Из более плотной в менее плотную ($n_1 > n_2$).' },
+ { q:'Если $n_2 > n_1$, луч:', opts:['Прижимается к нормали','Удаляется от нормали','Идёт по оригинальному пути','Останавливается'], correct:0, explain:'$\\beta < \\alpha$ — прижимается.' },
+ { q:'Палка в воде кажется сломанной из-за:', opts:['Отражения','Преломления','Дисперсии','Дифракции'], correct:1, explain:'Преломления на границе вода–воздух.' }
+];
+
+const I7_CALC_ITEMS = [
+ { q:'Стекло $n = 1{,}5$, воздух $n=1$. $\\sin\\alpha_{кр}$?', answer:['0.667','2/3','0.67'], explain:'$1/1{,}5 = 2/3$.' },
+ { q:'$n_{сердцевины} = 1{,}5$, $n_{оболочки} = 1{,}4$. $\\sin\\alpha_{кр}$?', answer:['0.933','14/15','0.93'], explain:'$1{,}4/1{,}5 = 14/15 \\approx 0{,}933$ ⇒ $\\alpha_{кр} \\approx 69°$.' },
+ { q:'$\\alpha_{кр} = 30°$. $n_{отношение}$?', answer:'0.5', explain:'$\\sin 30° = 0{,}5 = n_2/n_1$.' },
+ { q:'Толщина пластинки 4 см, $\\alpha=30°$, $\\beta = 19°$ (стекло). $x$ ≈ толщина $\\cdot \\sin(\\alpha-\\beta)/\\cos\\beta$ (см)?', answer:['0.8','0.79','0.81'], explain:'$x = 4 \\cdot \\sin 11°/\\cos 19° \\approx 4 \\cdot 0{,}19/0{,}945 \\approx 0{,}8$ см.' },
+ { q:'$\\lambda_{красн} = 700$ нм отклоняется призмой слабее или сильнее фиолетового 400 нм?', answer:['слабее','меньше'], explain:'$n(700) < n(400)$ ⇒ красный отклоняется слабее.' }
+];
+
+const I7_TH_ITEMS = [
+ { q:'Дисперсия — это:', opts:['Отражение','Зависимость $n$ от $\\lambda$','Разложение в спектр интерферометром','Дифракция в кристалле'], correct:1, explain:'$n = n(\\lambda)$.' },
+ { q:'Призма разлагает белый свет потому что:', opts:['Разные $\\lambda$ имеют разные $n$','Свет частично отражается','Кристаллы поглощают','Стекло поляризует'], correct:0, explain:'Дисперсия.' },
+ { q:'Плоскопараллельная пластинка:', opts:['Меняет направление луча','Смещает луч параллельно','Поглощает свет','Поворачивает поляризацию'], correct:1, explain:'Луч сдвигается, но не меняет угла.' },
+ { q:'Оптоволокно работает на:', opts:['Интерференции','Дифракции','Полном внутр. отражении','Поляризации'], correct:2, explain:'ПВО внутри сердцевины.' },
+ { q:'В радуге наблюдатель видит красный сверху , фиолетовый снизу потому что:', opts:['Красный преломляется сильнее','Фиолетовый преломляется сильнее','Цвета не отличаются','Капля поглощает синий'], correct:1, explain:'Фиолетовый ($\\lambda<$) преломляется сильнее.' }
+];
+
/* ===== Boss defs ===== */
const BOSS_DEFS = {
b1: { title:'Босс §14 — Скорость света', tag:'§14', xp:65, stages:[
@@ -960,6 +1235,27 @@ const BOSS_DEFS = {
{ q:'Изображение в плоском зеркале:', type:'mc', opts:['Действ., перевёрнутое','Мнимое, прямое, равное','Уменьшенное','Увеличенное'], correct:1, explain:'Мнимое, прямое, равное.' },
{ q:'Объект на 3 м от зеркала. Изображение на сколько метров от объекта?', type:'input', a:'6', explain:'$d + d = 6$ м.' },
{ q:'Если повернуть зеркало на 15°, отражённый луч повернётся на:', type:'input', a:'30', explain:'$2\\alpha = 30°$.' }
+ ]},
+ b5: { title:'Босс §18 — Сферические зеркала', tag:'§18', xp:75, stages:[
+ { q:'$R = 60$ см. $F$ (см)?', type:'input', a:'30', explain:'$F = R/2 = 30$ см.' },
+ { q:'$F=10$ см, $d=20$ см. $f$ (см)?', type:'input', a:'20', explain:'$1/f = 1/10 - 1/20 = 1/20 \\Rightarrow f = 20$.' },
+ { q:'Изображение в выпуклом зеркале:', type:'mc', opts:['Действительное увеличенное','Мнимое прямое уменьшенное','Перевёрнутое','Равное'], correct:1, explain:'Всегда мнимое, прямое, уменьшенное.' },
+ { q:'$\\Gamma = -f/d$. $f = 30$, $d = 15$. $\\Gamma$?', type:'input', a:['-2','-2.0'], explain:'$-30/15 = -2$.' },
+ { q:'Луч через фокус $F$ после отражения идёт:', type:'mc', opts:['Через $C$','Параллельно главной оси','Обратно','Через $O$'], correct:1, explain:'Стандартный луч 2.' }
+ ]},
+ b6: { title:'Босс §19 — Закон Снелла', tag:'§19', xp:75, stages:[
+ { q:'$n_1\\sin\\alpha = ?$', type:'mc', opts:['$n_2\\cos\\beta$','$n_2\\sin\\beta$','$n_2/\\sin\\beta$','$\\sin\\beta/n_2$'], correct:1, explain:'Снелл.' },
+ { q:'$n = c/v$. Если $n = 2$, то $v = ?$ (м/с)', type:'input', a:['1.5e8','1.5·10⁸','150000000'], explain:'$v = c/n = 1{,}5 \\cdot 10^8$.' },
+ { q:'$\\sin\\alpha_{кр} = n_2/n_1$ при условии:', type:'mc', opts:['$n_1 < n_2$','$n_1 > n_2$','$n_1 = n_2$','Любое'], correct:1, explain:'ПВО только из плотной в менее плотную.' },
+ { q:'$n_{вода} = 1{,}33$. $\\sin\\alpha_{кр}$ (округлить до 0,01)?', type:'input', a:['0.75','3/4'], explain:'$1/1{,}33 \\approx 0{,}75$.' },
+ { q:'Луч из стекла в воздух под $\\alpha = 60°$, $n_{ст}=1{,}5$. Что произойдёт?', type:'mc', opts:['Преломится','Полное внутр. отражение','Поглотится','Удвоится'], correct:1, explain:'$\\sin 60° = 0{,}866 > 0{,}667$ ⇒ ПВО.' }
+ ]},
+ b7: { title:'Босс §20 — Призма, оптоволокно', tag:'§20', xp:75, stages:[
+ { q:'Призма разлагает белый свет в спектр благодаря:', type:'mc', opts:['Дифракции','Интерференции','Дисперсии','Отражению'], correct:2, explain:'Дисперсия $n(\\lambda)$.' },
+ { q:'В стекле фиолетовый свет отклоняется ... красного:', type:'mc', opts:['Слабее','Сильнее','Одинаково','Не отклоняется'], correct:1, explain:'$n_{фиол} > n_{кр}$.' },
+ { q:'$n_{серд}=1{,}5$, $n_{обол}=1{,}4$. $\\sin\\alpha_{кр}$?', type:'input', a:['0.933','14/15','0.93'], explain:'$1{,}4/1{,}5 \\approx 0{,}933$.' },
+ { q:'Плоскопараллельная пластинка ... луч:', type:'mc', opts:['Поворачивает на 90°','Смещает параллельно','Поглощает','Разлагает в спектр'], correct:1, explain:'Параллельное смещение.' },
+ { q:'Оптоволокно использует:', type:'mc', opts:['Поляризацию','Полное внутр. отражение','Дифракцию','Радугу'], correct:1, explain:'ПВО в сердцевине.' }
]}
};