diff --git a/frontend/textbooks/geometry_11_ch1.html b/frontend/textbooks/geometry_11_ch1.html
index c6f0800..3a77c31 100644
--- a/frontend/textbooks/geometry_11_ch1.html
+++ b/frontend/textbooks/geometry_11_ch1.html
@@ -392,7 +392,7 @@ function buildParaSelector(){
}
const BUILT=new Set();
-const BUILDERS = { p1:()=>buildStub('p1'), p2:()=>buildStub('p2'), final1:()=>buildStub('final1') };
+const BUILDERS = { p1:()=>buildP1(), p2:()=>buildStub('p2'), final1:()=>buildStub('final1') };
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);
@@ -407,13 +407,13 @@ function goTo(id){
}
const SIDEBARS = {
- p1:{title:"Шпаргалка § 1", rows:[["Тема", "Призма"],["Формула","$S_{бок}=Pl$, $V=S_{осн}h$"]]},
+ p1:{title:"Шпаргалка § 1", rows:[["Тема","Призма"],["Прямая","$S_{бок}=P_{осн}\\\\cdot h$"],["Наклонная","$S_{бок}=P_{пер}\\\\cdot l$"],["Объём","$V=S_{осн}\\\\cdot h$"],["Диагональ пар.","$d=\\\\sqrt{a^2+b^2+c^2}$"]]},
p2:{title:"Шпаргалка § 2", rows:[["Тема", "Цилиндр"],["Формула","$S_{бок}=2\\\\pi Rh$, $V=\\\\pi R^2h$"]]},
final1:{title:"Финал раздела 1", rows:[["§ 1–§ 2","теория раздела 1"],["Награда","+50 XP"]]}
};
const TIPS=[
- {sec:'p1',html:"§ 1 «Призма» — содержание в разработке. $S_{бок}=Pl$, $V=S_{осн}h$"},
+ {sec:'p1',html:"§ 1 «Призма» — крути 3D-модель в интерактиве 1, проверь формулы в калькуляторе. Главное: $V=S_{осн}\\\\cdot h$, $S_{бок}=P_{осн}\\\\cdot h$ (для прямой)."},
{sec:'p2',html:"§ 2 «Цилиндр» — содержание в разработке. $S_{бок}=2\\\\\\\\pi Rh$, $V=\\\\\\\\pi R^2h$"},
{sec:'final1',html:"Финал раздела 1 — интегрированные задачи по разделу."}
];
@@ -619,6 +619,376 @@ function wireReadBtn(paraId){
});
}
+/* ===== §1 «Призма» — Wave 1 ===== */
+function buildP1(){
+ const box = document.getElementById('p1-body');
+ if(!box) return;
+ let html = '';
+
+ /* === ТЕОРИЯ === */
+
+ html += makeCard('theory', 'Определение и виды призм', '§ 1.1',
+ '
Призма — многогранник, две грани которого (основания) — равные многоугольники, лежащие в параллельных плоскостях, а остальные грани (боковые) — параллелограммы.
'
+ + 'Виды призм:
'
+ + ''
+ + 'Прямая — боковые рёбра $\\perp$ основанию. Боковые грани — прямоугольники. '
+ + 'Наклонная — боковые рёбра не перпендикулярны основанию. '
+ + 'Правильная — прямая призма, основание которой — правильный многоугольник. '
+ + ' '
+ + 'Параллелепипед — призма с параллелограммом в основании. У неё $6$ граней, $12$ рёбер, $8$ вершин.
'
+ + 'Прямой параллелепипед — боковые рёбра $\\perp$ основанию. Прямоугольный параллелепипед — прямой, у которого основание — прямоугольник (значит, все грани — прямоугольники). Куб — прямоугольный параллелепипед с равными рёбрами.
'
+ + 'Свойства параллелепипеда:
'
+ + ''
+ + 'Противоположные грани равны и параллельны. '
+ + 'Все четыре диагонали пересекаются в одной точке и делятся ею пополам. '
+ + 'Диагональ прямоугольного параллелепипеда: $d=\\sqrt{a^2+b^2+c^2}$. '
+ + ' ');
+
+ html += makeCard('rule', 'Площадь поверхности и объём', '§ 1.2',
+ 'Боковая поверхность.
'
+ + ''
+ + 'Прямой призмы: $S_{бок}=P_{осн}\\cdot h$, где $P_{осн}$ — периметр основания, $h$ — высота (= боковое ребро). '
+ + 'Наклонной призмы: $S_{бок}=P_{пер}\\cdot l$, где $P_{пер}$ — периметр перпендикулярного сечения , $l$ — боковое ребро. '
+ + ' '
+ + 'Полная поверхность: $S_{полн}=S_{бок}+2\\cdot S_{осн}$.
'
+ + 'Объём (для любой призмы):
'
+ + '$$V=S_{осн}\\cdot h$$
'
+ + 'где $h$ — высота призмы (расстояние между плоскостями оснований).
'
+ + 'Пример: правильная 6-угольная призма '
+ + '
Сторона основания $a=4$, высота $h=10$:
'
+ + '
'
+ + '$S_{осн}=\\dfrac{3\\sqrt{3}}{2}\\,a^2=24\\sqrt{3}\\approx 41{,}57$ '
+ + '$P_{осн}=6a=24$ '
+ + '$S_{бок}=24\\cdot 10=240$ '
+ + '$V=24\\sqrt{3}\\cdot 10=240\\sqrt{3}\\approx 415{,}7$ '
+ + ' '
+ + '
');
+
+ html += makeCard('example', 'Диагональ прямоугольного параллелепипеда', '§ 1.3',
+ 'Пусть у прямоугольного параллелепипеда измерения $a$, $b$, $c$ (длина, ширина, высота).
'
+ + 'Диагональ грани (например, нижнего основания): $d_{грани}=\\sqrt{a^2+b^2}$.
'
+ + 'Главная диагональ — отрезок, соединяющий противоположные вершины. Тогда:
'
+ + '$$d^2=a^2+b^2+c^2$$
'
+ + 'Это трёхмерная теорема Пифагора .
'
+ + 'Доказательство '
+ + '
Возьмём вершину $A$ нижнего основания и противоположную $A_1$ верхнего. Соединим $A$ с вершиной $C$ нижнего основания, потом $C$ с $A_1$.
'
+ + '
В треугольнике $ACA_1$ угол при $C$ прямой (ребро $CC_1=c$ перпендикулярно плоскости основания). По Пифагору в нижнем основании: $AC^2=a^2+b^2$. В $\\triangle ACA_1$: $AA_1^2=AC^2+CA_1^2=a^2+b^2+c^2$.
'
+ + '
'
+ + 'Пример: куб со стороной $3 \\Rightarrow d=\\sqrt{9+9+9}=3\\sqrt{3}\\approx 5{,}20$.
');
+
+ /* === ИНТЕРАКТИВ 1 — 3D-конструктор === */
+ html += ''
+ + ''
+ + '
Меняй число сторон основания $n$, радиус описанной окружности $R$ и высоту $h$. Вращай мышью или выбирай вид. После 4 разных конфигураций — +10 XP.
'
+ + '
'
+ + '$n$ (сторон):5 '
+ + '$R$ (радиус):1.5 '
+ + '$h$ (высота):2.4 '
+ + '
'
+ + '
'
+ + 'Изо '
+ + 'Спереди '
+ + 'Сверху '
+ + 'Сбоку '
+ + '
'
+ + '
'
+ + '
'
+ + '$P_{осн}=$— '
+ + '$S_{осн}=$— '
+ + '$S_{бок}=$— '
+ + '$S_{полн}=$— '
+ + '$V=$— '
+ + '
'
+ + '
Конфигураций изучено: 0 / 4
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 2 — Калькулятор === */
+ html += '';
+
+ /* === ИНТЕРАКТИВ 3 — DnD сортер === */
+ html += ''
+ + ''
+ + '
Перетащи описание в нужный ящик. Кликни чип, затем ящик — тоже сработает.
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
'
+ + '
Проверить Сброс
'
+ + '
'
+ + '
';
+
+ /* === ИНТЕРАКТИВ 4 — Тренажёр === */
+ html += ''
+ + ''
+ + '
Введи числовой ответ. Допуск $\\pm 0{,}05$ для дробных значений.
'
+ + '
'
+ + '
Решено: 0 / 6
'
+ + '
';
+
+ html += secNavFor('p1');
+ html += readButton('p1');
+
+ box.innerHTML = html;
+ renderMath(box);
+
+ /* ====== JS-логика интерактивов ====== */
+
+ /* IV1 — 3D конструктор */
+ (function(){
+ if(!window.G3D) return;
+ const svg = document.getElementById('p1-iv1-svg');
+ const elN = document.getElementById('p1-iv1-n');
+ const elR = document.getElementById('p1-iv1-R');
+ const elH = document.getElementById('p1-iv1-h');
+ const vN = document.getElementById('p1-iv1-n-v');
+ const vR = document.getElementById('p1-iv1-R-v');
+ const vH = document.getElementById('p1-iv1-h-v');
+ const oP = document.getElementById('p1-iv1-P');
+ const oSb = document.getElementById('p1-iv1-Sb');
+ const oSs = document.getElementById('p1-iv1-Ss');
+ const oSt = document.getElementById('p1-iv1-St');
+ const oV = document.getElementById('p1-iv1-V');
+ const oCnt = document.getElementById('p1-iv1-cnt');
+ if(!svg) return;
+ 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 n = +elN.value, R = +elR.value, h = +elH.value;
+ vN.textContent = n;
+ vR.textContent = R.toFixed(1);
+ vH.textContent = h.toFixed(1);
+ const mesh = G3D.prismMesh(n, R, h);
+ 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'
+ });
+ /* Формулы для правильного n-угольника, вписанного в окружность радиуса R */
+ const a = 2*R*Math.sin(Math.PI/n);
+ const P = n*a;
+ const Sb = 0.5*n*R*R*Math.sin(2*Math.PI/n);
+ const Ss = P*h;
+ const St = Ss + 2*Sb;
+ const V = Sb*h;
+ oP.textContent = P.toFixed(2);
+ oSb.textContent = Sb.toFixed(2);
+ oSs.textContent = Ss.toFixed(2);
+ oSt.textContent = St.toFixed(2);
+ oV.textContent = V.toFixed(2);
+ const key = n+'|'+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, 'p1-iv1');
+ bumpProgress('p1', 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('p1-iv1');
+ if(host) host.appendChild(note);
+ setTimeout(function(){ try{ note.remove(); }catch(e){} }, 3000);
+ }
+ }
+ draw();
+ G3D.attachOrbit(svg, scene, draw);
+ [elN, elR, elH].forEach(function(el){ el.addEventListener('input', draw); });
+ document.querySelectorAll('#p1-iv1 .g3d-tools .btn').forEach(function(b){
+ b.addEventListener('click', function(){ G3D.presetView(scene, b.dataset.view, draw); });
+ });
+ })();
+
+ /* IV2 — Калькулятор */
+ (function(){
+ const radios = document.querySelectorAll('input[name="p1-iv2-type"]');
+ const fldReg = document.getElementById('p1-iv2-fields-reg');
+ const fldRect = document.getElementById('p1-iv2-fields-rect');
+ const elN = document.getElementById('p1-iv2-n');
+ const elA = document.getElementById('p1-iv2-a');
+ const elH = document.getElementById('p1-iv2-h');
+ const elRa = document.getElementById('p1-iv2-ra');
+ const elRb = document.getElementById('p1-iv2-rb');
+ const elRc = document.getElementById('p1-iv2-rc');
+ const labels = {
+ 'p1-iv2-n':'p1-iv2-n-v', 'p1-iv2-a':'p1-iv2-a-v', 'p1-iv2-h':'p1-iv2-h-v',
+ 'p1-iv2-ra':'p1-iv2-ra-v', 'p1-iv2-rb':'p1-iv2-rb-v', 'p1-iv2-rc':'p1-iv2-rc-v'
+ };
+ Object.keys(labels).forEach(function(k){
+ const el = document.getElementById(k), lab = document.getElementById(labels[k]);
+ if(!el || !lab) return;
+ const upd = function(){ lab.textContent = el.step === '1' ? el.value : (+el.value).toFixed(1); };
+ el.addEventListener('input', upd); upd();
+ });
+ radios.forEach(function(r){ r.addEventListener('change', function(){
+ const v = document.querySelector('input[name="p1-iv2-type"]:checked').value;
+ fldReg.style.display = v === 'reg' ? '' : 'none';
+ fldRect.style.display = v === 'rect' ? '' : 'none';
+ }); });
+ let xpGiven = false;
+ document.getElementById('p1-iv2-calc').addEventListener('click', function(){
+ const out = document.getElementById('p1-iv2-out');
+ const v = document.querySelector('input[name="p1-iv2-type"]:checked').value;
+ let html = '';
+ if(v === 'reg'){
+ const n = +elN.value, a = +elA.value, h = +elH.value;
+ const P = n*a;
+ const apo = a / (2*Math.tan(Math.PI/n));
+ const Sb = 0.5 * P * apo;
+ const Ss = P * h;
+ const St = Ss + 2*Sb;
+ const V = Sb * h;
+ html = ''
+ + '
Правильная '+n+'-угольная призма, $a='+a.toFixed(2)+'$, $h='+h.toFixed(2)+'$
'
+ + '
$P_{осн}=n\\cdot a='+n+'\\cdot '+a.toFixed(2)+'='+P.toFixed(2)+'$
'
+ + '
$S_{осн}=\\dfrac{1}{2}P\\cdot a_{апо}=\\dfrac{n a^2}{4}\\cot\\dfrac{\\pi}{n}\\approx '+Sb.toFixed(2)+'$
'
+ + '
$S_{бок}=P_{осн}\\cdot h='+P.toFixed(2)+'\\cdot '+h.toFixed(2)+'='+Ss.toFixed(2)+'$
'
+ + '
$S_{полн}=S_{бок}+2S_{осн}\\approx '+St.toFixed(2)+'$
'
+ + '
$V=S_{осн}\\cdot h\\approx '+V.toFixed(2)+'$
'
+ + '
';
+ } else {
+ const a = +elRa.value, b = +elRb.value, c = +elRc.value;
+ const V = a*b*c;
+ const St = 2*(a*b + b*c + a*c);
+ const d = Math.sqrt(a*a + b*b + c*c);
+ html = ''
+ + '
Прямоугольный параллелепипед, $a='+a.toFixed(2)+'$, $b='+b.toFixed(2)+'$, $c='+c.toFixed(2)+'$
'
+ + '
$V=abc='+a.toFixed(2)+'\\cdot '+b.toFixed(2)+'\\cdot '+c.toFixed(2)+'='+V.toFixed(2)+'$
'
+ + '
$S_{полн}=2(ab+bc+ac)='+St.toFixed(2)+'$
'
+ + '
$d=\\sqrt{a^2+b^2+c^2}=\\sqrt{'+(a*a+b*b+c*c).toFixed(2)+'}\\approx '+d.toFixed(2)+'$
'
+ + '
';
+ }
+ out.innerHTML = html;
+ renderMath(out);
+ if(!xpGiven){
+ xpGiven = true;
+ addXp(10, 'p1-iv2');
+ bumpProgress('p1', 15);
+ }
+ });
+ })();
+
+ /* IV3 — DnD сортер */
+ (function(){
+ const items = [
+ { id:'i1', html:'Основание — правильный 6-угольник, боковые рёбра $\\perp$ основанию', cat:'regular' },
+ { id:'i2', html:'Боковые рёбра наклонены к основанию под углом 60°', cat:'oblique' },
+ { id:'i3', html:'Все 6 граней — прямоугольники, все рёбра равны (куб)', cat:'straight' },
+ { id:'i4', html:'Боковые рёбра $\\perp$ основанию, основание — параллелограмм', cat:'straight' },
+ { id:'i5', html:'Основание — квадрат со стороной 3, высота 5, боковые рёбра $\\perp$', cat:'regular' },
+ { id:'i6', html:'Боковые грани — параллелограммы, не прямоугольники', cat:'oblique' }
+ ];
+ const sorter = setupSorter({
+ poolId:'p1-iv3-pool',
+ scopeSelector:'#p1-iv3',
+ items: items,
+ cats: ['straight','regular','oblique']
+ });
+ let xpGiven = false;
+ document.getElementById('p1-iv3-check').addEventListener('click', function(){
+ const fb = document.getElementById('p1-iv3-fb');
+ let correct = 0;
+ items.forEach(function(it){ if(sorter.placed[it.id] === it.cat) correct++; });
+ if(correct === items.length){
+ feedback(fb, true, '✓ Все 6 правильно! +15 XP');
+ if(!xpGiven){
+ xpGiven = true;
+ addXp(15, 'p1-iv3');
+ bumpProgress('p1', 25);
+ }
+ } else {
+ feedback(fb, false, '✗ Правильно: '+correct+' из '+items.length+'. Попробуй ещё раз.');
+ }
+ });
+ document.getElementById('p1-iv3-reset').addEventListener('click', function(){
+ sorter.reset();
+ const fb = document.getElementById('p1-iv3-fb'); fb.style.display = 'none';
+ });
+ })();
+
+ /* IV4 — Тренажёр */
+ (function(){
+ const tasks = [
+ { q:'Прямоугольный параллелепипед $3\\times 4\\times 5$. $V=\\,?$', a:60, tol:0.05 },
+ { q:'Куб со стороной 2. $V=\\,?$', a:8, tol:0.05 },
+ { q:'Куб со стороной 3. Диагональ $d=\\,?$ (точность 0,01)', a:5.20, tol:0.05 },
+ { q:'Прямоугольный параллелепипед $2\\times 3\\times 6$. Главная диагональ?', a:7, tol:0.05 },
+ { q:'Правильная 4-угольная призма со стороной основания 4 и высотой 5. $V=\\,?$', a:80, tol:0.05 },
+ { q:'Прямоугольный параллелепипед $3\\times 4\\times 5$. $S_{полн}=\\,?$', a:94, tol:0.05 }
+ ];
+ const list = document.getElementById('p1-iv4-list');
+ const scoreEl = document.getElementById('p1-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('p1-iv4-inp-'+i);
+ const fb = document.getElementById('p1-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, 'p1-iv4');
+ bumpProgress('p1', 25);
+ setTimeout(function(){ achievement('p1_done'); }, 400);
+ }
+ }
+ } else {
+ feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.');
+ }
+ });
+ });
+ })();
+
+ wireReadBtn('p1');
+}
+
/* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */
function buildStub(id){