diff --git a/frontend/textbooks/geometry_11_ch2.html b/frontend/textbooks/geometry_11_ch2.html
index 1b9e8f8..c69c71d 100644
--- a/frontend/textbooks/geometry_11_ch2.html
+++ b/frontend/textbooks/geometry_11_ch2.html
@@ -392,7 +392,7 @@ function buildParaSelector(){
}
const BUILT=new Set();
-const BUILDERS = { p3:buildP3, p4:()=>buildStub('p4'), final2:()=>buildStub('final2') };
+const BUILDERS = { p3:buildP3, p4:buildP4, final2:()=>buildStub('final2') };
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);
@@ -417,13 +417,24 @@ const SIDEBARS = {
["Апофема","$l=\\\\sqrt{r^2+h^2}$"],
["Усечённая","$V=\\\\dfrac{h}{3}(S_1+S_2+\\\\sqrt{S_1 S_2})$"]
]},
- p4:{title:"Шпаргалка § 4", rows:[["Тема", "Конус"],["Формула","$S_{бок}=\\\\pi Rl$"]]},
+ p4:{title:"Шпаргалка § 4", rows:[
+ ["Конус","основание ($R$) + апекс"],
+ ["Связь","$l^2=R^2+h^2$"],
+ ["$S_{осн}$","$\\\\pi R^2$"],
+ ["$S_{бок}$","$\\\\pi R l$"],
+ ["$S_{полн}$","$\\\\pi R(R+l)$"],
+ ["$V$","$\\\\dfrac{1}{3}\\\\pi R^2 h$"],
+ ["Развёртка","сектор $r=l$, дуга $2\\\\pi R$"],
+ ["Угол развёртки","$\\\\varphi=\\\\dfrac{360°R}{l}$"],
+ ["Усечённый $V$","$\\\\dfrac{\\\\pi h}{3}(R_1^2+R_2^2+R_1R_2)$"],
+ ["Усечённый $S_{бок}$","$\\\\pi(R_1+R_2)l$"]
+ ]},
final2:{title:"Финал раздела 2", rows:[["§ 3–§ 4","теория раздела 2"],["Награда","+50 XP"]]}
};
const TIPS=[
{sec:'p3',html:"Главное правило: $V=\\\\\\\\dfrac{1}{3}S_{осн}h$ для любой пирамиды. А для правильной — $S_{бок}=\\\\\\\\dfrac{1}{2}P_{осн}l$, где $l$ — апофема."},
- {sec:'p4',html:"§ 4 «Конус» — содержание в разработке. $S_{бок}=\\\\\\\\pi Rl$"},
+ {sec:'p4',html:"Запомни связку: $l^2=R^2+h^2$. Все формулы конуса — это $\\\\\\\\pi R$ умноженное на соответствующий «множитель»: $R$ (основание), $l$ (боковая), $R+l$ (полная), $\\\\\\\\dfrac{Rh}{3}$ (объём)."},
{sec:'final2',html:"Финал раздела 2 — интегрированные задачи по разделу."}
];
@@ -986,6 +997,401 @@ function buildP3(){
wireReadBtn('p3');
}
+/* ===== § 4 «Конус» — Wave 2 ===== */
+
+function buildP4(){
+ const box = document.getElementById('p4-body');
+ if(!box) return;
+ let html = '';
+
+ /* === ТЕОРИЯ === */
+
+ html += makeCard('theory', 'Определение и элементы', '§ 4.1',
+ '
Конус (прямой круговой) — тело, образованное вращением прямоугольного треугольника вокруг одного из катетов.
'
+ + 'Элементы конуса:
'
+ + ''
+ + 'Основание — круг радиуса $R$ (получается вращением второго катета). '
+ + 'Вершина конуса (апекс) — точка на оси вращения, не лежащая в основании. '
+ + 'Ось — катет, вокруг которого вращали; совпадает с высотой $h$. '
+ + 'Образующие — отрезки длины $l$ от апекса к точкам окружности основания (это гипотенузы при вращении). Все образующие равны. '
+ + 'Боковая поверхность — поверхность вращения гипотенузы. '
+ + 'Высота $h$ — расстояние от апекса до плоскости основания. '
+ + ' '
+ + 'Главная связь (теорема Пифагора в осевом сечении):
'
+ + '$$l^2 = R^2 + h^2$$
'
+ + 'Конус — «предельный» случай пирамиды: если у правильной $n$-угольной пирамиды устремить число сторон основания $n\\to\\infty$ при фиксированном радиусе описанной окружности, то получится конус. Поэтому формулы для конуса можно получать «по аналогии» с пирамидой, заменяя $P_{осн}$ на $2\\pi R$, а $S_{осн}$ на $\\pi R^2$.
');
+
+ html += makeCard('rule', 'Площадь и объём. Развёртка', '§ 4.2',
+ 'Основные формулы:
'
+ + '$$S_{осн} = \\pi R^2$$
'
+ + '$$S_{бок} = \\pi R l$$
'
+ + '$$S_{полн} = \\pi R (R + l)$$
'
+ + '$$V = \\dfrac{1}{3}\\pi R^2 h$$
'
+ + 'Развёртка боковой поверхности конуса — это круговой сектор радиуса $l$ (равного образующей), у которого длина дуги равна длине окружности основания $2\\pi R$.
'
+ + 'Угол развёртки:
'
+ + '$$\\varphi = \\dfrac{2\\pi R}{l}\\;\\text{рад} = \\dfrac{360°\\cdot R}{l}$$
'
+ + 'Пример: конус $R=3$, $h=4$ '
+ + '
'
+ + '$l=\\sqrt{R^2+h^2}=\\sqrt{9+16}=5$ — образующая. '
+ + '$S_{осн}=\\pi R^2 = 9\\pi$. '
+ + '$S_{бок}=\\pi R l = 15\\pi$. '
+ + '$S_{полн}=\\pi R(R+l)= 3\\pi\\cdot 8 = 24\\pi\\approx 75{,}4$. '
+ + '$V=\\dfrac{1}{3}\\pi R^2 h=\\dfrac{1}{3}\\cdot 9\\pi\\cdot 4 = 12\\pi\\approx 37{,}7$. '
+ + 'Угол развёртки: $\\varphi=\\dfrac{360°\\cdot 3}{5}=216°$. '
+ + ' '
+ + '
');
+
+ html += makeCard('example', 'Сечения. Усечённый конус', '§ 4.3',
+ 'Сечения конуса плоскостью:
'
+ + ''
+ + 'Перпендикулярное оси (параллельное основанию): круг радиуса меньше $R$. Если плоскость находится на расстоянии $h_1$ от апекса, то радиус сечения $r_1 = \\dfrac{R\\,h_1}{h}$. '
+ + 'Осевое (плоскость проходит через ось): равнобедренный треугольник с основанием $2R$ и боковыми сторонами $l$. '
+ + 'Через апекс (плоскость содержит апекс, но не ось): равнобедренный треугольник с боковыми сторонами $l$ и основанием — хордой окружности. '
+ + ' '
+ + 'Усечённый конус — часть конуса, заключённая между основанием и плоскостью, параллельной основанию.
'
+ + ''
+ + 'Два круглых основания радиусов $R_1$ (нижнее, большее) и $R_2$ (верхнее, меньшее). '
+ + 'Высота $h$ — расстояние между плоскостями оснований. '
+ + 'Образующая $l$ — отрезок между соответствующими точками окружностей. Связь: $l^2 = h^2 + (R_1-R_2)^2$. '
+ + ' '
+ + '$$V = \\dfrac{1}{3}\\pi h\\bigl(R_1^2 + R_2^2 + R_1 R_2\\bigr)$$
'
+ + '$$S_{бок} = \\pi (R_1 + R_2)\\,l$$
'
+ + 'Пример: усечённый конус $R_1=5$, $R_2=3$, $h=4$ '
+ + '
'
+ + '$l=\\sqrt{h^2+(R_1-R_2)^2}=\\sqrt{16+4}=\\sqrt{20}=2\\sqrt{5}\\approx 4{,}47$. '
+ + '$S_{бок}=\\pi(R_1+R_2)l = 8\\pi\\cdot 2\\sqrt{5}=16\\pi\\sqrt{5}\\approx 112{,}4$. '
+ + '$V=\\dfrac{1}{3}\\pi\\cdot 4\\cdot(25+9+15)=\\dfrac{196\\pi}{3}\\approx 205{,}3$. '
+ + ' '
+ + '
');
+
+ /* === ИНТЕРАКТИВ 1 — 3D-конструктор конуса === */
+ html += ''
+ + ''
+ + '
Меняй радиус основания $R$ и высоту $h$. Вращай мышью или выбирай вид. После 4 разных конфигураций — +10 XP.
'
+ + '
'
+ + '$R$ (радиус):1.5 '
+ + '$h$ (высота):2.6 '
+ + '
'
+ + '
'
+ + 'Изо '
+ + 'Спереди '
+ + 'Сверху '
+ + 'Сбоку '
+ + '
'
+ + '
'
+ + '
'
+ + '$l=$— '
+ + '$S_{осн}=$— '
+ + '$S_{бок}=$— '
+ + '$S_{полн}=$— '
+ + '$V=$— '
+ + '$\\varphi=$— '
+ + '
'
+ + '
Конфигураций изучено: 0 / 4
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 2 — Развёртка (2D-сектор) === */
+ html += ''
+ + ''
+ + '
Двигай $R$ и $h$ — увидишь, как меняется круговой сектор развёртки: его радиус равен $l$, длина дуги — $2\\pi R$, а угол — $\\varphi=\\dfrac{360°R}{l}$. После 4 конфигураций — +10 XP.
'
+ + '
'
+ + '$R$ (радиус):1.5 '
+ + '$h$ (высота):2.6 '
+ + '
'
+ + '
'
+ + '
'
+ + '$l=$— '
+ + 'дуга $=2\\pi R=$— '
+ + 'угол $\\varphi=$— '
+ + '
'
+ + '
Конфигураций изучено: 0 / 4
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 3 — Квикфайр «какое сечение?» === */
+ html += ''
+ + ''
+ + '
Читай описание плоскости — выбирай форму сечения: круг , равнобедренный треугольник или эллипс .
'
+ + '
'
+ + '
Верно: 0 / 6
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 4 — Тренажёр V и S === */
+ html += ''
+ + ''
+ + '
Введи числовой ответ. Используй $\\pi\\approx 3{,}14$. Допуск $\\pm 0{,}05$.
'
+ + '
'
+ + '
Решено: 0 / 6
'
+ + '
';
+
+ html += secNavFor('p4');
+ html += readButton('p4');
+
+ box.innerHTML = html;
+ renderMath(box);
+
+ /* ====== JS-логика интерактивов ====== */
+
+ /* IV1 — 3D-конструктор конуса */
+ (function(){
+ if(!window.G3D) return;
+ const svg = document.getElementById('p4-iv1-svg');
+ const elR = document.getElementById('p4-iv1-R');
+ const elH = document.getElementById('p4-iv1-h');
+ const vR = document.getElementById('p4-iv1-R-v');
+ const vH = document.getElementById('p4-iv1-h-v');
+ const oL = document.getElementById('p4-iv1-l');
+ const oSo = document.getElementById('p4-iv1-So');
+ const oSb = document.getElementById('p4-iv1-Sb');
+ const oSt = document.getElementById('p4-iv1-St');
+ const oV = document.getElementById('p4-iv1-V');
+ const oPhi = document.getElementById('p4-iv1-phi');
+ const oCnt = document.getElementById('p4-iv1-cnt');
+ if(!svg) return;
+ const PI = 3.14;
+ const scene = G3D.createScene({W:480, H:400, scale:50, camDist:8, rotX:-0.35, rotY:0.7});
+ const seen = new Set();
+ let xpGiven = false;
+
+ function draw(){
+ const R = +elR.value, h = +elH.value;
+ vR.textContent = R.toFixed(1);
+ vH.textContent = h.toFixed(1);
+ const mesh = G3D.coneMesh(R, h, 32);
+ const M = G3D.buildRotMatrix(scene);
+ svg.innerHTML = G3D.renderMesh(mesh, M, scene, {
+ fillBase:'rgba(252,231,243,.55)',
+ fillSide:'rgba(219,234,254,.55)',
+ strokeVisible:'#0f172a',
+ strokeHidden:'#94a3b8'
+ });
+ const l = Math.sqrt(R*R + h*h);
+ const So = PI*R*R;
+ const Sb = PI*R*l;
+ const St = PI*R*(R + l);
+ const V = PI*R*R*h/3;
+ const phi = 360*R/l;
+ oL.textContent = l.toFixed(2);
+ oSo.textContent = So.toFixed(2);
+ oSb.textContent = Sb.toFixed(2);
+ oSt.textContent = St.toFixed(2);
+ oV.textContent = V.toFixed(2);
+ oPhi.textContent = phi.toFixed(1) + '°';
+ const key = R.toFixed(1)+'|'+h.toFixed(1);
+ seen.add(key);
+ oCnt.textContent = Math.min(seen.size, 4);
+ if(seen.size >= 4 && !xpGiven){
+ xpGiven = true;
+ addXp(10, 'p4-iv1');
+ bumpProgress('p4', 15);
+ const note = document.createElement('div');
+ note.className = 'feedback ok';
+ note.innerHTML = '✓ +10 XP за изучение 4 разных конусов!';
+ note.style.cssText = 'display:block;margin-top:8px';
+ const host = document.getElementById('p4-iv1');
+ if(host) host.appendChild(note);
+ setTimeout(function(){ try{ note.remove(); }catch(e){} }, 3000);
+ }
+ }
+ draw();
+ G3D.attachOrbit(svg, scene, draw);
+ [elR, elH].forEach(function(el){ el.addEventListener('input', draw); });
+ document.querySelectorAll('#p4-iv1 .g3d-tools .btn').forEach(function(b){
+ b.addEventListener('click', function(){ G3D.presetView(scene, b.dataset.view, draw); });
+ });
+ })();
+
+ /* IV2 — Развёртка (2D-сектор) */
+ (function(){
+ const svg = document.getElementById('p4-iv2-svg');
+ const elR = document.getElementById('p4-iv2-R');
+ const elH = document.getElementById('p4-iv2-h');
+ const vR = document.getElementById('p4-iv2-R-v');
+ const vH = document.getElementById('p4-iv2-h-v');
+ const oL = document.getElementById('p4-iv2-l');
+ const oArc = document.getElementById('p4-iv2-arc');
+ const oPhi = document.getElementById('p4-iv2-phi');
+ const oCnt = document.getElementById('p4-iv2-cnt');
+ if(!svg) return;
+ const PI = 3.14;
+ const W = 380, H = 320;
+ const cx = 190, cy = 180;
+ const seen = new Set();
+ let xpGiven = false;
+
+ function draw(){
+ const R = +elR.value, h = +elH.value;
+ vR.textContent = R.toFixed(1);
+ vH.textContent = h.toFixed(1);
+ const l = Math.sqrt(R*R + h*h);
+ const arc = 2*PI*R;
+ const phiDeg = 360*R/l;
+ const phiRad = phiDeg * Math.PI / 180;
+ /* масштаб: подгоняем радиус сектора к ~120px на SVG */
+ const scale = 120 / l;
+ const rPix = l * scale;
+ /* строим сектор: центр (cx,cy), от угла -phi/2 до +phi/2 (отсчёт от вертикали вверх) */
+ const a0 = -Math.PI/2 - phiRad/2;
+ const a1 = -Math.PI/2 + phiRad/2;
+ const x0 = cx + rPix*Math.cos(a0), y0 = cy + rPix*Math.sin(a0);
+ const x1 = cx + rPix*Math.cos(a1), y1 = cy + rPix*Math.sin(a1);
+ const largeArc = phiRad > Math.PI ? 1 : 0;
+ let s = '';
+ /* сетка для контекста */
+ s += ' ';
+ /* пунктирный круг полного радиуса l (показывает «целое» откуда вырезан сектор) */
+ s += ' ';
+ /* заливка сектора */
+ s += ' ';
+ /* радиус-метка слева (l) */
+ s += ' ';
+ const midR1x = (cx + x0)/2, midR1y = (cy + y0)/2;
+ s += 'l='+l.toFixed(2)+' ';
+ /* радиус справа */
+ s += ' ';
+ /* подпись дуги */
+ const midA = -Math.PI/2;
+ const labelR = rPix + 16;
+ const labX = cx + labelR*Math.cos(midA), labY = cy + labelR*Math.sin(midA);
+ s += 'дуга = 2πR ≈ '+arc.toFixed(2)+' ';
+ /* центр и подпись угла φ */
+ s += ' ';
+ /* дуга индикатор угла маленькая */
+ const angR = 26;
+ const ax0 = cx + angR*Math.cos(a0), ay0 = cy + angR*Math.sin(a0);
+ const ax1 = cx + angR*Math.cos(a1), ay1 = cy + angR*Math.sin(a1);
+ s += ' ';
+ s += 'φ='+phiDeg.toFixed(1)+'° ';
+ svg.innerHTML = s;
+ oL.textContent = l.toFixed(2);
+ oArc.textContent = arc.toFixed(2);
+ oPhi.textContent = phiDeg.toFixed(1) + '°';
+ const key = R.toFixed(1)+'|'+h.toFixed(1);
+ seen.add(key);
+ oCnt.textContent = Math.min(seen.size, 4);
+ if(seen.size >= 4 && !xpGiven){
+ xpGiven = true;
+ addXp(10, 'p4-iv2');
+ bumpProgress('p4', 15);
+ const note = document.createElement('div');
+ note.className = 'feedback ok';
+ note.innerHTML = '✓ +10 XP за изучение 4 разных развёрток!';
+ note.style.cssText = 'display:block;margin-top:8px';
+ const host = document.getElementById('p4-iv2');
+ if(host) host.appendChild(note);
+ setTimeout(function(){ try{ note.remove(); }catch(e){} }, 3000);
+ }
+ }
+ draw();
+ [elR, elH].forEach(function(el){ el.addEventListener('input', draw); });
+ })();
+
+ /* IV3 — Квикфайр сечений */
+ (function(){
+ const tasks = [
+ { q:'Плоскость перпендикулярна оси конуса и пересекает его.', a:'круг' },
+ { q:'Осевое сечение — плоскость проходит через ось конуса.', a:'треугольник' },
+ { q:'Плоскость параллельна основанию и не совпадает с ним.', a:'круг' },
+ { q:'Плоскость проходит через апекс и пересекает основание по хорде.', a:'треугольник' },
+ { q:'Плоскость наклонена к основанию под углом 30°, не проходит через апекс, пересекает все образующие.', a:'эллипс' },
+ { q:'Плоскость параллельна основанию и проходит через середину высоты.', a:'круг' }
+ ];
+ const list = document.getElementById('p4-iv3-list');
+ const scoreEl = document.getElementById('p4-iv3-score');
+ const solved = new Set();
+ let xpGiven = false;
+ const NAMES = {'круг':'Круг', 'треугольник':'Равнобедренный треугольник', 'эллипс':'Эллипс'};
+ list.innerHTML = tasks.map(function(t, i){
+ return ''
+ + '
Задание '+(i+1)+'. '+t.q+'
'
+ + '
'
+ + 'Круг '
+ + 'Равнобедренный треугольник '
+ + 'Эллипс '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(list);
+ list.querySelectorAll('button[data-i]').forEach(function(b){
+ b.addEventListener('click', function(){
+ const i = +b.dataset.i, v = b.dataset.v, t = tasks[i];
+ const fb = document.getElementById('p4-iv3-fb-'+i);
+ if(solved.has(i)) return;
+ if(v === t.a){
+ feedback(fb, true, '✓ Верно — это '+NAMES[t.a]+'.');
+ solved.add(i);
+ scoreEl.textContent = solved.size;
+ if(solved.size === tasks.length && !xpGiven){
+ xpGiven = true;
+ addXp(15, 'p4-iv3');
+ bumpProgress('p4', 25);
+ }
+ } else {
+ feedback(fb, false, '✗ Не то. Подумай ещё раз — где плоскость пересекает образующие?');
+ }
+ });
+ });
+ })();
+
+ /* IV4 — Тренажёр V, S, l, угол развёртки */
+ (function(){
+ const tasks = [
+ { q:'Конус: $R=3$, $h=4$. Найди $V$ (с $\\pi\\approx 3{,}14$).', a:37.68, tol:0.1 },
+ { q:'Тот же конус ($R=3$, $h=4$). Образующая $l=\\,?$', a:5, tol:0.05 },
+ { q:'Тот же конус ($R=3$, $h=4$). $S_{бок}=\\,?$ (с $\\pi\\approx 3{,}14$)', a:47.1, tol:0.1 },
+ { q:'Тот же конус ($R=3$, $h=4$). $S_{полн}=\\,?$ (с $\\pi\\approx 3{,}14$)', a:75.36, tol:0.1 },
+ { q:'Конус: $R=6$, $l=10$. Высота $h=\\,?$', a:8, tol:0.05 },
+ { q:'Конус $R=3$, $l=6$. Угол развёртки $\\varphi=\\,?$ (в градусах)', a:180, tol:0.5 }
+ ];
+ const list = document.getElementById('p4-iv4-list');
+ const scoreEl = document.getElementById('p4-iv4-score');
+ const solved = new Set();
+ let xpGiven = false;
+ list.innerHTML = tasks.map(function(t, i){
+ return ''
+ + '
Задача '+(i+1)+'. '+t.q+'
'
+ + '
'
+ + ' '
+ + 'Проверить '
+ + '
'
+ + '
'
+ + '
';
+ }).join('');
+ renderMath(list);
+ list.querySelectorAll('button[data-i]').forEach(function(b){
+ b.addEventListener('click', function(){
+ const i = +b.dataset.i, t = tasks[i];
+ const inp = document.getElementById('p4-iv4-inp-'+i);
+ const fb = document.getElementById('p4-iv4-fb-'+i);
+ const raw = (inp.value || '').replace(',', '.').trim();
+ const val = parseFloat(raw);
+ if(!isFinite(val)){ feedback(fb, false, '✗ Введи число'); return; }
+ if(Math.abs(val - t.a) <= t.tol){
+ feedback(fb, true, '✓ Верно!');
+ if(!solved.has(i)){
+ solved.add(i);
+ scoreEl.textContent = solved.size;
+ if(solved.size === tasks.length && !xpGiven){
+ xpGiven = true;
+ addXp(15, 'p4-iv4');
+ bumpProgress('p4', 25);
+ setTimeout(function(){ achievement('p4_done'); }, 400);
+ }
+ }
+ } else {
+ feedback(fb, false, '✗ Не точно. Пересчитай аккуратно (используй $\\pi\\approx 3{,}14$).');
+ }
+ });
+ });
+ })();
+
+ wireReadBtn('p4');
+}
+
/* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */
function buildStub(id){