diff --git a/backend/tests/chemistry8-page.test.js b/backend/tests/chemistry8-page.test.js
index 437eed7..3ab7f5c 100644
--- a/backend/tests/chemistry8-page.test.js
+++ b/backend/tests/chemistry8-page.test.js
@@ -117,3 +117,15 @@ test('ch3: нуклид §30 и паспорт §35 монтируются', asy
doc.defaultView.goTo('p35'); await wait(120);
assert.ok(doc.querySelectorAll('#c-passport .pt-cell').length > 80, 'ПСХЭ паспорта §35');
});
+
+/* ── Глава 4 ── */
+test('ch4: SPA без ошибок, 7 карточек, §36 активен, тип связи', async () => {
+ const { doc, errors } = await loadDom('chemistry_8_ch4.html', '/js/chem8_ch4_widgets.js');
+ assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
+ assert.equal(doc.querySelectorAll('#psel-grid .psel-card').length, 7, '6 § + финал');
+ assert.ok(doc.querySelector('.sec.active') && doc.querySelector('.sec.active').id === 'sec-p36', '§36 активен');
+ doc.defaultView.goTo('p37'); await wait(120);
+ assert.ok(doc.querySelector('#c-bond1 .bt-svg'), 'виджет типа связи §37');
+ doc.defaultView.goTo('p38'); await wait(120);
+ assert.ok(doc.querySelector('#c-bond2 .bt-out'), 'виджет полярности §38');
+});
diff --git a/backend/tests/chemistry8.test.js b/backend/tests/chemistry8.test.js
index b105305..7d58d42 100644
--- a/backend/tests/chemistry8.test.js
+++ b/backend/tests/chemistry8.test.js
@@ -113,7 +113,7 @@ test('каждая глава существует, ссылается на ха
const html = fs.readFileSync(path.join(TB, ch.file), 'utf8');
assert.ok(html.includes('/textbook/chemistry-8"'), ch.file + ' ссылка назад в хаб');
assert.ok(html.includes('/js/chem8_svg.js'), ch.file + ' подключает chem8_svg');
- if (['chemistry-8-intro', 'chemistry-8-ch1', 'chemistry-8-ch2', 'chemistry-8-ch3'].includes(ch.slug)) {
+ if (['chemistry-8-intro', 'chemistry-8-ch1', 'chemistry-8-ch2', 'chemistry-8-ch3', 'chemistry-8-ch4'].includes(ch.slug)) {
// перестроены на движок (SPA): slug задаётся через CHEM8_CFG
assert.ok(html.includes("slug:'" + ch.slug + "'"), ch.file + ' slug в CHEM8_CFG');
assert.ok(html.includes('/js/chem8_engine.js'), ch.file + ' подключает движок');
@@ -175,6 +175,17 @@ test('Phase 4 — Глава 3 построена + atomShell/shellConfig кор
assert.equal(C.zSym(17), 'Cl', 'Z=17 → Cl');
});
+test('Phase 5 — Глава 4 построена + bondType корректен', () => {
+ const html = fs.readFileSync(path.join(TB, 'chemistry_8_ch4.html'), 'utf8');
+ for (let i = 36; i <= 41; i++) assert.ok(html.includes('id="sec-p' + i + '"'), '§' + i + ' секция');
+ assert.ok(html.includes('id="c-bond1"'), 'тип связи §37');
+ assert.ok(html.includes('Лабораторный опыт 4'), 'Лаб.4');
+ assert.ok(html.includes('/js/chem8_ch4_widgets.js'), 'виджеты главы 4');
+ assert.equal(C.bondClass('H', 'H').type, 'ковалентная неполярная');
+ assert.equal(C.bondClass('H', 'Cl').type, 'ковалентная полярная');
+ assert.equal(C.bondClass('Na', 'Cl').type, 'ионная');
+});
+
test('chem8_engine.js и виджеты — валидный синтаксис', () => {
const eng = fs.readFileSync(path.join(ROOT, 'frontend', 'js', 'chem8_engine.js'), 'utf8');
const wid = fs.readFileSync(path.join(ROOT, 'frontend', 'js', 'chem8_intro_widgets.js'), 'utf8');
diff --git a/frontend/css/chem8-textbook.css b/frontend/css/chem8-textbook.css
index 847c092..382dd67 100644
--- a/frontend/css/chem8-textbook.css
+++ b/frontend/css/chem8-textbook.css
@@ -376,6 +376,20 @@ html.dark .passport h4{color:var(--pri-l)}
.passport-grid div{padding:6px 9px;background:var(--card);border:1px solid var(--border);border-radius:8px}
.passport-grid b{color:var(--pri-d)}html.dark .passport-grid b{color:var(--pri-l)}
+/* тип связи (§37,38) */
+.bt-svg{width:100%;max-width:280px;height:auto;color:var(--text);display:block;margin:8px auto}
+.bt-stage{display:flex;justify-content:center}
+.bt-out.ok{background:var(--ok-bg);border-color:#86efac}
+.bt-out.bad{background:var(--fail-bg);border-color:#fca5a5}
+
+/* решётки (§41) */
+.lat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin:10px 0}
+.lat-card{border:1.5px solid var(--border);border-radius:12px;padding:13px 15px;background:var(--card-soft)}
+.lat-card h4{font-family:'Outfit';font-weight:800;font-size:.92rem;margin-bottom:6px;color:var(--pri-d)}
+html.dark .lat-card h4{color:var(--pri-l)}
+.lat-card .lat-ex{font-family:var(--mono);font-size:.82rem;color:var(--muted);margin-bottom:4px}
+.lat-card ul{margin:4px 0 0 16px;font-size:.82rem}
+
/* орбитали (§32) — статичные SVG */
.orb-row{display:flex;gap:18px;flex-wrap:wrap;justify-content:center;margin:10px 0}
.orb-item{text-align:center}
diff --git a/frontend/js/chem8_ch4_widgets.js b/frontend/js/chem8_ch4_widgets.js
new file mode 100644
index 0000000..674fb31
--- /dev/null
+++ b/frontend/js/chem8_ch4_widgets.js
@@ -0,0 +1,14 @@
+/* chem8_ch4_widgets.js — виджеты Главы 4 «Химическая связь».
+ * Использует window.Chem8: bondType.
+ */
+(function (W) {
+ 'use strict';
+ function C() { return W.Chem8 || {}; }
+ function $(id) { return document.getElementById(id); }
+
+ function mount_p37() { var el = $('c-bond1'); if (el && !el._b && C().bondType) { el._b = 1; C().bondType(el, { a: 'H', b: 'H' }); } }
+ function mount_p38() { var el = $('c-bond2'); if (el && !el._b && C().bondType) { el._b = 1; C().bondType(el, { a: 'H', b: 'Cl' }); } }
+
+ W.CHEM8_WIDGETS = {};
+ W.FLAG_MOUNTS = { p37: mount_p37, p38: mount_p38 };
+})(window);
diff --git a/frontend/js/chem8_svg.js b/frontend/js/chem8_svg.js
index 60954a9..daba5d3 100644
--- a/frontend/js/chem8_svg.js
+++ b/frontend/js/chem8_svg.js
@@ -690,6 +690,63 @@
return { el: host, draw: draw };
}
+ /* ──────────────────────────────────────────────────────────────────────────
+ Химическая связь (Phase 5).
+ EN — электроотрицательность (Полинг, школьные значения). bondClass(da,db)
+ по разнице ЭО → тип связи. bondType(mount) — интерактивный виджет.
+ ────────────────────────────────────────────────────────────────────────── */
+ var EN = {
+ H:2.1, Li:1.0, Be:1.5, B:2.0, C:2.5, N:3.0, O:3.5, F:4.0,
+ Na:0.9, Mg:1.2, Al:1.5, Si:1.8, P:2.1, S:2.5, Cl:3.0,
+ K:0.8, Ca:1.0, Br:2.8, I:2.5, Zn:1.6, Fe:1.8, Cu:1.9, Ag:1.9
+ };
+ function enOf(sym) { return EN[sym] != null ? EN[sym] : 2.0; }
+ function bondClass(a, b) {
+ var d = Math.abs(enOf(a) - enOf(b));
+ if (a !== b && (a in EN) && (b in EN) && enOf(a) <= 1.6 && enOf(b) <= 1.6) {
+ // два металла → металлическая
+ if (METALS_EN[a] && METALS_EN[b]) return { type: 'металлическая', cls: 'warn', d: d };
+ }
+ if (d >= 1.7) return { type: 'ионная', cls: 'bad', d: d };
+ if (d < 0.4) return { type: 'ковалентная неполярная', cls: 'good', d: d };
+ return { type: 'ковалентная полярная', cls: 'mid', d: d };
+ }
+ var METALS_EN = { Li:1, Be:1, Na:1, Mg:1, Al:1, K:1, Ca:1, Zn:1, Fe:1, Cu:1, Ag:1 };
+
+ function bondType(mount, opts) {
+ var host = typeof mount === 'string' ? global.document.querySelector(mount) : mount;
+ if (!host) return null;
+ opts = opts || {};
+ var syms = Object.keys(EN);
+ function optList(sel) { return syms.map(function (s) { return '' + s + ' (ЭО ' + enOf(s) + ') '; }).join(''); }
+ host.innerHTML = '
Атом A ' + optList(opts.a || 'H') + ' '
+ + 'Атом B ' + optList(opts.b || 'Cl') + '
'
+ + '
';
+ var sa = host.querySelector('.bt-a'), sb = host.querySelector('.bt-b'), stage = host.querySelector('.bt-stage'), out = host.querySelector('.bt-out');
+ function upd() {
+ var a = sa.value, b = sb.value, r = bondClass(a, b), d = Math.round(r.d * 10) / 10;
+ // δ-заряды: более ЭО атом — δ−
+ var aMore = enOf(a) > enOf(b), polar = r.type.indexOf('полярная') >= 0;
+ var da = (r.type === 'ионная') ? (aMore ? '−' : '+') : (polar ? (aMore ? 'δ−' : 'δ+') : '');
+ var db = (r.type === 'ионная') ? (aMore ? '+' : '−') : (polar ? (aMore ? 'δ+' : 'δ−') : '');
+ var color = r.cls === 'good' ? 'var(--ok)' : r.cls === 'bad' ? 'var(--fail)' : 'var(--pri)';
+ stage.innerHTML = ''
+ + ' '
+ + ' '
+ + ' '
+ + '' + a + ' '
+ + '' + b + ' '
+ + (da ? '' + da + ' ' : '')
+ + (db ? '' + db + ' ' : '')
+ + ' ';
+ out.className = 'out bt-out ' + (r.cls === 'good' ? 'ok' : r.cls === 'bad' ? 'bad' : '');
+ out.innerHTML = 'ΔЭО = |' + enOf(a) + ' − ' + enOf(b) + '| = ' + d + ' → связь ' + r.type + ' '
+ + (r.type === 'ионная' ? ' Электрон полностью переходит к более электроотрицательному атому.' : polar ? ' Общая пара смещена к более электроотрицательному атому (' + (aMore ? a : b) + ').' : r.type.indexOf('металл') >= 0 ? ' Общие электроны принадлежат всем атомам («электронный газ»).' : ' Общая пара поделена поровну.') + ' ';
+ }
+ sa.addEventListener('change', upd); sb.addEventListener('change', upd); upd();
+ return { el: host, update: upd };
+ }
+
/* ---- Каркасы-заглушки интерактивных виджетов (реализуются по фазам) ---- */
function notImplemented(name) {
return function () {
@@ -727,6 +784,10 @@
shellConfig: shellConfig, // распределение электронов по слоям
nuclide: nuclide, // §30 — A=Z+N, нуклид
zSym: zSym, // Z → символ элемента
+ // готово (Phase 5 — химическая связь)
+ bondType: bondType, // §37,38 — ЭО → тип связи
+ bondClass: bondClass, // классификация связи по ΔЭО
+ enOf: enOf, // электроотрицательность
// заглушки (см. план, разд. B) — наполняются в Phase 5–6
oxStateCalc: notImplemented('oxStateCalc'), // §42 — калькулятор степени окисления
redoxBalancer: notImplemented('redoxBalancer'), // §44 — e-баланс ОВР
diff --git a/frontend/textbooks/chemistry_8_ch4.html b/frontend/textbooks/chemistry_8_ch4.html
index dc242c9..193ff96 100644
--- a/frontend/textbooks/chemistry_8_ch4.html
+++ b/frontend/textbooks/chemistry_8_ch4.html
@@ -7,130 +7,214 @@
Химия 8 · Глава 4 · «Химическая связь»
-
+
+
+
-
+
+
-
-
-
- К разделам
-
+
-
Глава 4 · § 36–41
-
Химическая связь
+
Химия 8 · Глава 4
+
Природа связи, ковалентная (полярная и неполярная), ионная и металлическая связь, кристаллические решётки
-
-
-
-
-
Раздел в разработке
-
Интерактивное наглядное наполнение этого раздела (теория, модели, симуляторы, тренажёры и боссы) добавляется поэтапно. Ниже — план параграфов раздела согласно учебнику.
-
-
+
+
+
+ Почему атомы держатся вместе
+ Атомы соединяются, чтобы завершить внешний электронный слой и стать устойчивее. В зависимости от того, как именно они «делят» электроны, возникают разные типы химической связи — а от них зависят свойства веществ.
+
+
-
-
- Содержание раздела
+
+
+
+
+
+
+
+
+
-
- § 36 Природа химической связи
- § 37 Ковалентная связь
- § 38 Неполярная и полярная ковалентная связь. Электроотрицательность
- Лабораторный опыт 4. Составление моделей молекул
- § 39 Ионная связь
- § 40 Металлическая связь. Межмолекулярное взаимодействие
- § 41 Кристаллическое состояние вещества
-
+
-
+
+