diff --git a/backend/tests/chemistry7-page.test.js b/backend/tests/chemistry7-page.test.js
index bfef7eb..f2b1d23 100644
--- a/backend/tests/chemistry7-page.test.js
+++ b/backend/tests/chemistry7-page.test.js
@@ -25,6 +25,7 @@ function buildPage(file) {
'/js/chem7_svg.js': readF('frontend/js/chem7_svg.js'),
'/js/chem7_ch1_widgets.js': readF('frontend/js/chem7_ch1_widgets.js'),
'/js/chem7_ch2_widgets.js': readF('frontend/js/chem7_ch2_widgets.js'),
+ '/js/chem7_ch3_widgets.js': readF('frontend/js/chem7_ch3_widgets.js'),
'/js/chem8_engine.js': readF('frontend/js/chem8_engine.js')
};
html = html
@@ -162,6 +163,19 @@ test('ch2 Волна 2: §16 + §17 + ПР2 + финал главы монтир
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
});
+test('ch3 Волна 1: §18 + §19 + §20 + ЛО3 монтируются', async () => {
+ const { doc, errors } = await loadDom('chemistry_7_ch3.html');
+ assert.ok(doc.querySelector('#p18-card svg'), 'паспорт водорода §18');
+ doc.defaultView.goTo('p19'); await wait(100);
+ assert.ok(doc.querySelector('#p19-rx #p19-pick'), 'реакции водорода §19');
+ doc.defaultView.goTo('p20'); await wait(100);
+ assert.ok(doc.querySelector('#p20-ind #p20-ind-ind'), 'индикаторы §20');
+ assert.ok(doc.querySelector('#p20-acids table'), 'таблица кислот §20');
+ doc.defaultView.goTo('lo3'); await wait(100);
+ assert.ok(doc.querySelector('#lo3-ind #lo3-ind-ind'), 'индикаторы ЛО3');
+ assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
+});
+
/* ── Хаб: каталог глав + финал курса ── */
function buildHub() {
let html = readF('frontend/textbooks/chemistry_7_hub.html');
diff --git a/frontend/js/chem7_ch3_widgets.js b/frontend/js/chem7_ch3_widgets.js
new file mode 100644
index 0000000..2369a47
--- /dev/null
+++ b/frontend/js/chem7_ch3_widgets.js
@@ -0,0 +1,172 @@
+/* chem7_ch3_widgets.js — интерактивы главы 3 «Водород» (Химия 7).
+ * Монтируются движком chem8_engine.js: window.CHEM8_WIDGETS[id].
+ * Используют window.Chem8 (chem8_svg.js): chemEq, formula.
+ * Без эмоджи; KaTeX — через window.chem8RenderMath.
+ */
+(function (W) {
+ 'use strict';
+ function C() { return W.Chem8 || {}; }
+ function $(id) { return document.getElementById(id); }
+ function esc(s){ return String(s).replace(/&/g,'&').replace(//g,'>'); }
+ function gcd(a, b) { return b ? gcd(b, a % b) : a; }
+ function ceq(src, opts){ return C().chemEq ? C().chemEq(src, opts || {}) : esc(src); }
+ function fml(s){ return C().formula ? C().formula(s) : s; }
+ var COL = { H:'#cbd5e1', O:'#ef4444' };
+ function molSvg(atoms){
+ var list=[]; atoms.forEach(function(p){ for(var i=0;i
'+el+''; x+=24; });
+ return '';
+ }
+
+ /* §18 — модель H₂ + паспорт водорода */
+ function mount_p18() {
+ var m = $('p18-card'); if (!m || m._built) return; m._built = 1;
+ m.innerHTML = molSvg([['H',2]])
+ + '
Водород Элемент: символ H, $Z=1$, $A_r=1$ — самый лёгкий элемент. '
+ + 'Простое вещество: молекула $H_2$ — самый лёгкий газ, без цвета и запаха, легче воздуха, мало растворим в воде. '
+ + 'В природе: в составе воды, многих веществ; во Вселенной — самый распространённый элемент.
';
+ if (W.chem8RenderMath) try { W.chem8RenderMath(m); } catch(e){}
+ }
+
+ /* §19 — реакции водорода: горение и восстановление */
+ var RX = [
+ { name:'Горение водорода в кислороде', eq:'2H2 + O2 = 2H2O', note:'Водород горит, образуя воду. Смесь водорода с воздухом — «гремучий газ», взрывается!' },
+ { name:'Восстановление оксида меди(II)', eq:'H2 + CuO = Cu + H2O', note:'Водород отнимает кислород у оксида: чёрный CuO превращается в красную медь. Водород здесь — восстановитель.' }
+ ];
+ function mount_p19() {
+ var m = $('p19-rx'); if (!m || m._built) return; m._built = 1;
+ var idx = 0;
+ function render(){
+ var r = RX[idx];
+ var swatch = idx===1 ? '
CuO (чёрный) → Cu (красный)
' : '';
+ m.innerHTML = ''
+ + '
' + ceq(r.eq) + '
' + esc(r.note) + '
' + swatch + '
';
+ $('p19-pick').addEventListener('change', function(e){ idx=+e.target.value; m._built=0; render(); });
+ }
+ render();
+ }
+
+ /* индикаторы */
+ var ACIDS = [
+ { f:'HCl', name:'соляная', res:'Cl', resName:'хлорид', resVal:1 },
+ { f:'H2SO4', name:'серная', res:'SO4', resName:'сульфат', resVal:2 },
+ { f:'HNO3', name:'азотная', res:'NO3', resName:'нитрат', resVal:1 },
+ { f:'H2CO3', name:'угольная', res:'CO3', resName:'карбонат',resVal:2 }
+ ];
+ var INDIC = {
+ 'Лакмус': { neutral:['#7c3aed','фиолетовый'], acid:['#dc2626','красный'] },
+ 'Метилоранж': { neutral:['#f59e0b','оранжевый'], acid:['#e11d48','розово-красный'] }
+ };
+ function indicatorWidget(mountId, withAcidPick) {
+ var m = $(mountId); if (!m || m._built) return; m._built = 1;
+ var ind = 'Лакмус', acid = 0;
+ function strip(color){ return ''; }
+ function render(){
+ var a = ACIDS[acid], col = INDIC[ind];
+ m.innerHTML = '
Слева активность убывает вправо. Граница — водород H₂.
'
+ + '
Кликни по металлу — узнаешь, вытесняет ли он водород из кислоты.
';
+ var out = $('p21-act-out');
+ m.querySelectorAll('.act-cell').forEach(function(b){
+ b.addEventListener('click', function(){
+ var i=+b.dataset.i, el=ROW[i]; if(el==='H'){ out.className='out'; out.innerHTML='Водород H₂ — граница ряда активности.'; return; }
+ out.className='out ok';
+ if(iВнимание: очень активный металл — с кислотами реагирует бурно (для получения водорода используют Zn, Fe).' : '';
+ out.innerHTML = ''+el+' стоит левее H₂ → вытесняет водород из соляной и серной кислот: образуются соль и $H_2\\uparrow$.'+extra;
+ } else {
+ out.innerHTML = ''+el+' стоит правее H₂ → водород из кислот не вытесняет (например, медь и серебро с этими кислотами не реагируют).';
+ }
+ if (W.chem8RenderMath) try { W.chem8RenderMath(out); } catch(e){}
+ });
+ });
+ }
+
+ /* ЛО4 — взаимодействие кислот с металлами */
+ var L4M = [ ['Zn','цинк',1], ['Fe','железо',1], ['Mg','магний',1], ['Cu','медь',0] ];
+ var L4A = [ ['HCl','соляная'], ['H2SO4','серная'] ];
+ function mount_lo4() {
+ var m = $('lo4-rx'); if (!m || m._built) return; m._built = 1;
+ var mi=0, ai=0;
+ var EQ = { 'Zn|HCl':'Zn + 2HCl = ZnCl2 + H2^', 'Zn|H2SO4':'Zn + H2SO4 = ZnSO4 + H2^',
+ 'Fe|HCl':'Fe + 2HCl = FeCl2 + H2^', 'Fe|H2SO4':'Fe + H2SO4 = FeSO4 + H2^',
+ 'Mg|HCl':'Mg + 2HCl = MgCl2 + H2^', 'Mg|H2SO4':'Mg + H2SO4 = MgSO4 + H2^' };
+ function render(){
+ m.innerHTML = '
'
+ + ''
+ + '
Выбери металл и кислоту.
';
+ $('lo4-m').addEventListener('change',function(e){mi=+e.target.value;m._built=0;render();});
+ $('lo4-a').addEventListener('change',function(e){ai=+e.target.value;m._built=0;render();});
+ $('lo4-go').addEventListener('click',function(){
+ var met=L4M[mi], ac=L4A[ai], out=$('lo4-out');
+ if(!met[2]){ out.className='out bad'; out.innerHTML=''+met[1]+' стоит правее H₂ в ряду активности — реакция не идёт, пузырьки не выделяются.'; return; }
+ out.className='out ok';
+ out.innerHTML='Наблюдаем выделение пузырьков газа (водород $H_2\\uparrow$). Металл вытесняет водород из кислоты:
'+ceq(EQ[met[0]+'|'+ac[0]])+'
';
+ if (W.chem8RenderMath) try { W.chem8RenderMath(out); } catch(e){}
+ });
+ }
+ render();
+ }
+
+ /* §22 — конструктор солей (металл + кислотный остаток) */
+ var SM = [ ['Na',1], ['K',1], ['Ca',2], ['Mg',2], ['Zn',2], ['Al',3] ];
+ var SR = [ ['Cl',1,'хлорид'], ['NO3',1,'нитрат'], ['SO4',2,'сульфат'], ['CO3',2,'карбонат'] ];
+ function mount_p22() {
+ var m = $('p22-salt'); if (!m || m._built) return; m._built = 1;
+ function render(){
+ m.innerHTML = '
'
+ + '
';
+ $('p22-m').addEventListener('change',upd); $('p22-r').addEventListener('change',upd); upd();
+ }
+ function rom(n){ return ['','I','II','III'][n]; }
+ function upd(){
+ var me=SM[+$('p22-m').value], re=SR[+$('p22-r').value];
+ var lcm=me[1]*re[1]/gcd(me[1],re[1]), x=lcm/me[1], y=lcm/re[1];
+ var poly=/[0-9]/.test(re[0]);
+ var raw = me[0] + (x>1?x:'') + (poly && y>1 ? '('+re[0]+')'+y : re[0] + (y>1?y:''));
+ var out=$('p22-out'); out.className='out ok';
+ out.innerHTML='Валентности: '+me[0]+' = '+rom(me[1])+', остаток '+fml(re[0])+' = '+rom(re[1])+' Формула соли ('+re[2]+'а): '+fml(raw)+'';
+ }
+ render();
+ }
+
+ /* ПР3 — чистота водорода («гремучий газ») */
+ function mount_pr3() {
+ var m = $('pr3-test'); if (!m || m._built) return; m._built = 1;
+ m.innerHTML = '
Чтобы проверить чистоту водорода, его поджигают.
';
+ $('pr3-mix').addEventListener('click',function(){ var o=$('pr3-out'); o.className='out bad'; o.innerHTML='Смесь водорода с воздухом — «гремучий газ» — взрывается с резким хлопком. Значит, водород собран нечисто.'; });
+ $('pr3-pure').addEventListener('click',function(){ var o=$('pr3-out'); o.className='out ok'; o.innerHTML='Чистый водород горит спокойно, почти без звука. Значит, газ собран чисто.'; });
+ }
+
+ W.CHEM8_WIDGETS = Object.assign(W.CHEM8_WIDGETS || {}, {
+ p18: mount_p18, p19: mount_p19, p20: mount_p20, lo3: mount_lo3,
+ p21: mount_p21, lo4: mount_lo4, p22: mount_p22, pr3: mount_pr3
+ });
+ W.FLAG_MOUNTS = Object.assign(W.FLAG_MOUNTS || {}, {});
+})(window);
diff --git a/frontend/textbooks/chemistry_7_ch3.html b/frontend/textbooks/chemistry_7_ch3.html
index da9ee68..3a7b08f 100644
--- a/frontend/textbooks/chemistry_7_ch3.html
+++ b/frontend/textbooks/chemistry_7_ch3.html
@@ -17,6 +17,7 @@
+
@@ -90,11 +91,114 @@ window.PARAS = [
{id:'final3', num:'★', name:'Финал главы', sub:'босс · ачивка', final:true}
];
-window.ACH_LABELS = { start:'Начало главы 3!', final3_tasks:'Глава 3 пройдена!' };
-window.SIDEBARS = { p18:{ title:'Глава 3 · Химия 7', rows:[['Раздел','Водород'],['§§','18–22'],['Лаб/ПР','ЛО 3,4 · ПР 3']] } };
-window.TIPS = [{ sec:'p18', html:'Глава наполняется содержанием по фазам. Сейчас доступны навигация по параграфам и отметка о прочтении (+10 XP).' }];
+window.ACH_LABELS = { start:'Начало главы 3!', p18_done:'§18 изучен!', p19_done:'§19 изучен!',
+ p20_done:'§20 изучен!', lo3_done:'Лабораторный опыт 3 выполнен!', final3_tasks:'Глава 3 пройдена!' };
+window.SIDEBARS = {
+ p18:{ title:'Шпаргалка §18', rows:[['$H$','элемент, $Z=1$'],['$H_2$','самый лёгкий газ'],['Вселенная','самый частый элемент']] },
+ p19:{ title:'Шпаргалка §19', rows:[['Горение','$+O_2 \\to H_2O$'],['Гремучий газ','$H_2$ + воздух'],['Восстановитель','отнимает O у оксида']] },
+ p20:{ title:'Шпаргалка §20', rows:[['Кислота','H + остаток'],['Примеры','$HCl$, $H_2SO_4$'],['Лакмус','в кислоте красный']] },
+ lo3:{ title:'Лаб. опыт 3', rows:[['Лакмус','красный'],['Метилоранж','розово-красный']] }
+};
+window.TIPS = [
+ { sec:'p18', html:'$H$ — самый лёгкий элемент ($A_r=1$). Простое вещество $H_2$ — самый лёгкий газ, легче воздуха. Во Вселенной водород — самый распространённый элемент.' },
+ { sec:'p19', html:'Водород горит в кислороде, образуя воду. С оксидами он ведёт себя как восстановитель: $H_2 + CuO = Cu + H_2O$.' },
+ { sec:'p20', html:'Кислота = атомы водорода + кислотный остаток. Индикаторы меняют цвет: лакмус в кислоте — красный, метилоранж — розово-красный.' },
+ { sec:'lo3', html:'В кислоте лакмус становится красным, а метилоранж — розово-красным. Так обнаруживают кислоту.' }
+];
-/* Phase 0: заглушки-builder'ы из PARAS (теория и интерактивы добавляются в фазах 1–4). */
+window.POOLS = {
+ p18:[
+ {q:'Водород — это самый…',opts:['Тяжёлый газ','Лёгкий газ','Активный металл','Ядовитый газ'],a:1,ex:'$H_2$ — самый лёгкий газ.'},
+ {q:'Чему равна относительная атомная масса водорода $A_r(\\text{H})$?',hint:'из таблицы',unit:'',a:1,ex:'$A_r(\\text{H})=1$.'},
+ {q:'$\\text{H}_2$ — это…',opts:['Химический элемент','Простое вещество','Сложное вещество','Смесь'],a:1,ex:'Молекула из двух атомов одного элемента — простое вещество.'},
+ {q:'Где водород встречается чаще всего?',opts:['В земной коре','Во Вселенной','В металлах','В песке'],a:1,ex:'Во Вселенной водород — самый распространённый элемент.'}
+ ],
+ p19:[
+ {q:'При горении водорода в кислороде образуется…',opts:['Углекислый газ','Вода','Оксид меди','Соль'],a:1,ex:'$2H_2+O_2=2H_2O$.'},
+ {q:'Смесь водорода с воздухом называют…',opts:['Угарным газом','Гремучим газом','Озоном','Сухим льдом'],a:1,ex:'Гремучий газ взрывоопасен.'},
+ {q:'В реакции $\\text{H}_2+\\text{CuO}=\\text{Cu}+\\text{H}_2\\text{O}$ водород является…',opts:['Окислителем','Восстановителем','Катализатором','Индикатором'],a:1,ex:'Водород отнимает кислород — восстановитель.'},
+ {q:'Коэффициент перед $\\text{H}_2\\text{O}$ в $2\\text{H}_2+\\text{O}_2=2\\text{H}_2\\text{O}$?',hint:'',unit:'',a:2,ex:'2.'}
+ ],
+ p20:[
+ {q:'Из чего состоит кислота?',opts:['Из металла и кислорода','Из атомов водорода и кислотного остатка','Из двух металлов','Из воды и соли'],a:1,ex:'Кислота = водород + кислотный остаток.'},
+ {q:'Какого цвета становится лакмус в кислоте?',opts:['Синего','Красного','Зелёного','Жёлтого'],a:1,ex:'Лакмус в кислоте — красный.'},
+ {q:'Какова формула серной кислоты?',opts:['HCl','H₂SO₄','HNO₃','H₂CO₃'],a:1,ex:'Серная кислота — $H_2SO_4$.'},
+ {q:'Индикатор — это вещество, которое…',opts:['Ускоряет реакцию','Меняет цвет в кислоте или щёлочи','Растворяет металлы','Выделяет газ'],a:1,ex:'Индикаторы обнаруживают кислоты и щёлочи по изменению цвета.'}
+ ]
+};
+
+function rememberBox(items){
+ return '
Самый лёгкий элемент Вселенной и его простое вещество.
'
+ +'
$H$$H_2$
'
+ +makeCard('theory','Элемент и простое вещество','§18','
Водород как элемент — атомы H ($Z=1$, $A_r=1$), самый лёгкий из всех элементов. Атомы водорода входят в состав воды и множества других веществ.
'
+ +'
Водород как простое вещество — газ $\\text{H}_2$ (молекула из двух атомов). Это самый лёгкий газ, легче воздуха.
')
+ +makeCard('theory','Свойства и нахождение','§18','
$\\text{H}_2$ — газ без цвета и запаха, мало растворим в воде. В свободном виде на Земле водорода почти нет, но в составе веществ (особенно воды) его много. Во Вселенной водород — самый распространённый элемент.
')
+ +wgt('Паспорт водорода','')
+ +rememberBox(['$H$ — самый лёгкий элемент ($A_r=1$).','$H_2$ — самый лёгкий газ, легче воздуха.','Во Вселенной водород — самый распространённый элемент.'])
+ +qList(['Чем водород-элемент отличается от простого вещества $H_2$?','Назови физические свойства водорода.','Где на Земле находится водород?'])
+ +secNav(null,'p19')+readButton('p18');
+ wireReadBtn('p18');
+}
+
+function build_p19(){
+ document.getElementById('p19-body').innerHTML =
+ '
§ 19 · Химия 7
Химические свойства водорода
'
+ +'
$2\\text{H}_2+\\text{O}_2=2\\text{H}_2\\text{O}$
'
+ +'
Как водород горит и почему его называют восстановителем.
'
+ +'
горениевосстановитель
'
+ +makeCard('theory','Горение водорода','§19','
Водород горит в кислороде, образуя воду: $2\\text{H}_2+\\text{O}_2=2\\text{H}_2\\text{O}$. Смесь водорода с воздухом (или кислородом) — «гремучий газ» — взрывоопасна, поэтому перед поджиганием водород проверяют на чистоту.
Водород способен отнимать кислород у оксидов металлов: $\\text{H}_2+\\text{CuO}=\\text{Cu}+\\text{H}_2\\text{O}$. Чёрный оксид меди превращается в красную медь. Вещество, отнимающее кислород, называют восстановителем.
')
+ +wgt('Реакции водорода','')
+ +rememberBox(['Водород горит в кислороде → образуется вода.','Смесь $H_2$ с воздухом — гремучий газ, взрывается.','Водород — восстановитель: отнимает кислород у оксидов.'])
+ +qList(['Запиши уравнение горения водорода.','Почему водород называют восстановителем?','Что такое гремучий газ?'])
+ +secNav('p18','p20')+readButton('p19');
+ wireReadBtn('p19');
+}
+
+function build_p20(){
+ document.getElementById('p20-body').innerHTML =
+ '
§ 20 · Химия 7
Понятие о кислотах
'
+ +'
Что такое кислоты и как их обнаруживают индикаторами.
'
+ +'
кислотаиндикатор
'
+ +makeCard('theory','Состав кислот','§20','
Кислоты — сложные вещества, в состав которых входят атомы водорода и кислотный остаток.
'
+ +'
Примеры: соляная $\\text{HCl}$, серная $\\text{H}_2\\text{SO}_4$, азотная $\\text{HNO}_3$, угольная $\\text{H}_2\\text{CO}_3$. Число атомов водорода в кислоте равно валентности кислотного остатка.
')
+ +makeCard('theory','Индикаторы','§20','
Индикаторы — вещества, которые меняют свой цвет в присутствии кислоты. В кислоте лакмус становится красным, а метилоранж — розово-красным. Так кислоту можно обнаружить.
')
+ +wgt('Индикаторы в кислоте','')
+ +wgt('Важнейшие кислоты и их остатки','')
+ +rememberBox(['Кислота = атомы водорода + кислотный остаток.','Лакмус в кислоте — красный, метилоранж — розово-красный.','Индикаторы помогают обнаружить кислоту.'])
+ +qList(['Из чего состоят кислоты?','Как с помощью индикатора обнаружить кислоту?','Назови формулу и название двух кислот.'])
+ +secNav('p19','lo3')+readButton('p20');
+ wireReadBtn('p20');
+}
+
+function build_lo3(){
+ document.getElementById('lo3-body').innerHTML =
+ '
Лабораторный опыт 3
Действие кислот на индикаторы
'
+ +'
Научиться обнаруживать кислоту с помощью индикаторов.
'
+ +makeCard('lab','Ход работы',null,'
В пробирку с раствором кислоты добавь несколько капель лакмуса — он станет красным.
В другую пробирку с кислотой добавь метилоранж — он станет розово-красным.
Сравни с окраской индикаторов в чистой воде.
Сделай вывод, как обнаружить кислоту.
'
+ +'
Кислоты едкие — работай аккуратно, не допускай попадания на кожу и одежду.
')
+ +wgt('Индикаторы в кислоте','')
+ +secNav('p20','p21')+readButton('lo3');
+ wireReadBtn('lo3');
+}
+
+/* заглушки для ещё не наполненных § (следующая волна) */
(function(){
var P = window.PARAS, B = {};
function ph(p, prev, next){
@@ -104,7 +208,7 @@ window.TIPS = [{ sec:'p18', html:'Глава наполняется содерж
'
' + p.num + ' · Химия 7
' + p.name + '
'
+ '
Содержание этого ' + (p.final ? 'раздела' : 'параграфа') + ' готовится.
'
+ makeCard('theory', p.name, p.num,
- '
Скоро здесь появятся теория, наглядные SVG-схемы, молекулярные модели и интерактивные тренажёры по теме «' + p.name + '». Пока доступна навигация по главе' + (p.final ? '.' : ' и отметка о прочтении.') + '
')
+ '
Скоро здесь появятся теория, наглядные SVG-схемы и интерактивные тренажёры по теме «' + p.name + '». Пока доступна навигация по главе' + (p.final ? '.' : ' и отметка о прочтении.') + '