diff --git a/backend/scripts/gen_phys7_ch.js b/backend/scripts/gen_phys7_ch.js
new file mode 100644
index 0000000..c58b12f
--- /dev/null
+++ b/backend/scripts/gen_phys7_ch.js
@@ -0,0 +1,457 @@
+#!/usr/bin/env node
+// Генератор скелетов глав Физики 7. Создаёт physics_7_ch1..ch5.html из единого шаблона.
+// Phase 0: скелет с инфраструктурой (header, navigator, sidebar, KaTeX, прогресс/XP, goTo),
+// без §-контента — наполняется в Phase 1+.
+
+const fs = require('fs');
+const path = require('path');
+
+const VER = '20260530';
+const OUT = path.join(__dirname, '..', '..', 'frontend', 'textbooks');
+
+const CHAPTERS = [
+ {
+ n: 1, slug: 'physics-7-ch1',
+ title: 'Физические методы познания природы',
+ range: '§§1–7',
+ accent: '#4f46e5', accentD: '#3730a3', accentSoft: '#e0e7ff',
+ coverGrad: 'linear-gradient(135deg,#312e81,#4f46e5 60%,#a5b4fc)',
+ paras: [
+ { id:'p1', num:'§ 1', title:'Физика — наука о природе', wm:'?' },
+ { id:'p2', num:'§ 2', title:'Тело, явление, величина', wm:'×' },
+ { id:'p3', num:'§ 3', title:'Методы исследования в физике', wm:'⚙' },
+ { id:'p4', num:'§ 4', title:'Прямые и косвенные измерения', wm:'=' },
+ { id:'p5', num:'§ 5', title:'Единицы измерения. СИ', wm:'м' },
+ { id:'p6', num:'§ 6', title:'Действия над физическими величинами', wm:'±' },
+ { id:'p7', num:'§ 7', title:'Цена деления. Погрешность', wm:'∇' },
+ { id:'final1', num:'Финал', title:'Итоги главы 1', wm:'★' },
+ ],
+ achTitle: 'Юный физик',
+ },
+ {
+ n: 2, slug: 'physics-7-ch2',
+ title: 'Строение вещества',
+ range: '§§8–13',
+ accent: '#7c3aed', accentD: '#5b21b6', accentSoft: '#ede9fe',
+ coverGrad: 'linear-gradient(135deg,#4c1d95,#7c3aed 60%,#c4b5fd)',
+ paras: [
+ { id:'p8', num:'§ 8', title:'Дискретное строение вещества', wm:'•' },
+ { id:'p9', num:'§ 9', title:'Тепловое движение частиц', wm:'~' },
+ { id:'p10', num:'§ 10', title:'Взаимодействие частиц', wm:'⇌' },
+ { id:'p11', num:'§ 11', title:'Газ, жидкость, твёрдое', wm:'△' },
+ { id:'p12', num:'§ 12', title:'Тепловое расширение', wm:'↔' },
+ { id:'p13', num:'§ 13', title:'Температура. Термометры', wm:'°' },
+ { id:'final2', num:'Финал', title:'Итоги главы 2', wm:'★' },
+ ],
+ achTitle: 'Знаток вещества',
+ },
+ {
+ n: 3, slug: 'physics-7-ch3',
+ title: 'Движение и силы',
+ range: '§§14–27',
+ accent: '#dc2626', accentD: '#991b1b', accentSoft: '#fee2e2',
+ coverGrad: 'linear-gradient(135deg,#7f1d1d,#dc2626 60%,#f87171)',
+ paras: [
+ { id:'p14', num:'§ 14', title:'Механическое движение. Относительность', wm:'→' },
+ { id:'p15', num:'§ 15', title:'Траектория, путь, время', wm:'s' },
+ { id:'p16', num:'§ 16', title:'Равномерное движение. Скорость', wm:'v' },
+ { id:'p17', num:'§ 17', title:'Графики s(t) и v(t)', wm:'∠' },
+ { id:'p18', num:'§ 18', title:'Средняя скорость', wm:'⟨⟩' },
+ { id:'p19', num:'§ 19', title:'Инерция', wm:'∞' },
+ { id:'p20', num:'§ 20', title:'Масса. Плотность', wm:'ρ' },
+ { id:'p21', num:'§ 21', title:'Сила', wm:'F' },
+ { id:'p22', num:'§ 22', title:'Сила тяжести', wm:'↓' },
+ { id:'p23', num:'§ 23', title:'Сила упругости', wm:'≈' },
+ { id:'p24', num:'§ 24', title:'Вес тела', wm:'P' },
+ { id:'p25', num:'§ 25', title:'Динамометр', wm:'⊥' },
+ { id:'p26', num:'§ 26', title:'Сложение сил', wm:'+' },
+ { id:'p27', num:'§ 27', title:'Сила трения', wm:'~' },
+ { id:'final3', num:'Финал', title:'Итоги главы 3', wm:'★' },
+ ],
+ achTitle: 'Мастер движения',
+ },
+ {
+ n: 4, slug: 'physics-7-ch4',
+ title: 'Давление',
+ range: '§§28–35',
+ accent: '#d97706', accentD: '#92400e', accentSoft: '#fef3c7',
+ coverGrad: 'linear-gradient(135deg,#78350f,#d97706 60%,#fbbf24)',
+ paras: [
+ { id:'p28', num:'§ 28', title:'Давление. Единицы давления', wm:'p' },
+ { id:'p29', num:'§ 29', title:'Давление газа', wm:'∴' },
+ { id:'p30', num:'§ 30', title:'Закон Паскаля', wm:'⊕' },
+ { id:'p31', num:'§ 31', title:'Гидростатическое давление', wm:'≡' },
+ { id:'p32', num:'§ 32', title:'Сообщающиеся сосуды', wm:'U' },
+ { id:'p33', num:'§ 33', title:'Газы и их вес', wm:'⌒' },
+ { id:'p34', num:'§ 34', title:'Атмосферное давление', wm:'∼' },
+ { id:'p35', num:'§ 35', title:'Барометры и манометры', wm:'⏚' },
+ { id:'final4', num:'Финал', title:'Итоги главы 4', wm:'★' },
+ ],
+ achTitle: 'Властелин давления',
+ },
+ {
+ n: 5, slug: 'physics-7-ch5',
+ title: 'Работа. Мощность. Энергия',
+ range: '§§36–42',
+ accent: '#10b981', accentD: '#047857', accentSoft: '#d1fae5',
+ coverGrad: 'linear-gradient(135deg,#064e3b,#10b981 60%,#6ee7b7)',
+ paras: [
+ { id:'p36', num:'§ 36', title:'Механическая работа', wm:'A' },
+ { id:'p37', num:'§ 37', title:'КПД', wm:'η' },
+ { id:'p38', num:'§ 38', title:'Мощность', wm:'P' },
+ { id:'p39', num:'§ 39', title:'Кинетическая энергия',wm:'Eк' },
+ { id:'p40', num:'§ 40', title:'Потенциальная энергия',wm:'Eп' },
+ { id:'p41', num:'§ 41', title:'Расчёт Eп = mgh', wm:'h' },
+ { id:'p42', num:'§ 42', title:'Закон сохранения энергии',wm:'∑' },
+ { id:'final5', num:'Финал', title:'Итоги главы 5', wm:'★' },
+ ],
+ achTitle: 'Энергетик',
+ },
+];
+
+function makeHTML(C) {
+ const parasJs = C.paras.map(p => `{id:'${p.id}',num:'${p.num}',title:${JSON.stringify(p.title)},wm:'${p.wm}'}`).join(',');
+ const sections = C.paras.map(p =>
+ `
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+ `).join('\n');
+
+ return `
+
+
+
+
+
+
+Физика 7 · Глава ${C.n} · ${C.title}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Глава ${C.n}
+
${C.title} · ${C.range}
+
+
+
+
+
+
+
+
+
Параграфы главы ${C.n}
+
+
+
+${sections}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+}
+
+CHAPTERS.forEach(C => {
+ const html = makeHTML(C);
+ const file = path.join(OUT, `physics_7_ch${C.n}.html`);
+ fs.writeFileSync(file, html, 'utf8');
+ console.log(`[gen_phys7_ch] ${file} — ${html.split('\n').length} lines`);
+});
+console.log('Done.');
diff --git a/backend/scripts/gen_phys7_lab.js b/backend/scripts/gen_phys7_lab.js
new file mode 100644
index 0000000..d473e25
--- /dev/null
+++ b/backend/scripts/gen_phys7_lab.js
@@ -0,0 +1,291 @@
+#!/usr/bin/env node
+// Генератор скелета лабораторного практикума Физики 7. Phase 0: только инфраструктура.
+
+const fs = require('fs');
+const path = require('path');
+
+const VER = '20260530';
+const OUT = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_7_lab.html');
+
+const LABS = [
+ { id:'lr1', num:'ЛР 1', title:'Определение цены деления шкалы измерительного прибора', wm:'1', tag:'§ 7' },
+ { id:'lr2', num:'ЛР 2', title:'Измерение длины', wm:'2', tag:'§ 4 · § 7' },
+ { id:'lr3', num:'ЛР 3', title:'Измерение объёма', wm:'3', tag:'§ 4' },
+ { id:'lr4', num:'ЛР 4', title:'Изучение неравномерного движения', wm:'4', tag:'§ 18' },
+ { id:'lr5', num:'ЛР 5', title:'Измерение плотности вещества', wm:'5', tag:'§ 20' },
+ { id:'lr6', num:'ЛР 6', title:'Изучение силы трения', wm:'6', tag:'§ 27' },
+];
+
+const labsJs = LABS.map(l => `{id:'${l.id}',num:'${l.num}',title:${JSON.stringify(l.title)},wm:'${l.wm}',tag:'${l.tag}'}`).join(',');
+const sections = LABS.map(l =>
+ `
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+ `).join('\n');
+
+const html = `
+
+
+
+
+
+
+Физика 7 · Лабораторный практикум
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Лабораторный практикум
+
6 виртуальных лабораторных работ
+
+
+
+
+
+
+
+
+
Лабораторные работы
+
+
+
+${sections}
+
+
+
+
+
+
+
+
+
+
+
+
+
+`;
+
+fs.writeFileSync(OUT, html, 'utf8');
+console.log(`[gen_phys7_lab] ${OUT} — ${html.split('\n').length} lines`);
diff --git a/backend/src/db/migrations/039_physics_7_hub.sql b/backend/src/db/migrations/039_physics_7_hub.sql
new file mode 100644
index 0000000..9d8c800
--- /dev/null
+++ b/backend/src/db/migrations/039_physics_7_hub.sql
@@ -0,0 +1,60 @@
+-- Physics 7 hub migration (self-sufficient).
+-- Creates physics-7 as a full 5-chapter + lab textbook in the style of physics-8/9/10:
+-- physics-7 (hub, html_path = physics_7_hub.html)
+-- physics-7-ch1 (Физические методы познания природы, §§1–7) → physics_7_ch1.html
+-- physics-7-ch2 (Строение вещества, §§8–13) → physics_7_ch2.html
+-- physics-7-ch3 (Движение и силы, §§14–27) → physics_7_ch3.html
+-- physics-7-ch4 (Давление, §§28–35) → physics_7_ch4.html
+-- physics-7-ch5 (Работа. Мощность. Энергия, §§36–42) → physics_7_ch5.html
+-- physics-7-lab (Лабораторный практикум, 6 ЛР) → physics_7_lab.html
+--
+-- This migration is the single source of truth for physics-7 textbook structure.
+-- It is idempotent and does not depend on any prior physics-7 migration.
+
+-- 1. Ensure the parent physics-7 hub row exists.
+INSERT OR IGNORE INTO textbooks
+ (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active)
+VALUES
+ ('physics-7', 'physics', 7, 'Физика — 7 класс',
+ '',
+ 'Первый курс физики: методы познания, строение вещества, движение и силы, давление, работа/мощность/энергия. 42 параграфа в 5 главах + 6 виртуальных лабораторных работ.',
+ 'physics_7_hub.html', 48, 'sky', 3, 1);
+
+-- 2. Update the parent physics-7 hub row (idempotent on re-runs).
+UPDATE textbooks
+SET
+ author = '',
+ para_count = 48,
+ html_path = 'physics_7_hub.html',
+ description = 'Первый курс физики: методы познания, строение вещества, движение и силы, давление, работа/мощность/энергия. 42 параграфа в 5 главах + 6 виртуальных лабораторных работ.',
+ color = 'sky'
+WHERE slug = 'physics-7';
+
+-- 3. Insert the 6 children (5 chapters + lab).
+INSERT INTO textbooks
+ (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active, parent_slug)
+VALUES
+ ('physics-7-ch1', 'physics', 7, 'Физика 7 · Физические методы познания природы',
+ '',
+ '§§1–7: физика как наука, физическое тело и явление, методы исследования, измерения, СИ, цена деления, погрешность.',
+ 'physics_7_ch1.html', 7, 'sky', 1, 1, 'physics-7'),
+ ('physics-7-ch2', 'physics', 7, 'Физика 7 · Строение вещества',
+ '',
+ '§§8–13: дискретное строение, тепловое движение, взаимодействие частиц, три состояния, тепловое расширение, термометр.',
+ 'physics_7_ch2.html', 6, 'indigo', 2, 1, 'physics-7'),
+ ('physics-7-ch3', 'physics', 7, 'Физика 7 · Движение и силы',
+ '',
+ '§§14–27: механическое движение, равномерное и неравномерное, плотность, силы тяжести/упругости/трения, динамометр, равнодействующая.',
+ 'physics_7_ch3.html', 14, 'red', 3, 1, 'physics-7'),
+ ('physics-7-ch4', 'physics', 7, 'Физика 7 · Давление',
+ '',
+ '§§28–35: давление, закон Паскаля, гидравлический пресс, гидростатика, сообщающиеся сосуды, атмосферное давление, барометры.',
+ 'physics_7_ch4.html', 8, 'amber', 4, 1, 'physics-7'),
+ ('physics-7-ch5', 'physics', 7, 'Физика 7 · Работа. Мощность. Энергия',
+ '',
+ '§§36–42: механическая работа, КПД, мощность, кинетическая и потенциальная энергия, закон сохранения механической энергии.',
+ 'physics_7_ch5.html', 7, 'emerald', 5, 1, 'physics-7'),
+ ('physics-7-lab', 'physics', 7, 'Физика 7 · Лабораторный практикум',
+ '',
+ '6 виртуальных лабораторных работ: цена деления, измерение длины, объёма, неравномерное движение, плотность, сила трения.',
+ 'physics_7_lab.html', 6, 'cyan', 6, 1, 'physics-7');
diff --git a/frontend/js/phys.js b/frontend/js/phys.js
index 098ca3e..822f64b 100644
--- a/frontend/js/phys.js
+++ b/frontend/js/phys.js
@@ -443,6 +443,319 @@ function Rparallel() {
return inv > 0 ? 1 / inv : Infinity;
}
+// ======================================================================
+// PHYSICS 7 HELPERS — силы, давление, гидростатика, барометры, энергия.
+// Все размеры в SVG-пикселях; физические величины в СИ.
+// ======================================================================
+
+function forceVector(x, y, F, angleDeg, color, label, scale) {
+ scale = scale || 1.5;
+ const a = -angleDeg * Math.PI / 180;
+ const x2 = x + F * scale * Math.cos(a);
+ const y2 = y + F * scale * Math.sin(a);
+ let s = drawArrow(x, y, x2, y2, color || '#0f172a', 2.5, 9);
+ if (label) {
+ const lx = x2 + 8 * Math.cos(a);
+ const ly = y2 + 8 * Math.sin(a) + 4;
+ s += `${label}`;
+ }
+ return s;
+}
+
+function dynamometer(x, y, h, Fmax, Fcurr) {
+ const w = 30;
+ const springTop = y + 14, springBot = y + h - 28;
+ const stretch = Math.max(0, Math.min(1, Fcurr / Fmax)) * (springBot - springTop);
+ const pointerY = springTop + stretch;
+ let s = ``;
+ const coils = 8;
+ const coilH = (pointerY - springTop) / coils;
+ let path = `M ${x + w/2} ${springTop}`;
+ for (let i = 0; i < coils; i++) {
+ path += ` L ${x + (i%2 ? w-6 : 6)} ${springTop + (i+0.5)*coilH}`;
+ }
+ path += ` L ${x + w/2} ${pointerY}`;
+ s += ``;
+ const ticks = 10;
+ for (let i = 0; i <= ticks; i++) {
+ const ty = springTop + (springBot - springTop) * i / ticks;
+ s += ``;
+ if (i % 2 === 0) {
+ s += `${(Fmax * i / ticks).toFixed(Fmax < 5 ? 1 : 0)}`;
+ }
+ }
+ s += ``;
+ s += ``;
+ s += `F = ${Fcurr.toFixed(1)} Н`;
+ return s;
+}
+
+function blockOnSurface(x, y, w, h, label, weights) {
+ let s = ``;
+ if (label) s += `${label}`;
+ if (weights && weights > 0) {
+ const wH = 10, wW = w * 0.7;
+ for (let i = 0; i < weights; i++) {
+ const wy = y - (i + 1) * (wH + 2);
+ s += ``;
+ }
+ }
+ return s;
+}
+
+function connectedVessels(x, y, kindA, kindB, levelY, fluidColor) {
+ fluidColor = fluidColor || '#60a5fa';
+ const widths = { cylinder: 60, wide: 100, narrow: 35 };
+ const wA = widths[kindA] || 60, wB = widths[kindB] || 60;
+ const h = 140, gap = 50;
+ const xA = x, xB = x + wA + gap;
+ let s = '';
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ const fillH = (y + h) - levelY;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ return s;
+}
+
+function hydraulicPress(x, y, sSmall, sLarge, fSmall, fluidColor) {
+ fluidColor = fluidColor || '#60a5fa';
+ const fLarge = fSmall * sLarge / sSmall;
+ const scale = 6;
+ const wSmall = Math.max(20, Math.sqrt(sSmall) * scale);
+ const wLarge = Math.max(40, Math.sqrt(sLarge) * scale);
+ const cylH = 60, baseY = y + 110, gap = 40;
+ const xS = x, xL = x + wSmall + gap;
+ let s = '';
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += drawArrow(xS + wSmall/2, y + 20, xS + wSmall/2, y + 40, '#dc2626', 2.5, 8);
+ s += drawArrow(xL + wLarge/2, y + 20, xL + wLarge/2, y + 40, '#10b981', 2.5, 8);
+ s += `F_1 = ${fSmall.toFixed(0)} Н`;
+ s += `F_2 = ${fLarge.toFixed(0)} Н`;
+ s += `S_1 = ${sSmall} см²`;
+ s += `S_2 = ${sLarge} см²`;
+ return s;
+}
+
+function mercuryBarometer(x, y, hMm) {
+ hMm = hMm == null ? 760 : hMm;
+ const maxMm = 800, scale = 0.4;
+ const tubeH = maxMm * scale, tubeW = 14;
+ const cupY = y + tubeH + 10, cupW = 70, cupH = 26;
+ const colH = hMm * scale, colTop = y + tubeH - colH;
+ let s = '';
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ s += `вакуум`;
+ for (let mm = 0; mm <= maxMm; mm += 50) {
+ const ty = y + tubeH - mm * scale;
+ s += ``;
+ if (mm % 100 === 0) s += `${mm}`;
+ }
+ s += ``;
+ s += `${hMm} мм`;
+ return s;
+}
+
+function aneroidBarometer(cx, cy, r, pressurePa) {
+ const pMm = pressurePa / 133.322;
+ const pMin = 720, pMax = 800;
+ const angDeg = -210 + 240 * Math.max(0, Math.min(1, (pMm - pMin) / (pMax - pMin)));
+ const angRad = angDeg * Math.PI / 180;
+ let s = '';
+ s += ``;
+ s += ``;
+ for (let p = pMin; p <= pMax; p += 10) {
+ const a = (-210 + 240 * (p - pMin) / (pMax - pMin)) * Math.PI / 180;
+ const r1 = r - 4, r2 = r - 12;
+ const x1 = cx + r1 * Math.cos(a), y1 = cy + r1 * Math.sin(a);
+ const x2 = cx + r2 * Math.cos(a), y2 = cy + r2 * Math.sin(a);
+ s += ``;
+ if (p % 20 === 0) {
+ const rT = r - 22;
+ const xT = cx + rT * Math.cos(a), yT = cy + rT * Math.sin(a) + 3;
+ s += `${p}`;
+ }
+ }
+ const tipX = cx + (r - 18) * Math.cos(angRad), tipY = cy + (r - 18) * Math.sin(angRad);
+ s += ``;
+ s += ``;
+ s += `${pMm.toFixed(0)} мм рт. ст.`;
+ return s;
+}
+
+function uManometer(x, y, w, h, deltaH, fluidColor) {
+ fluidColor = fluidColor || '#0891b2';
+ const tube = 14;
+ const xL = x, xR = x + w - tube;
+ const baseY = y + h;
+ let s = ``;
+ s += ``;
+ s += ``;
+ const lLevel = y + h * 0.45 + deltaH / 2;
+ const rLevel = y + h * 0.45 - deltaH / 2;
+ s += ``;
+ s += ``;
+ if (Math.abs(deltaH) > 1) {
+ s += ``;
+ s += `Δh`;
+ }
+ return s;
+}
+
+function rulerWithError(x, y, lenCm, mmPerDiv) {
+ mmPerDiv = mmPerDiv || 1;
+ const pxPerCm = 30;
+ const w = lenCm * pxPerCm, h = 28;
+ let s = ``;
+ const totalDivs = (lenCm * 10) / mmPerDiv;
+ for (let i = 0; i <= totalDivs; i++) {
+ const tx = x + (i * mmPerDiv / 10) * pxPerCm;
+ const mm = i * mmPerDiv;
+ const isCm = mm % 10 === 0, isHalfCm = mm % 5 === 0;
+ const tickH = isCm ? 12 : (isHalfCm ? 8 : 5);
+ s += ``;
+ if (isCm) s += `${mm/10}`;
+ }
+ s += `см`;
+ return s;
+}
+
+function bimetal(x, y, w, h, deltaT) {
+ const ang = Math.max(-30, Math.min(30, deltaT * 0.3));
+ let s = ``;
+ s += ``;
+ s += ``;
+ s += `ΔT = ${deltaT.toFixed(0)} °C`;
+ s += ``;
+ return s;
+}
+
+function expandingRod(x, y, l0, alpha, deltaT) {
+ const dl = l0 * alpha * deltaT * 1000;
+ const len = l0 + dl;
+ const h = 16;
+ const color = tempColor(deltaT, 0, 100);
+ let s = ``;
+ s += ``;
+ if (dl > 1) {
+ s += drawArrow(x + l0, y + h + 14, x + len, y + h + 14, '#dc2626', 1.8, 6);
+ s += `Δl = ${dl.toFixed(1)} px`;
+ }
+ return s;
+}
+
+// === HillSlideSim — тележка скатывается с горки (для §42, закон сохранения) ===
+class HillSlideSim {
+ constructor(opts) {
+ opts = opts || {};
+ this.x0 = opts.x0 || 30;
+ this.y0 = opts.y0 || 200;
+ this.hStart = opts.hStart != null ? opts.hStart : 5;
+ this.m = opts.mass || 1;
+ this.g = opts.g || 9.8;
+ this.friction = opts.friction || 0;
+ this.scale = opts.scale || 30;
+ this.reset();
+ }
+ reset() { this.t = 0; this.x = 0; this.v = 0; this.h = this.hStart; }
+ step(dt) {
+ const gEff = this.g * (1 - this.friction);
+ this.t += dt;
+ const dropped = this.hStart - this.h;
+ if (this.h <= 0) { this.h = 0; this.v = Math.sqrt(2 * gEff * this.hStart); return; }
+ this.v = Math.sqrt(2 * gEff * Math.max(0, dropped));
+ this.x += this.v * dt;
+ const L = this.hStart * 4;
+ const xRel = Math.min(this.x, L) / L;
+ this.h = this.hStart * Math.pow(1 - xRel, 2);
+ }
+ getEnergies() {
+ return {
+ Ek: 0.5 * this.m * this.v * this.v,
+ Ep: this.m * this.g * this.h,
+ Etot: 0.5 * this.m * this.v * this.v + this.m * this.g * this.h
+ };
+ }
+ renderProfile() {
+ const L = this.hStart * 4;
+ const pxL = L * this.scale, pxH = this.hStart * this.scale;
+ const baseY = this.y0;
+ let path = `M ${this.x0} ${baseY - pxH}`;
+ const N = 40;
+ for (let i = 1; i <= N; i++) {
+ const xRel = i / N;
+ const yRel = Math.pow(1 - xRel, 2);
+ path += ` L ${(this.x0 + pxL * xRel).toFixed(1)} ${(baseY - pxH * yRel).toFixed(1)}`;
+ }
+ let s = '';
+ s += ``;
+ s += ``;
+ const cartX = this.x0 + this.x * this.scale;
+ const cartY = baseY - this.h * this.scale;
+ s += ``;
+ s += ``;
+ s += ``;
+ return s;
+ }
+}
+
+// === PendulumSim — математический маятник (для §42) ===
+class PendulumSim {
+ constructor(opts) {
+ opts = opts || {};
+ this.cx = opts.cx || 150;
+ this.cy = opts.cy || 40;
+ this.L = opts.length || 1.2;
+ this.m = opts.mass || 0.5;
+ this.g = opts.g || 9.8;
+ this.phi0 = (opts.angleDeg || 25) * Math.PI / 180;
+ this.scale = opts.scale || 80;
+ this.reset();
+ }
+ reset() { this.t = 0; this.phi = this.phi0; this.omega = 0; }
+ step(dt) {
+ const alpha = -(this.g / this.L) * Math.sin(this.phi);
+ this.omega += alpha * dt;
+ this.phi += this.omega * dt;
+ this.t += dt;
+ }
+ getEnergies() {
+ const h = this.L * (1 - Math.cos(this.phi));
+ const v = Math.abs(this.omega) * this.L;
+ return {
+ Ek: 0.5 * this.m * v * v,
+ Ep: this.m * this.g * h,
+ Etot: 0.5 * this.m * v * v + this.m * this.g * h
+ };
+ }
+ render() {
+ const pxL = this.L * this.scale;
+ const bx = this.cx + pxL * Math.sin(this.phi);
+ const by = this.cy + pxL * Math.cos(this.phi);
+ let s = '';
+ s += ``;
+ s += ``;
+ s += ``;
+ s += ``;
+ return s;
+ }
+}
+
// === Экспорт ===
window.PHYS = {
tempColor: tempColor,
@@ -473,6 +786,20 @@ window.PHYS = {
atmToPa: atmToPa,
paToAtm: paToAtm,
litersToM3: litersToM3,
- m3ToLiters: m3ToLiters
+ m3ToLiters: m3ToLiters,
+ // Physics 7 — Phase 0
+ forceVector: forceVector,
+ dynamometer: dynamometer,
+ blockOnSurface: blockOnSurface,
+ connectedVessels: connectedVessels,
+ hydraulicPress: hydraulicPress,
+ mercuryBarometer: mercuryBarometer,
+ aneroidBarometer: aneroidBarometer,
+ uManometer: uManometer,
+ rulerWithError: rulerWithError,
+ bimetal: bimetal,
+ expandingRod: expandingRod,
+ HillSlideSim: HillSlideSim,
+ PendulumSim: PendulumSim
};
})();
diff --git a/frontend/textbooks/physics_7_ch1.html b/frontend/textbooks/physics_7_ch1.html
new file mode 100644
index 0000000..a1eb8e9
--- /dev/null
+++ b/frontend/textbooks/physics_7_ch1.html
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+Физика 7 · Глава 1 · Физические методы познания природы
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Глава 1
+
Физические методы познания природы · §§1–7
+
+
+
+
+
+
+
+
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/textbooks/physics_7_ch2.html b/frontend/textbooks/physics_7_ch2.html
new file mode 100644
index 0000000..c98d83a
--- /dev/null
+++ b/frontend/textbooks/physics_7_ch2.html
@@ -0,0 +1,355 @@
+
+
+
+
+
+
+
+Физика 7 · Глава 2 · Строение вещества
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Глава 2
+
Строение вещества · §§8–13
+
+
+
+
+
+
+
+
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/textbooks/physics_7_ch3.html b/frontend/textbooks/physics_7_ch3.html
new file mode 100644
index 0000000..5f57d87
--- /dev/null
+++ b/frontend/textbooks/physics_7_ch3.html
@@ -0,0 +1,387 @@
+
+
+
+
+
+
+
+Физика 7 · Глава 3 · Движение и силы
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Глава 3
+
Движение и силы · §§14–27
+
+
+
+
+
+
+
+
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/textbooks/physics_7_ch4.html b/frontend/textbooks/physics_7_ch4.html
new file mode 100644
index 0000000..a01fa4c
--- /dev/null
+++ b/frontend/textbooks/physics_7_ch4.html
@@ -0,0 +1,363 @@
+
+
+
+
+
+
+
+Физика 7 · Глава 4 · Давление
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Глава 4
+
Давление · §§28–35
+
+
+
+
+
+
+
+
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/textbooks/physics_7_ch5.html b/frontend/textbooks/physics_7_ch5.html
new file mode 100644
index 0000000..193721d
--- /dev/null
+++ b/frontend/textbooks/physics_7_ch5.html
@@ -0,0 +1,359 @@
+
+
+
+
+
+
+
+Физика 7 · Глава 5 · Работа. Мощность. Энергия
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Глава 5
+
Работа. Мощность. Энергия · §§36–42
+
+
+
+
+
+
+
+
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+ Содержимое параграфа появится в одной из ближайших фаз разработки.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/textbooks/physics_7_hub.html b/frontend/textbooks/physics_7_hub.html
new file mode 100644
index 0000000..3644392
--- /dev/null
+++ b/frontend/textbooks/physics_7_hub.html
@@ -0,0 +1,946 @@
+
+
+
+
+
+
+
+
+Физика 7 класс — учебник
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика — 7 класс
+
Первый курс физики: методы познания природы, строение вещества, движение и силы, давление, работа и энергия, лабораторный практикум
+
+
+
+
+
+
+
+
+ f
+
+
Общий прогресс по курсу
+
Загрузка...
+
+
+ 0 XP
+
+
+
+
+
+
+
Σ
+
Глава 1
+
Методы познания природы
+
§1–§7 + Финал
+
+
+
Физика как наука. Тело, явление, величина. Методы исследования. Прямые и косвенные измерения. СИ. Цена деления. Погрешность.
+
+
+
+
+
+
+
+
°
+
Глава 2
+
Строение вещества
+
§8–§13 + Финал
+
+
+
Дискретное строение. Тепловое движение. Взаимодействие частиц. Три состояния вещества. Тепловое расширение. Температура и термометры.
+
+
+
+
+
+
+
+
F
+
Глава 3
+
Движение и силы
+
§14–§27 + Финал
+
+
+
Механическое движение. Равномерное и неравномерное движение. Скорость. Масса. Плотность. Силы тяжести, упругости, трения. Динамометр. Равнодействующая.
+
+
+
+
+
+
+
+
P
+
Глава 4
+
Давление
+
§28–§35 + Финал
+
+
+
Давление твёрдых тел, газов, жидкостей. Закон Паскаля. Гидравлический пресс. Гидростатика. Сообщающиеся сосуды. Атмосферное давление. Барометры и манометры.
+
+
+
+
+
+
+
+
E
+
Глава 5
+
Работа. Мощность. Энергия
+
§36–§42 + Финал
+
+
+
Механическая работа. КПД. Мощность. Кинетическая и потенциальная энергия. Закон сохранения механической энергии.
+
+
+
+
+
+
+
+
ЛР
+
Лаборатория
+
Лабораторный практикум
+
6 виртуальных ЛР
+
+
+
6 виртуальных лабораторных работ: цена деления, измерение длины и объёма, неравномерное движение, плотность вещества, сила трения.
+
+
+
+
+
+
+
+
+
+
+
+
Финал курса
+
Босс-проверка по всему курсу
+
Шпаргалка курса и 10 интегрированных боссов по всем 3 главам. Победи всех — получи «Магистр физики 7» и +150 XP.
+
+
+
+
+
+
+
+
+
+
+
+ Гл. 1
+ Методы познания
+
+
+ - $C = (X_2 - X_1)/N$ — цена деления
+ - $\Delta X = C/2$ — погрешность
+ - СИ: м, кг, с, А, К, моль, кд
+ - Кратные: к (10³), М (10⁶); дольные: м (10⁻³), мк (10⁻⁶)
+ - $S = ab$, $V = abc$ — косвенные измерения
+
+
+
+
+ Гл. 2
+ Строение вещества
+
+
+ - $d_{мол} \sim 10^{-10}$ м
+ - Тверд.: фиксированная форма и объём
+ - Жидк.: объём фиксирован, форма — нет
+ - Газ: ни форма, ни объём не фиксированы
+ - $\Delta l \sim \Delta T$ (расширение)
+ - Шкала Цельсия: 0 — лёд, 100 — кипение
+
+
+
+
+ Гл. 3
+ Движение и силы
+
+
+ - $v = s/t$, $[v] = $ м/с
+ - $\langle v\rangle = s_{полн}/t_{полн}$
+ - $\rho = m/V$, $[\rho] = $ кг/м³
+ - $F_т = mg$, $g \approx 10$ Н/кг
+ - $P = mg$ (вес на опоре)
+ - $R = F_1 + F_2$ (сонапр.), $R = |F_1 - F_2|$ (противопол.)
+ - $F_{тр} \sim N$
+
+
+
+
+ Гл. 4
+ Давление
+
+
+ - $p = F/S$, $[p] = $ Па
+ - Закон Паскаля: $p$ передаётся одинаково
+ - Гидравлика: $F_2/F_1 = S_2/S_1$
+ - $p = \rho g h$ — гидростатика
+ - Сообщ. сосуды → один уровень (однородная жидкость)
+ - $p_0 = 101\,325$ Па $= 760$ мм рт. ст.
+
+
+
+
+ Гл. 5
+ Работа и энергия
+
+
+ - $A = Fs$ (при $\vec F \parallel \vec s$), $[A] = $ Дж
+ - $\eta = A_{полез}/A_{полн} \cdot 100\%$
+ - $P = A/t$, $[P] = $ Вт
+ - $E_к = mv^2/2$
+ - $E_п = mgh$
+ - $E_к + E_п = \text{const}$ (без трения)
+
+
+
+
+
+
+ 10 интегрированных боссов
+
+
+
+
Боссов побеждено: 0 / 10
+
+
+
+
+
+
+
+
+
Курс Физика 8 пройден!
+
Вы прошли всю итоговую проверку курса. +150 XP, ачивка «Магистр физики 7» получена.
+
+
+ К каталогу учебников
+
+
+
+
+
+
+
+
+
+
+
Магистр физики 7
+
Прочитайте все 40 параграфов и выполните все 7 лабораторных работ, чтобы получить достижение
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/textbooks/physics_7_lab.html b/frontend/textbooks/physics_7_lab.html
new file mode 100644
index 0000000..e5e1dd3
--- /dev/null
+++ b/frontend/textbooks/physics_7_lab.html
@@ -0,0 +1,305 @@
+
+
+
+
+
+
+
+Физика 7 · Лабораторный практикум
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Физика 7 · Лабораторный практикум
+
6 виртуальных лабораторных работ
+
+
+
+
+
+
+
+
+
Лабораторные работы
+
+
+
+
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+
+
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+
+
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+
+
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+
+
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+
+
+
+ Виртуальная лабораторная работа появится в Phase 7 (после контента глав).
+
+
+
+
+
+
+
+
+
+
+
+
+
+