diff --git a/backend/src/db/migrations/009_physics_8.sql b/backend/src/db/migrations/009_physics_8.sql deleted file mode 100644 index e376c2a..0000000 --- a/backend/src/db/migrations/009_physics_8.sql +++ /dev/null @@ -1,12 +0,0 @@ --- Add Physics 8 textbooks (3 parts: thermal, electrical, optical phenomena) --- by Исаченкова Л. А. (2018). 40 paragraphs total, split across 3 files. -INSERT OR IGNORE INTO textbooks (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order) VALUES - ('physics-8-thermal', 'physics', 8, 'Физика 8 — Тепловые явления', 'Исаченкова Л. А.', - 'Часть 1. §1–§11: внутренняя энергия, теплопередача, удельная теплоёмкость, фазовые переходы, тепловые двигатели.', - 'physics8_thermal.html', 11, 'amber', 4), - ('physics-8-electro', 'physics', 8, 'Физика 8 — Электрические явления', 'Исаченкова Л. А.', - 'Часть 2. §12–§31: электризация, закон Кулона, электрический ток, закон Ома, работа и мощность тока, электромагнитные явления.', - 'physics8_electro.html', 20, 'blue', 5), - ('physics-8-optics', 'physics', 8, 'Физика 8 — Световые явления', 'Исаченкова Л. А.', - 'Часть 3. §32–§40: источники света, отражение и преломление, линзы, оптические приборы, цвет и спектр.', - 'physics8_optics.html', 9, 'violet', 6); diff --git a/backend/src/db/migrations/010_physics_8_merge.sql b/backend/src/db/migrations/010_physics_8_merge.sql deleted file mode 100644 index 917c192..0000000 --- a/backend/src/db/migrations/010_physics_8_merge.sql +++ /dev/null @@ -1,11 +0,0 @@ --- Объединить 3 отдельных учебника физики 8 (thermal/electro/optics) в один hub-учебник. --- Hub-страница physics_8.html содержит карточки 3 разделов и ссылки на исходные файлы. - --- 1. Удаляем 3 прежние записи (создали их часом раньше, прогресса пользователей ещё нет). -DELETE FROM textbooks WHERE slug IN ('physics-8-thermal','physics-8-electro','physics-8-optics'); - --- 2. Регистрируем единый учебник «Физика 8» с hub-страницей. -INSERT OR IGNORE INTO textbooks (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order) VALUES - ('physics-8', 'physics', 8, 'Физика — 8 класс', 'Исаченкова Л. А.', - 'Интерактивный учебник по физике 8 класса. 40 параграфов в трёх разделах: Тепловые явления (§1–§11), Электрические явления (§12–§31), Световые явления (§32–§40).', - 'physics_8.html', 40, 'blue', 4); diff --git a/backend/src/db/migrations/015_physics_8_hub.sql b/backend/src/db/migrations/015_physics_8_hub.sql deleted file mode 100644 index f790245..0000000 --- a/backend/src/db/migrations/015_physics_8_hub.sql +++ /dev/null @@ -1,29 +0,0 @@ --- Physics 8 hub migration. --- Converts physics-8 from a monolithic entry into a hub with 3 children, --- mirroring the algebra-8 hub pattern established in migration 014. - --- 1. Insert 3 child rows for the sub-textbooks. -INSERT OR IGNORE INTO textbooks - (slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active, parent_slug) -VALUES - ('physics-8-thermal', 'physics', 8, 'Физика 8 · Тепловые явления', - '', - 'Внутренняя энергия, теплопередача, удельная теплоёмкость, фазовые переходы, тепловые двигатели.', - 'physics8_thermal.html', 11, 'orange', 1, 1, 'physics-8'), - ('physics-8-electro', 'physics', 8, 'Физика 8 · Электрические явления', - '', - 'Электростатика, закон Кулона, электрический ток, закон Ома, электрические цепи.', - 'physics8_electro.html', 20, 'blue', 2, 1, 'physics-8'), - ('physics-8-optics', 'physics', 8, 'Физика 8 · Световые явления', - '', - 'Источники света, отражение, преломление, линзы, оптические приборы.', - 'physics8_optics.html', 9, 'purple', 3, 1, 'physics-8'); - --- 2. Update the parent physics-8 row: clear author, set para_count=40, update description. -UPDATE textbooks -SET - author = '', - para_count = 40, - html_path = 'physics_8.html', - description = 'Полный курс физики 8 класса в трёх разделах: тепловые явления (§1–§11), электрические явления (§12–§31), световые явления (§32–§40).' -WHERE slug = 'physics-8'; diff --git a/backend/src/db/migrations/037_physics_8_hub.sql b/backend/src/db/migrations/037_physics_8_hub.sql index 879d7b6..e2ac551 100644 --- a/backend/src/db/migrations/037_physics_8_hub.sql +++ b/backend/src/db/migrations/037_physics_8_hub.sql @@ -1,19 +1,27 @@ --- Physics 8 hub migration. --- Rebuilds physics-8 as a full 3-chapter + lab textbook in the style of physics-10: +-- Physics 8 hub migration (self-sufficient). +-- Creates / rebuilds physics-8 as a full 3-chapter + lab textbook in the style of physics-10: -- physics-8 (hub, html_path = physics_8_hub.html) -- physics-8-ch1 (Тепловые явления, §§1–11) → physics_8_ch1.html -- physics-8-ch2 (Электромагнитные явления, §§12–31) → physics_8_ch2.html -- physics-8-ch3 (Световые явления, §§32–40) → physics_8_ch3.html -- physics-8-lab (Лабораторный практикум, 7 ЛР) → physics_8_lab.html -- --- Replaces the old legacy children created in migration 015 --- (physics-8-thermal / physics-8-electro / physics-8-optics), which pointed --- to monolithic legacy files. Author left empty per project policy. +-- This migration is the single source of truth for physics-8 textbook structure. +-- It is idempotent and does not depend on any prior physics-8 migration. --- 1. Remove legacy children (HTML files are kept on disk as backup, just unlinked from DB). +-- 1. Remove legacy children if they ever existed (no-op on fresh DBs). DELETE FROM textbooks WHERE slug IN ('physics-8-thermal', 'physics-8-electro', 'physics-8-optics'); --- 2. Update the parent physics-8 hub row. +-- 2. Ensure the parent physics-8 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-8', 'physics', 8, 'Физика — 8 класс', + '', + 'Полный курс физики 8 класса: тепловые явления (§§1–11), электромагнитные явления (§§12–31), световые явления (§§32–40), 7 виртуальных лабораторных работ.', + 'physics_8_hub.html', 47, 'violet', 4, 1); + +-- 3. Update the parent physics-8 hub row (covers case where it already existed from legacy migrations). UPDATE textbooks SET author = '', diff --git a/frontend/js/phys.js b/frontend/js/phys.js index 9e596b8..098ca3e 100644 --- a/frontend/js/phys.js +++ b/frontend/js/phys.js @@ -353,6 +353,81 @@ function phaseGraphTT(W, H, pad, points, tMaxAll, TminAll, TmaxAll) { return { svg: s, toX: toX, toY: toY }; } +// === Анимация конвекции — тороидальный поток частиц === +// Используется в §4 Физики 8 (главный визуал «конвекция в жидкости/газе»). +// opts: { N — число частиц (default 24), w, h — размеры области, speed (отн. ед., default 1), +// tHot, tCold — температуры для окраски (default 100, 20) }. +function createConvectionSim(opts) { + opts = opts || {}; + const N = opts.N || 24; + const w = opts.w || 220; + const h = opts.h || 140; + const speed = opts.speed != null ? opts.speed : 1; + const tHot = opts.tHot != null ? opts.tHot : 100; + const tCold = opts.tCold != null ? opts.tCold : 20; + // Каждая частица движется по фазе вдоль контура прямоугольника: + // правая сторона — вверх (нагрев / подъём), верхняя — влево, левая — вниз (охлаждение), нижняя — вправо. + const parts = new Array(N); + for (let i = 0; i < N; i++) parts[i] = { phase: i / N }; + return { + N: N, w: w, h: h, speed: speed, + _tHot: tHot, _tCold: tCold, + setSpeed(v) { this.speed = v; }, + setHot(v) { this._tHot = v; }, + setCold(v) { this._tCold = v; }, + step(dt) { + const dPhase = 0.18 * this.speed * dt; + for (let i = 0; i < this.N; i++) { + parts[i].phase = (parts[i].phase + dPhase) % 1; + if (parts[i].phase < 0) parts[i].phase += 1; + } + }, + // Возвращает координаты частицы (cx, cy) и температуру по её положению. + // phase ∈ [0,1): 0..0.25 — правая (подъём, t→tHot), 0.25..0.5 — верх (t=tHot), + // 0.5..0.75 — левая (опускание, t→tCold), 0.75..1 — низ (t=tCold). + _xy(phase, x, y) { + const margin = 12; + const W = this.w - 2 * margin; + const H = this.h - 2 * margin; + let lx, ly, t; + if (phase < 0.25) { + const k = phase / 0.25; + lx = W; ly = H * (1 - k); + t = this._tCold + (this._tHot - this._tCold) * k; + } else if (phase < 0.5) { + const k = (phase - 0.25) / 0.25; + lx = W * (1 - k); ly = 0; + t = this._tHot; + } else if (phase < 0.75) { + const k = (phase - 0.5) / 0.25; + lx = 0; ly = H * k; + t = this._tHot - (this._tHot - this._tCold) * k; + } else { + const k = (phase - 0.75) / 0.25; + lx = W * k; ly = H; + t = this._tCold; + } + return { cx: x + margin + lx, cy: y + margin + ly, t: t }; + }, + render(x, y) { + const tMin = Math.min(this._tCold, this._tHot); + const tMax = Math.max(this._tCold, this._tHot); + let s = ''; + // Контур сосуда + s += ``; + // Нагреватель снизу (красная полоса) + s += ``; + // Частицы + for (let i = 0; i < this.N; i++) { + const p = this._xy(parts[i].phase, x, y); + const c = tempColor(p.t, tMin, tMax); + s += ``; + } + return s; + } + }; +} + // === Электронные хелперы для электрических задач === // Параллельное и последовательное сопротивление function Rseries() { @@ -374,6 +449,7 @@ window.PHYS = { thermometer: thermometer, calorimeter: calorimeter, createHeatBar: createHeatBar, + createConvectionSim: createConvectionSim, phaseGraphTT: phaseGraphTT, Rseries: Rseries, Rparallel: Rparallel, diff --git a/frontend/textbooks/physics_8_lab.html b/frontend/textbooks/physics_8_lab.html index 984875b..5269a1b 100644 --- a/frontend/textbooks/physics_8_lab.html +++ b/frontend/textbooks/physics_8_lab.html @@ -889,10 +889,10 @@ function build_lr4(){ +'' +'' +'
' - +'Общий ток $I$ = 1 А (одинаков везде ✓)' + +'Общий ток $I$ = 1 А (одинаков везде ✓)' +'$U_1$ = 4 В, $U_2$ = 8 В' - +'$U_1+U_2$ = 12 В = $U$ ✓' - +'$R = R_1+R_2$ = 12 Ом, $U/I$ = 12 Ом ✓
'; + +'$U_1+U_2$ = 12 В = $U$ ✓' + +'$R = R_1+R_2$ = 12 Ом, $U/I$ = 12 Ом ✓'; h += _labResult('lr4', '

Все 3 правила послед. соединения подтверждены опытом:

' +'
  • $I$ одинаков везде;
  • $U = U_1 + U_2$;
  • $R = R_1 + R_2$.
' +'

Вывод: закон Ома и правила последовательного соединения выполняются.

'); @@ -938,10 +938,10 @@ function build_lr5(){ +'' +'' +'
' - +'$U_1 = U_2 = U$ = 12 В ✓' + +'$U_1 = U_2 = U$ = 12 В ✓' +'$I_1$ = 2 А, $I_2$ = 1 А' - +'$I_1+I_2$ = 3 А = $I$ ✓' - +'$R_{общ}$ по формуле = 4 Ом, $U/I$ = 4 Ом ✓
'; + +'$I_1+I_2$ = 3 А = $I$ ✓' + +'$R_{общ}$ по формуле = 4 Ом, $U/I$ = 4 Ом ✓'; h += _labResult('lr5', '

Все 3 правила параллельного соединения подтверждены:

' +'
  • $U$ одинаково на обеих ветвях;
  • $I = I_1 + I_2$;
  • $1/R = 1/R_1 + 1/R_2$.
' +'

Вывод: общее $R$ меньше любого из $R_1$, $R_2$, что соответствует теории.

'); @@ -1031,7 +1031,7 @@ function build_lr7(){ h += '
СИМ
Виртуальный опыт
' +'
' +'' - +'
$\\alpha$ = 30°Измерено $\\beta$ = 30°$\\alpha = \\beta$ ✓
'; + +'
$\\alpha$ = 30°Измерено $\\beta$ = 30°$\\alpha = \\beta$ ✓
'; /* таблица результатов */ h += '
ТАБЛИЦА
Серия измерений
' +''
Опыт$\\alpha$, °$\\beta$, °$\\alpha - \\beta$