Files
Learn_System/frontend/js/phys7_ch2_widgets.js
Maxim Dolgolyov ed97b6d90b feat(phys7 ch2): Phase 2 целиком — §§8-13 + финал «Знаток вещества»
Полная глава 2 «Строение вещества» в одном файле (1195 строк, 7 экспортов).

§8 Дискретное строение:
- 3 карточки (молекулы и атомы / шкала размеров от 1 м до ядра / доказательства)
- IV-1 СИМ: визуальная шкала размеров (8 объектов с цветными барами)
- IV-2 СИМ: конструктор молекул H₂O/CO₂/O₂/N₂/CH4/NaCl с SVG-схемами и описаниями
- IV-3 DnD: 8 объектов по 3 корзинам (атом/молекула/тело)
- IV-4 ТРН: 5 вопросов

§9 Тепловое движение. Диффузия:
- 3 карточки (хаотическое движение / диффузия и её скорость / примеры)
- IV-1 СИМ: анимированная диффузия 60 частиц (20 чернил + 40 воды), slider T → ускорение броуновского движения, кнопка «Сброс», requestAnimationFrame
- IV-2 КВИЗ: 3 вопроса о диффузии и броун. движении
- IV-3 DnD: 6 примеров → 3 скорости (быстро газ / средне жидк / медленно тверд)
- IV-4 ТРН: 5 вопросов

§10 Взаимодействие частиц:
- 3 карточки (отталкивание/равновесие/притяжение / зачем знать / опыт со свинцом)
- IV-1 СИМ: интерактивный график F(r) (Леннард-Джонс-подобная кривая), slider положения → автоматическое определение «отталкивание / равновесие / притяжение / силы малы»
- IV-2 КВИЗ: 4 вопроса
- IV-3 DnD: 6 ситуаций по 4 корзинам
- IV-4 ТРН: 4 вопроса

§11 Три состояния — ГЛАВНЫЙ ВИЗУАЛ ГЛАВЫ 2:
- 3 карточки (таблица состояний / поведение молекул / вода во всех 3 состояниях)
- IV-1 СИМ: переключатель solid/liquid/gas с 3 разными режимами анимации
  50 частиц: solid — крист. решётка 10×5 + дрожание; liquid — отскоки + гравитация
  к дну + плоский уровень; gas — свободное хаотическое движение по всему объёму
- IV-2 КВИЗ: 4 вопроса о свойствах
- IV-3 DnD: 9 веществ → 3 состояния
- IV-4 ТРН: 5 вопросов

§12 Тепловое расширение:
- 3 карточки (почему / где важно / аномалия воды)
- IV-1 СИМ: стержень со slider ΔT (0..200°C), цвет по температуре (HSL 240→0),
  пунктир базовой длины, индикатор Δl
- IV-2 СИМ: биметаллическая пластина с slider ΔT (-50..100°C), изгиб ±30°
- IV-3 DnD: 6 веществ → 3 уровня расширения
- IV-4 ТРН: 5 вопросов

§13 Температура. Термометры:
- 3 карточки (T и тепловое движение / шкала Цельсия / 4 вида термометров)
- IV-1 СИМ: виртуальный термометр SVG (-50..150 °C), столбик меняет цвет по
  температуре, шкала с делениями, указатель-стрелка, контекстная подсказка
  (мороз/комфорт/жарко/кипяток...) + конвертер в Кельвины
- IV-2 КАЛЬК: slider t°C → T(K) = t + 273.15, упоминание абс. нуля
- IV-3 DnD: 6 температур → 3 диапазона
- IV-4 ТРН: 5 вопросов (включая °C↔K)

ФИНАЛ ГЛАВЫ 2 (5 боссов + ачивка «Знаток вещества» +50 XP):
1. Молекула vs волос: во сколько раз меньше (10⁶)
2. Диффузия в горячей воде (/T_2$ через Кельвины)
3. Сжатие газа в шприце (20/50 = 40%)
4. Удлинение рельса при ΔT=60°C (18 мм)
5. 27 °C → 300.2 K

Все интерактивы wireDnd/wireQuiz/слайдеры/симы привязаны. parse-check, smoke-test (7 экспортов) пройдены.
2026-05-30 11:00:40 +03:00

1196 lines
88 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Физика 7 · Глава 2 «Строение вещества» · виджеты §§8–13 + финал (Wave 1+2+3).
// Экспорт: window.PHYS7_CH2_WIDGETS = { p8, p9, p10, p11, p12, p13, final2 }.
// Палитра главы — violet (#7c3aed).
(function(){
'use strict';
const ACCENT = '#7c3aed';
const ACCENT_D = '#5b21b6';
const ACCENT_SOFT = '#ede9fe';
function renderMath(root){
if(window.renderMathInElement){
try{
window.renderMathInElement(root, {
delimiters: [{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}],
throwOnError: false
});
}catch(e){}
}
}
function makeCard(kind, title, badge, body){
const colorByKind = { theory:ACCENT, rule:'#dc2626', example:'#10b981' };
const labelByKind = { theory:'Теория', rule:'Правило', example:'Пример' };
const c = colorByKind[kind] || ACCENT;
return '<div style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-left:5px solid ' + c + ';border-radius:11px;padding:14px 16px;margin-bottom:14px;box-shadow:0 2px 8px rgba(0,0,0,.05)">'
+ '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap">'
+ '<span style="background:' + c + ';color:#fff;padding:3px 10px;border-radius:99px;font-size:.7rem;font-weight:800;text-transform:uppercase;letter-spacing:.05em">' + labelByKind[kind] + '</span>'
+ '<span style="font-size:.72rem;font-weight:700;color:#64748b;letter-spacing:.04em">' + (badge||'') + '</span>'
+ '<span style="font-family:Unbounded,sans-serif;font-weight:800;font-size:.96rem;color:#0f172a;flex:1;min-width:0">' + title + '</span>'
+ '</div>'
+ '<div style="font-size:.94rem;line-height:1.6;color:#0f172a">' + body + '</div>'
+ '</div>';
}
function wgWrap(id, badge, title, hint, body){
return '<div id="' + id + '" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:12px;padding:14px 16px;margin-bottom:14px;box-shadow:0 2px 8px rgba(0,0,0,.05)">'
+ '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap">'
+ '<span style="background:' + ACCENT + ';color:#fff;padding:3px 10px;border-radius:99px;font-size:.7rem;font-weight:800;letter-spacing:.05em">' + badge + '</span>'
+ '<span style="font-family:Unbounded,sans-serif;font-weight:800;font-size:.92rem;color:#0f172a">' + title + '</span>'
+ '</div>'
+ (hint ? '<div style="font-size:.84rem;color:#64748b;background:' + ACCENT_SOFT + ';border-left:3px solid ' + ACCENT + ';border-radius:6px;padding:8px 12px;margin-bottom:10px;line-height:1.5">' + hint + '</div>' : '')
+ body
+ '</div>';
}
function readButton(pid){
return '<div style="text-align:center;margin-top:18px"><button class="ph7-read-btn" data-pid="' + pid + '" '
+ 'style="background:linear-gradient(135deg,#10b981,#047857);color:#fff;border:none;padding:11px 22px;border-radius:11px;font-weight:700;font-size:.92rem;cursor:pointer;font-family:inherit;display:inline-flex;align-items:center;gap:8px;box-shadow:0 4px 14px rgba(16,185,129,.32)">'
+ '<svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"><polyline points="20 6 9 17 4 12"/></svg>'
+ 'Я прочитал § &nbsp;<span style="opacity:.85;font-size:.86rem">+10 XP</span>'
+ '</button></div>';
}
function wireReadBtn(pid){
const btn = document.querySelector('.ph7-read-btn[data-pid="' + pid + '"]');
if(!btn) return;
const KEY = 'physics7_ch2_read_' + pid;
if(localStorage.getItem(KEY) === '1'){
btn.innerHTML = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"><polyline points="20 6 9 17 4 12"/></svg> Прочитано';
btn.disabled = true; btn.style.background = '#94a3b8'; btn.style.cursor = 'default';
return;
}
btn.addEventListener('click', function(){
if(localStorage.getItem(KEY) === '1') return;
localStorage.setItem(KEY, '1');
if(typeof window.bumpProgress === 'function') window.bumpProgress(pid, 30);
if(typeof window.addXp === 'function') window.addXp(10, 'read-' + pid);
btn.innerHTML = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round"><polyline points="20 6 9 17 4 12"/></svg> Прочитано';
btn.disabled = true; btn.style.background = '#94a3b8'; btn.style.cursor = 'default';
});
}
function wireDnd(host, items){
const root = document.getElementById(host);
if(!root) return;
const checkBtn = root.querySelector('.dnd-check');
const fb = root.querySelector('.dnd-fb');
let placed = {};
let armed = null;
root.querySelectorAll('.dnd-chip').forEach(chip => chip.addEventListener('click', () => {
if(armed === chip){ armed.classList.remove('armed'); armed.style.boxShadow = ''; armed = null; return; }
if(armed){ armed.classList.remove('armed'); armed.style.boxShadow = ''; }
armed = chip;
chip.classList.add('armed');
chip.style.boxShadow = '0 0 0 3px rgba(124,58,237,.3)';
}));
root.querySelectorAll('.drop-box').forEach(box => box.addEventListener('click', () => {
if(!armed) return;
const cat = box.dataset.cat;
const id = armed.dataset.id;
placed[id] = cat;
const inner = box.querySelector('.drop-items');
const clone = armed.cloneNode(true);
clone.classList.remove('armed'); clone.classList.add('placed');
clone.style.background = ACCENT_SOFT; clone.style.borderColor = ACCENT; clone.style.boxShadow = '';
clone.addEventListener('click', e => {
e.stopPropagation();
delete placed[id];
clone.remove();
armed = null;
const orig = root.querySelector('.dnd-chip[data-id="' + id + '"]:not(.placed)');
if(orig) orig.style.display = '';
});
inner.appendChild(clone);
armed.style.display = 'none';
armed.classList.remove('armed'); armed.style.boxShadow = '';
armed = null;
}));
if(checkBtn) checkBtn.addEventListener('click', () => {
const total = items.length;
let correct = 0;
items.forEach(it => { if(placed[it.id] === it.cat) correct++; });
fb.style.display = 'block';
if(correct === total){
fb.style.background = '#d1fae5'; fb.style.color = '#065f46'; fb.style.borderLeft = '4px solid #10b981';
fb.innerHTML = '&#10003; Идеально! Все ' + total + ' карточек на своих местах.';
if(typeof window.addXp === 'function') window.addXp(15, 'dnd-' + host);
} else {
fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.innerHTML = '&#10007; Правильно: ' + correct + '/' + total + '. Попробуй ещё раз.';
}
});
}
function dndPool(host, items, cats){
const chips = items.map(it => '<button class="dnd-chip" data-id="' + it.id + '" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:10px;padding:7px 13px;cursor:pointer;font-size:.9rem;font-family:inherit;transition:all .15s">' + it.html + '</button>').join('');
const boxes = cats.map(c => '<div class="drop-box" data-cat="' + c.cat + '" style="background:#fff;border:1.5px dashed ' + ACCENT_SOFT + ';border-radius:10px;padding:10px;min-height:80px"><h5 style="font-family:Unbounded,sans-serif;font-size:.76rem;color:' + ACCENT_D + ';margin-bottom:8px;text-transform:uppercase;letter-spacing:.04em">' + c.label + '</h5><div class="drop-items" style="display:flex;flex-wrap:wrap;gap:6px;min-height:32px"></div></div>').join('');
return '<div id="' + host + '" class="dnd-host">'
+ '<div style="font-size:.86rem;color:#475569;margin-bottom:10px">Кликни по карточке, потом — на корзину. Чтобы вернуть: кликни по карточке в корзине.</div>'
+ '<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed ' + ACCENT_SOFT + ';border-radius:10px;background:#faf5ff">' + chips + '</div>'
+ '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px;margin-bottom:12px">' + boxes + '</div>'
+ '<div style="display:flex;gap:8px"><button class="dnd-check" type="button" style="background:linear-gradient(135deg,' + ACCENT + ',' + ACCENT_D + ');color:#fff;border:none;padding:9px 18px;border-radius:9px;font-weight:700;font-size:.86rem;cursor:pointer;font-family:inherit">Проверить</button></div>'
+ '<div class="dnd-fb" style="padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none;line-height:1.45"></div>'
+ '</div>';
}
function quizQuestion(host, idx, q, opts, correctIdx, explain){
const optsHtml = opts.map((o,i) => '<button class="qz-opt" data-i="' + i + '" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:9px;padding:9px 14px;cursor:pointer;font-size:.92rem;font-family:inherit;text-align:left;width:100%;margin-bottom:6px">' + o + '</button>').join('');
return '<div class="qz-q" data-idx="' + idx + '" style="background:' + ACCENT_SOFT + ';border:1.5px solid ' + ACCENT_SOFT + ';border-radius:10px;padding:12px 14px;margin-bottom:10px">'
+ '<div style="font-weight:700;margin-bottom:8px;font-size:.94rem">' + (idx+1) + '. ' + q + '</div>'
+ '<div class="qz-opts" data-correct="' + correctIdx + '" data-explain="' + (explain||'').replace(/"/g,'&quot;') + '">' + optsHtml + '</div>'
+ '<div class="qz-fb" style="padding:9px 12px;border-radius:8px;font-size:.86rem;margin-top:6px;display:none;line-height:1.45"></div>'
+ '</div>';
}
function wireQuiz(host, onAllCorrect){
const root = document.getElementById(host);
if(!root) return;
const all = root.querySelectorAll('.qz-q');
const done = new Set();
all.forEach(qDiv => {
const opts = qDiv.querySelectorAll('.qz-opt');
const correct = +qDiv.querySelector('.qz-opts').dataset.correct;
const explain = qDiv.querySelector('.qz-opts').dataset.explain;
const fb = qDiv.querySelector('.qz-fb');
opts.forEach(o => o.addEventListener('click', () => {
if(done.has(qDiv)) return;
const i = +o.dataset.i;
opts.forEach(x => x.disabled = true);
if(i === correct){
o.style.background = '#d1fae5'; o.style.borderColor = '#10b981'; o.style.color = '#065f46';
fb.style.display = 'block'; fb.style.background = '#d1fae5'; fb.style.color = '#065f46'; fb.style.borderLeft = '4px solid #10b981';
fb.innerHTML = '&#10003; Верно!' + (explain ? ' ' + explain : '');
done.add(qDiv);
if(done.size === all.length && typeof onAllCorrect === 'function') onAllCorrect();
} else {
o.style.background = '#fee2e2'; o.style.borderColor = '#dc2626'; o.style.color = '#7f1d1d';
opts[correct].style.background = '#d1fae5'; opts[correct].style.borderColor = '#10b981'; opts[correct].style.color = '#065f46';
fb.style.display = 'block'; fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.innerHTML = '&#10007; Неверно. Правильно: «' + opts[correct].textContent + '».' + (explain ? ' ' + explain : '');
done.add(qDiv);
}
}));
});
}
/* ========================================================== */
/* §8 — Дискретное строение вещества */
/* ========================================================== */
function add_p8(){
const body = document.getElementById('p8-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Из чего состоит вещество', '§ 8.1',
'Все вещества состоят из <b>мельчайших частиц</b> — <b>молекул</b> и <b>атомов</b>. '
+ 'Они так малы, что не видны даже в обычный микроскоп. Между частицами есть <b>промежутки</b>. '
+ 'Молекула — это наименьшая частица вещества, сохраняющая его химические свойства. '
+ 'Молекулы состоят из <b>атомов</b>.');
h += makeCard('rule', 'Размеры частиц', '§ 8.2',
'Типичный диаметр молекулы — около $10^{-10}$ м. Сравни:'
+ '<table style="width:100%;border-collapse:collapse;margin-top:6px;font-size:.92rem">'
+ '<tr style="background:' + ACCENT_SOFT + '"><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Объект</th><th style="padding:6px 10px;text-align:right;border-bottom:2px solid ' + ACCENT + '">Размер</th></tr>'
+ [['Зерно мака','1 мм $= 10^{-3}$ м'],['Толщина волоса','$\\approx 10^{-4}$ м'],['Бактерия','$\\approx 10^{-6}$ м'],['Молекула','$\\approx 10^{-10}$ м'],['Атом','$\\approx 10^{-10}$ м'],['Ядро атома','$\\approx 10^{-15}$ м']].map(([nm, sz]) =>
'<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">' + nm + '</td><td style="padding:5px 10px;text-align:right;border-bottom:1px solid ' + ACCENT_SOFT + ';font-family:JetBrains Mono,monospace">' + sz + '</td></tr>').join('')
+ '</table>');
h += makeCard('example', 'Доказательства дискретности', '§ 8.3',
'<ol style="padding-left:20px;margin:6px 0;line-height:1.7">'
+ '<li><b>Сжимаемость газов</b> — при сдавливании поршнем объём уменьшается → есть пустоты между молекулами.</li>'
+ '<li><b>Растворение сахара в воде</b> — молекулы сахара заполняют промежутки между молекулами воды; уровень почти не поднимается.</li>'
+ '<li><b>Расширение тел при нагреве</b> — увеличиваются промежутки между частицами.</li>'
+ '</ol>');
/* IV-1: визуал-масштабы */
h += wgWrap('p8-iv1', 'СИМ', 'Шкала размеров', 'От огромного к крошечному (логарифмическая шкала).',
'<div style="display:flex;flex-direction:column;gap:6px">'
+ [['1 м','Человек','#0284c7',1],['0,01 м','Монета','#10b981',0.85],['0,001 м','Зерно мака','#d97706',0.7],['10⁻⁴ м','Волос (толщина)','#dc2626',0.55],['10⁻⁶ м','Бактерия','#7c3aed',0.4],['10⁻⁸ м','Вирус','#0891b2',0.25],['10⁻¹⁰ м','Молекула','#92400e',0.12],['10⁻¹⁵ м','Ядро атома','#374151',0.05]].map(([sz, nm, col, w]) =>
'<div style="display:flex;align-items:center;gap:10px;background:#faf5ff;border-radius:8px;padding:6px 10px">'
+ '<div style="font-family:JetBrains Mono,monospace;font-weight:700;color:' + col + ';min-width:64px;font-size:.86rem">' + sz + '</div>'
+ '<div style="flex:1;height:18px;background:#fff;border:1px solid ' + ACCENT_SOFT + ';border-radius:4px;overflow:hidden"><div style="height:100%;width:' + (w*100) + '%;background:linear-gradient(90deg,' + col + ',' + col + '88)"></div></div>'
+ '<div style="font-size:.86rem;color:#475569;min-width:120px">' + nm + '</div>'
+ '</div>').join('')
+ '</div>');
/* IV-2: конструктор молекулы */
h += wgWrap('p8-iv2', 'СИМ', 'Конструктор молекулы', 'Выбери — увидь схему молекулы из атомов.',
'<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">'
+ ['H2O','CO2','O2','N2','CH4','NaCl'].map(m =>
'<button class="p8-mol" data-m="' + m + '" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:8px;padding:7px 14px;cursor:pointer;font-family:JetBrains Mono,monospace;font-weight:700;font-size:.9rem">' + m + '</button>').join('')
+ '</div>'
+ '<svg id="p8-mol-svg" viewBox="0 0 320 130" width="100%" style="max-width:400px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p8-mol-desc" style="text-align:center;font-size:.88rem;color:#475569;margin-top:8px"></div>');
/* IV-3: DnD */
h += wgWrap('p8-iv3', 'DnD', 'Атом / молекула / тело', 'Распредели понятия по корзинам.',
dndPool('p8-dnd', [
{ id:'a1', cat:'atom', html:'Атом водорода H' },
{ id:'a2', cat:'atom', html:'Атом кислорода O' },
{ id:'a3', cat:'mol', html:'Молекула воды H₂O' },
{ id:'a4', cat:'mol', html:'Молекула CO₂' },
{ id:'a5', cat:'body', html:'Капля воды' },
{ id:'a6', cat:'body', html:'Резиновый мяч' },
{ id:'a7', cat:'atom', html:'Атом железа Fe' },
{ id:'a8', cat:'mol', html:'Молекула O₂' }
], [
{ cat:'atom', label:'Атом' },
{ cat:'mol', label:'Молекула' },
{ cat:'body', label:'Тело' }
]));
/* IV-4: тренажёр */
h += wgWrap('p8-iv4', 'ТРН', 'Тренажёр §8', '5 вопросов на закрепление.',
'<div id="p8-tr-host">'
+ quizQuestion('p8-tr', 0, 'Каков примерный диаметр молекулы воды?', ['$10^{-3}$ м','$10^{-6}$ м','$10^{-10}$ м','$10^{-15}$ м'], 2, 'Молекулы — порядка $10^{-10}$ м (десятая часть нанометра).')
+ quizQuestion('p8-tr', 1, 'Что меньше: молекула или ядро атома?', ['Молекула','Ядро атома','Они одинаковые','Зависит от вещества'], 1, 'Ядро в $\\sim 10^5$ раз меньше атома.')
+ quizQuestion('p8-tr', 2, 'Почему газы легко сжимаются?', ['Молекулы мягкие','Между молекулами большие промежутки','Газ не имеет молекул','Молекулы скользят'], 1)
+ quizQuestion('p8-tr', 3, 'Молекула — это…', ['Видимая частица','Наименьшая частица, сохраняющая свойства вещества','Атом','Кристалл'], 1)
+ quizQuestion('p8-tr', 4, 'Из чего состоят молекулы?', ['Из электронов','Из протонов','Из атомов','Из ядер'], 2)
+ '</div>');
h += readButton('p8');
body.innerHTML = h;
// Wire molecule constructor
const molData = {
'H2O': { atoms:[{x:160,y:65,r:18,c:'#dc2626',l:'O'},{x:120,y:90,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:200,y:90,r:11,c:'#fff',l:'H',stroke:'#94a3b8'}], bonds:[[0,1],[0,2]], desc:'H₂O (вода): 1 атом кислорода + 2 атома водорода под углом 104,5°.' },
'CO2': { atoms:[{x:160,y:65,r:14,c:'#0f172a',l:'C'},{x:100,y:65,r:18,c:'#dc2626',l:'O'},{x:220,y:65,r:18,c:'#dc2626',l:'O'}], bonds:[[0,1],[0,2]], desc:'CO₂ (углекислый газ): углерод между двумя кислородами, молекула линейная.' },
'O2': { atoms:[{x:120,y:65,r:18,c:'#dc2626',l:'O'},{x:200,y:65,r:18,c:'#dc2626',l:'O'}], bonds:[[0,1]], desc:'O₂ (кислород): два атома кислорода. Этим воздухом мы дышим.' },
'N2': { atoms:[{x:120,y:65,r:18,c:'#0891b2',l:'N'},{x:200,y:65,r:18,c:'#0891b2',l:'N'}], bonds:[[0,1]], desc:'N₂ (азот): два атома азота. 78 % воздуха — это N₂.' },
'CH4': { atoms:[{x:160,y:65,r:14,c:'#0f172a',l:'C'},{x:160,y:30,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:160,y:100,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:110,y:65,r:11,c:'#fff',l:'H',stroke:'#94a3b8'},{x:210,y:65,r:11,c:'#fff',l:'H',stroke:'#94a3b8'}], bonds:[[0,1],[0,2],[0,3],[0,4]], desc:'CH₄ (метан): углерод в центре, 4 водорода по углам тетраэдра. Природный газ.' },
'NaCl':{ atoms:[{x:130,y:65,r:18,c:'#7c3aed',l:'Na'},{x:200,y:65,r:18,c:'#10b981',l:'Cl'}], bonds:[[0,1]], desc:'NaCl (поваренная соль): натрий + хлор. В твёрдом виде образует кубическую решётку.' }
};
function drawMol(m){
const d = molData[m];
let s = '';
d.bonds.forEach(([i,j]) => {
s += '<line x1="' + d.atoms[i].x + '" y1="' + d.atoms[i].y + '" x2="' + d.atoms[j].x + '" y2="' + d.atoms[j].y + '" stroke="#475569" stroke-width="3"/>';
});
d.atoms.forEach(a => {
s += '<circle cx="' + a.x + '" cy="' + a.y + '" r="' + a.r + '" fill="' + a.c + '" stroke="' + (a.stroke || a.c) + '" stroke-width="1.5"/>';
s += '<text x="' + a.x + '" y="' + (a.y + 4) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="' + (a.c === '#fff' ? '#0f172a' : '#fff') + '">' + a.l + '</text>';
});
document.getElementById('p8-mol-svg').innerHTML = s;
document.getElementById('p8-mol-desc').textContent = d.desc;
}
body.querySelectorAll('.p8-mol').forEach(btn => btn.addEventListener('click', () => {
body.querySelectorAll('.p8-mol').forEach(b => { b.style.background = '#fff'; b.style.color = '#0f172a'; });
btn.style.background = ACCENT; btn.style.color = '#fff';
drawMol(btn.dataset.m);
}));
drawMol('H2O');
body.querySelector('.p8-mol[data-m="H2O"]').style.background = ACCENT;
body.querySelector('.p8-mol[data-m="H2O"]').style.color = '#fff';
wireDnd('p8-dnd', [
{ id:'a1', cat:'atom' },{ id:'a2', cat:'atom' },{ id:'a3', cat:'mol' },{ id:'a4', cat:'mol' },
{ id:'a5', cat:'body' },{ id:'a6', cat:'body' },{ id:'a7', cat:'atom' },{ id:'a8', cat:'mol' }
]);
wireQuiz('p8-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p8'); });
wireReadBtn('p8');
renderMath(body);
}
/* ========================================================== */
/* §9 — Тепловое движение частиц. Диффузия */
/* ========================================================== */
function add_p9(){
const body = document.getElementById('p9-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Молекулы вечно движутся', '§ 9.1',
'Молекулы любого тела находятся в <b>непрерывном беспорядочном (хаотическом) движении</b>. '
+ 'Это движение называется <b>тепловым</b>: чем выше температура, тем быстрее движутся частицы.<br><br>'
+ 'Доказательство — <b>броуновское движение</b>: мельчайшие частицы в воде (пыльца, тушь) непрерывно дёргаются под ударами молекул.');
h += makeCard('rule', 'Диффузия', '§ 9.2',
'<b>Диффузия</b> — это самопроизвольное взаимное проникновение молекул одного вещества между молекулами другого.<br><br>'
+ 'Скорость диффузии зависит от:'
+ '<ul style="padding-left:20px;margin:5px 0">'
+ '<li><b>температуры:</b> выше $T$ → быстрее диффузия;</li>'
+ '<li><b>состояния вещества:</b> в газах ⪢ в жидкостях ⪢ в твёрдых телах.</li>'
+ '</ul>');
h += makeCard('example', 'Где мы видим диффузию', '§ 9.3',
'<ul style="padding-left:20px;margin:6px 0">'
+ '<li><b>Запах</b> духов или пищи распространяется по комнате — диффузия в воздухе.</li>'
+ '<li><b>Чай</b> завариваеётся быстрее в горячей воде — молекулы чая активно перемешиваются.</li>'
+ '<li><b>Засолка</b> огурцов идёт долго — диффузия в жидкости медленнее, чем в газе.</li>'
+ '<li><b>Сварка</b> металлов на самом деле — диффузия атомов в твёрдом теле, очень медленная.</li>'
+ '</ul>');
/* IV-1: симуляция диффузии (свой простой газ) */
h += wgWrap('p9-iv1', 'СИМ', 'Диффузия чернил в воде', 'Меняй температуру — наблюдай, как ускоряется смешивание.',
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Температура $t$, °C: <b id="p9-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">20</b><input type="range" id="p9-T-r" min="0" max="90" step="1" value="20" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<div style="display:flex;gap:6px;align-items:center;justify-content:flex-end;padding-top:6px"><button id="p9-reset" type="button" style="background:#fff;border:1.5px solid ' + ACCENT_SOFT + ';padding:8px 14px;border-radius:9px;cursor:pointer;font-family:inherit;font-weight:600">Сброс</button></div>'
+ '</div>'
+ '<svg id="p9-sim" viewBox="0 0 360 160" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#cffafe;border-radius:9px;border:1px solid #67e8f9"></svg>'
+ '<div style="text-align:center;font-size:.86rem;color:#64748b;margin-top:6px">Синие молекулы — вода, тёмные — чернила. Видно, как чем теплее, тем быстрее они перемешиваются.</div>');
/* IV-2: квиз */
h += wgWrap('p9-iv2', 'КВИЗ', 'Про диффузию', 'Выбери верное.',
'<div id="p9-q-host">'
+ quizQuestion('p9-q', 0, 'В каком веществе диффузия идёт быстрее всего?', ['В твёрдом','В жидком','В газообразном','Одинаково'], 2, 'В газах молекулы движутся быстрее и расстояния между ними больше.')
+ quizQuestion('p9-q', 1, 'Как ускорить заваривание чая?', ['Понизить температуру','Налить холодной воды','Налить горячей воды','Не размешивать'], 2)
+ quizQuestion('p9-q', 2, 'Что доказывает броуновское движение?', ['Что молекулы покоятся','Что молекулы движутся','Что молекулы видны','Что молекул нет'], 1)
+ '</div>');
/* IV-3: DnD скорости */
h += wgWrap('p9-iv3', 'DnD', 'Где диффузия быстрее?', 'Распредели 6 ситуаций.',
dndPool('p9-dnd', [
{ id:'a1', cat:'fast', html:'Дым из костра в воздухе' },
{ id:'a2', cat:'fast', html:'Запах духов в комнате' },
{ id:'a3', cat:'med', html:'Сахар в горячем чае' },
{ id:'a4', cat:'med', html:'Раствор соли в воде' },
{ id:'a5', cat:'slow', html:'Сварка металлов' },
{ id:'a6', cat:'slow', html:'Свинцовая пломба со временем «врастает» в дерево' }
], [
{ cat:'fast', label:'Быстро (газ)' },
{ cat:'med', label:'Средне (жидкость)' },
{ cat:'slow', label:'Медленно (твёрдое)' }
]));
/* IV-4: тренажёр */
h += wgWrap('p9-iv4', 'ТРН', 'Тренажёр §9', '5 вопросов.',
'<div id="p9-tr-host">'
+ quizQuestion('p9-tr', 0, 'Тепловое движение — это…', ['Падение тел','Движение колеса','Хаотическое движение молекул','Движение звуковой волны'], 2)
+ quizQuestion('p9-tr', 1, 'При нагревании средняя скорость молекул…', ['Не меняется','Увеличивается','Уменьшается','Становится нулевой'], 1)
+ quizQuestion('p9-tr', 2, 'В каком случае диффузия пройдёт быстрее: в холодной или горячей воде?', ['В холодной','В горячей','Одинаково','Не зависит'], 1)
+ quizQuestion('p9-tr', 3, 'Через сколько примерно времени запах из открытого флакона духов распространится по комнате?', ['Доли секунды','За минуту-две','За сутки','За месяц'], 1, 'Диффузия в газе — относительно быстрая, но мгновенной не бывает.')
+ quizQuestion('p9-tr', 4, 'Броуновское движение — это движение…', ['Молекул','Атомов','Мельчайших видимых частиц под ударами молекул','Звуковых волн'], 2)
+ '</div>');
h += readButton('p9');
body.innerHTML = h;
// Diffusion sim
const sim = (function(){
const W = 360, H = 160;
const N = 60;
const parts = [];
function init(){
parts.length = 0;
for(let i = 0; i < N; i++){
const isInk = i < 20;
parts.push({
x: isInk ? (40 + Math.random() * 60) : (Math.random() * W),
y: isInk ? (40 + Math.random() * 60) : (Math.random() * H),
vx: 0, vy: 0,
ink: isInk
});
}
}
function step(T){
const speed = 0.4 + T / 30; // px/frame
parts.forEach(p => {
p.vx += (Math.random() - 0.5) * speed * 0.6;
p.vy += (Math.random() - 0.5) * speed * 0.6;
p.vx *= 0.92; p.vy *= 0.92;
p.x += p.vx; p.y += p.vy;
if(p.x < 2){ p.x = 2; p.vx = -p.vx; }
if(p.x > W-2){ p.x = W-2; p.vx = -p.vx; }
if(p.y < 2){ p.y = 2; p.vy = -p.vy; }
if(p.y > H-2){ p.y = H-2; p.vy = -p.vy; }
});
}
function render(){
const svg = document.getElementById('p9-sim');
if(!svg) return false;
let s = '';
parts.forEach(p => {
const c = p.ink ? '#0f172a' : '#3b82f6';
s += '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="' + (p.ink ? 3 : 2) + '" fill="' + c + '" opacity="' + (p.ink ? 0.9 : 0.55) + '"/>';
});
svg.innerHTML = s;
return true;
}
return { init, step, render };
})();
let raf = 0;
function loop(){
const T = +document.getElementById('p9-T-r').value;
sim.step(T);
if(!sim.render()){ cancelAnimationFrame(raf); return; }
raf = requestAnimationFrame(loop);
}
sim.init();
raf = requestAnimationFrame(loop);
document.getElementById('p9-T-r').addEventListener('input', () => {
document.getElementById('p9-T').textContent = document.getElementById('p9-T-r').value;
});
document.getElementById('p9-reset').addEventListener('click', () => { sim.init(); });
wireDnd('p9-dnd', [
{ id:'a1', cat:'fast' },{ id:'a2', cat:'fast' },{ id:'a3', cat:'med' },{ id:'a4', cat:'med' },
{ id:'a5', cat:'slow' },{ id:'a6', cat:'slow' }
]);
wireQuiz('p9-q-host', () => { if(window.addXp) window.addXp(10, 'q-p9'); });
wireQuiz('p9-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p9'); });
wireReadBtn('p9');
renderMath(body);
}
/* ========================================================== */
/* §10 — Взаимодействие частиц вещества */
/* ========================================================== */
function add_p10(){
const body = document.getElementById('p10-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Два вида сил между частицами', '§ 10.1',
'Между молекулами одновременно действуют <b>силы притяжения</b> и <b>силы отталкивания</b>. '
+ 'Их интенсивность зависит от расстояния:'
+ '<ul style="padding-left:20px;margin:6px 0">'
+ '<li>на <b>малом</b> расстоянии (молекулы «прижаты») — преобладает <b>отталкивание</b>;</li>'
+ '<li>на <b>равновесном</b> расстоянии $r_0$ — силы уравновешиваются;</li>'
+ '<li>на <b>большом</b> расстоянии — преобладает <b>притяжение</b>;</li>'
+ '<li>на <b>очень большом</b> — силы пренебрежимо малы.</li>'
+ '</ul>');
h += makeCard('rule', 'Зачем нужно знать про эти силы', '§ 10.2',
'Силы между молекулами объясняют:'
+ '<ul style="padding-left:20px;margin:5px 0">'
+ '<li>почему <b>твёрдые</b> тела сохраняют форму (сильное притяжение),</li>'
+ '<li>почему трудно <b>растянуть</b> стальной трос (надо преодолеть притяжение),</li>'
+ '<li>почему трудно <b>сжать</b> жидкость (молекулы уже близко — мешает отталкивание),</li>'
+ '<li>почему <b>пружина</b> возвращается в исходное положение — силы упругости имеют ту же природу.</li>'
+ '</ul>');
h += makeCard('example', 'Опыт с свинцовыми цилиндрами', '§ 10.3',
'Если две тщательно отшлифованные свинцовые поверхности сжать вместе, '
+ 'они <b>«слипнутся»</b> — их можно даже подвесить на крючок, и они не разойдутся. '
+ 'Причина — притяжение молекул на малом расстоянии. '
+ 'Через грязный или окисленный слой это не работает: молекулы не подходят достаточно близко.');
/* IV-1: график F(r) */
h += wgWrap('p10-iv1', 'СИМ', 'График сил F(r) — притяжение и отталкивание', 'Двигай молекулу — увидь, какая сила преобладает.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Расстояние $r/r_0$: <b id="p10-r" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">1.00</b><input type="range" id="p10-r-r" min="60" max="250" step="2" value="100" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<svg id="p10-svg" viewBox="0 0 380 200" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p10-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.94rem;text-align:center"></div>');
/* IV-2: квиз */
h += wgWrap('p10-iv2', 'КВИЗ', 'Силы взаимодействия', 'Выбери верное.',
'<div id="p10-q-host">'
+ quizQuestion('p10-q', 0, 'На равновесном расстоянии $r_0$ молекулы…', ['Только притягиваются','Только отталкиваются','Притяжение и отталкивание равны','Не взаимодействуют'], 2)
+ quizQuestion('p10-q', 1, 'Почему трудно сжать жидкость?', ['Молекул мало','Молекулы уже близко — мешает отталкивание','Жидкость не имеет молекул','Притяжение слишком сильно'], 1)
+ quizQuestion('p10-q', 2, 'Почему пружина возвращается в исходную форму?', ['Из-за гравитации','Из-за сил между молекулами','Сама по себе','Из-за воздуха'], 1)
+ quizQuestion('p10-q', 3, 'На очень большом расстоянии межмолекулярные силы…', ['Очень большие','Пренебрежимо малы','Отталкивают','Колеблются'], 1)
+ '</div>');
/* IV-3: DnD */
h += wgWrap('p10-iv3', 'DnD', 'Преобладает что?', 'Сопоставь расстояние и преобладающую силу.',
dndPool('p10-dnd', [
{ id:'a1', cat:'rep', html:'Молекулы прижаты вплотную' },
{ id:'a2', cat:'rep', html:'Жидкость сжимают поршнем' },
{ id:'a3', cat:'eq', html:'$r = r_0$ (равновесие)' },
{ id:'a4', cat:'attr', html:'Растягивание стального троса' },
{ id:'a5', cat:'attr', html:'Молекулы немного раздвинуты' },
{ id:'a6', cat:'zero', html:'$r \\gg r_0$ (далеко)' }
], [
{ cat:'rep', label:'Отталкивание' },
{ cat:'eq', label:'Равновесие' },
{ cat:'attr', label:'Притяжение' },
{ cat:'zero', label:'Силы малы' }
]));
/* IV-4: тренажёр */
h += wgWrap('p10-iv4', 'ТРН', 'Тренажёр §10', '4 вопроса.',
'<div id="p10-tr-host">'
+ quizQuestion('p10-tr', 0, 'Между молекулами действуют…', ['Только притяжение','Только отталкивание','И притяжение, и отталкивание','Никаких сил'], 2)
+ quizQuestion('p10-tr', 1, 'Если молекулы оказались ближе $r_0$, то результирующая сила…', ['Отталкивает','Притягивает','Равна нулю','Не определена'], 0)
+ quizQuestion('p10-tr', 2, 'Опыт со свинцовыми цилиндрами показывает…', ['Что вещество твёрдое','Что молекулы притягиваются на близком расстоянии','Что свинец тяжёлый','Что молекулы движутся'], 1)
+ quizQuestion('p10-tr', 3, 'Силы упругости имеют ту же природу, что и…', ['Сила трения','Гравитация','Силы между молекулами','Электромагнитные волны'], 2)
+ '</div>');
h += readButton('p10');
body.innerHTML = h;
function drawF(){
const rRel = +document.getElementById('p10-r-r').value / 100; // r/r0 from 0.6 to 2.5
document.getElementById('p10-r').textContent = rRel.toFixed(2);
const W = 380, H = 200, pad = 30;
// Чертим оси r (x) и F (y)
// F(r) модельная: F = a/r^13 - b/r^7 (Lennard-Jones-like), минимум в r=1.
function F(r){ return 12/Math.pow(r,13) - 12/Math.pow(r,7); }
let s = '';
// Оси
s += '<line x1="' + pad + '" y1="' + (H/2) + '" x2="' + (W-pad+10) + '" y2="' + (H/2) + '" stroke="#0f172a" stroke-width="1.5"/>';
s += '<line x1="' + pad + '" y1="20" x2="' + pad + '" y2="' + (H-20) + '" stroke="#0f172a" stroke-width="1.5"/>';
s += '<text x="' + (W-pad+8) + '" y="' + (H/2 + 12) + '" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">r</text>';
s += '<text x="' + (pad+4) + '" y="20" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">F</text>';
// r=r0
const r0X = pad + (W - 2*pad) * (1 - 0.6) / (2.5 - 0.6);
s += '<line x1="' + r0X.toFixed(1) + '" y1="20" x2="' + r0X.toFixed(1) + '" y2="' + (H-20) + '" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3 2"/>';
s += '<text x="' + r0X.toFixed(1) + '" y="' + (H-6) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" fill="#64748b">r₀</text>';
// Кривая F(r)
let path = '';
for(let i = 0; i <= 60; i++){
const r = 0.6 + (2.5 - 0.6) * i / 60;
const f = F(r);
const fClamped = Math.max(-2, Math.min(4, f));
const x = pad + (W - 2*pad) * (r - 0.6) / (2.5 - 0.6);
const y = H/2 - fClamped * 18;
path += (i === 0 ? 'M' : 'L') + x.toFixed(1) + ' ' + y.toFixed(1) + ' ';
}
s += '<path d="' + path + '" fill="none" stroke="' + ACCENT + '" stroke-width="2.5"/>';
// Текущая точка
const curX = pad + (W - 2*pad) * (rRel - 0.6) / (2.5 - 0.6);
const curF = Math.max(-2, Math.min(4, F(rRel)));
const curY = H/2 - curF * 18;
s += '<circle cx="' + curX.toFixed(1) + '" cy="' + curY.toFixed(1) + '" r="6" fill="#dc2626" stroke="#fff" stroke-width="2"/>';
s += '<line x1="' + curX.toFixed(1) + '" y1="' + (H/2) + '" x2="' + curX.toFixed(1) + '" y2="' + curY.toFixed(1) + '" stroke="#dc2626" stroke-width="1.5" stroke-dasharray="2 2"/>';
// Подписи областей
s += '<text x="' + (pad + 30) + '" y="40" font-family="Inter,sans-serif" font-size="10" fill="#dc2626" font-weight="700">отталкивание</text>';
s += '<text x="' + (W - pad - 60) + '" y="' + (H - 40) + '" font-family="Inter,sans-serif" font-size="10" fill="#10b981" font-weight="700">притяжение</text>';
document.getElementById('p10-svg').innerHTML = s;
// Info
const fVal = F(rRel);
let label;
if(rRel < 0.95) label = '<b style="color:#dc2626">Отталкивание</b> (молекулы слишком близко).';
else if(rRel < 1.05) label = '<b style="color:#0c4a6e">Равновесие</b>: силы уравновешены, $F \\approx 0$.';
else if(rRel < 1.6) label = '<b style="color:#10b981">Притяжение</b> (молекулы стремятся вернуться).';
else label = '<b style="color:#64748b">Силы малы</b>: молекулы почти не взаимодействуют.';
document.getElementById('p10-info').innerHTML = '$r/r_0 = ' + rRel.toFixed(2) + '$ &nbsp;&middot;&nbsp; ' + label;
renderMath(document.getElementById('p10-info'));
}
document.getElementById('p10-r-r').addEventListener('input', drawF);
drawF();
wireDnd('p10-dnd', [
{ id:'a1', cat:'rep' },{ id:'a2', cat:'rep' },{ id:'a3', cat:'eq' },
{ id:'a4', cat:'attr' },{ id:'a5', cat:'attr' },{ id:'a6', cat:'zero' }
]);
wireQuiz('p10-q-host', () => { if(window.addXp) window.addXp(10, 'q-p10'); });
wireQuiz('p10-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p10'); });
wireReadBtn('p10');
renderMath(body);
}
/* ========================================================== */
/* §11 — Газообразное, жидкое, твёрдое состояния */
/* ГЛАВНЫЙ ВИЗУАЛ ГЛАВЫ 2: переключатель состояний с анимацией */
/* ========================================================== */
function add_p11(){
const body = document.getElementById('p11-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Три состояния — три поведения частиц', '§ 11.1',
'<b>Одно и то же вещество</b> может находиться в трёх состояниях. Различие — в том, '
+ 'как расположены и движутся его молекулы:'
+ '<table style="width:100%;border-collapse:collapse;margin-top:8px;font-size:.92rem">'
+ '<tr style="background:' + ACCENT_SOFT + '"><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Состояние</th><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Форма</th><th style="padding:6px 10px;text-align:left;border-bottom:2px solid ' + ACCENT + '">Объём</th></tr>'
+ '<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '"><b>Твёрдое</b></td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">сохраняет</td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">сохраняет</td></tr>'
+ '<tr><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '"><b>Жидкое</b></td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">принимает форму сосуда</td><td style="padding:5px 10px;border-bottom:1px solid ' + ACCENT_SOFT + '">сохраняет</td></tr>'
+ '<tr><td style="padding:5px 10px"><b>Газообразное</b></td><td style="padding:5px 10px">заполняет весь сосуд</td><td style="padding:5px 10px">не сохраняет</td></tr>'
+ '</table>');
h += makeCard('rule', 'Чем отличается поведение молекул', '§ 11.2',
'<ul style="padding-left:20px;margin:6px 0;line-height:1.7">'
+ '<li><b>Твёрдое</b>: молекулы в узлах кристаллической решётки; колеблются около положений равновесия. Притяжение сильное.</li>'
+ '<li><b>Жидкое</b>: молекулы упакованы плотно, но <i>«перескакивают»</i> с места на место. Промежутки малы — несжимаема, но течёт.</li>'
+ '<li><b>Газообразное</b>: молекулы летают почти свободно на больших расстояниях. Силы притяжения слабые. Газ занимает <b>весь</b> предоставленный объём.</li>'
+ '</ul>');
h += makeCard('example', 'Вода — все три состояния', '§ 11.3',
'Удивительно: одна и та же $\\text{H}_2\\text{O}$ существует во всех трёх состояниях:'
+ '<ul style="padding-left:20px;margin:6px 0">'
+ '<li><b>Лёд</b> (твёрдое) — при $t < 0$ °C. Сохраняет форму, можно расколоть.</li>'
+ '<li><b>Вода</b> (жидкое) — от $0$ до $100$ °C. Принимает форму сосуда.</li>'
+ '<li><b>Пар</b> (газообразное) — при $t > 100$ °C. Заполняет всё пространство.</li>'
+ '</ul>'
+ 'Сами молекулы при переходе <b>не меняются</b> — меняется лишь характер их движения и расположения.');
/* IV-1: ГЛАВНЫЙ ВИЗУАЛ — переключатель 3 состояний с симуляцией МКТ */
h += wgWrap('p11-iv1', 'СИМ', 'Молекулы в трёх состояниях', 'Переключай состояние — смотри, как меняется поведение частиц.',
'<div style="display:flex;gap:6px;margin-bottom:10px;flex-wrap:wrap">'
+ ['solid','liquid','gas'].map((st, i) => {
const labels = ['Твёрдое', 'Жидкое', 'Газ'];
const colors = ['#4f46e5', '#0891b2', '#94a3b8'];
return '<button class="p11-st" data-st="' + st + '" type="button" style="background:#fff;border:2px solid ' + colors[i] + ';color:' + colors[i] + ';padding:8px 18px;border-radius:9px;cursor:pointer;font-weight:700;font-size:.9rem;font-family:inherit">' + labels[i] + '</button>';
}).join('')
+ '</div>'
+ '<svg id="p11-sim" viewBox="0 0 360 180" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p11-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.92rem;line-height:1.55"></div>');
/* IV-2: квиз */
h += wgWrap('p11-iv2', 'КВИЗ', 'Свойства состояний', '',
'<div id="p11-q-host">'
+ quizQuestion('p11-q', 0, 'Какое состояние сохраняет и форму, и объём?', ['Твёрдое','Жидкое','Газообразное','Все три'], 0)
+ quizQuestion('p11-q', 1, 'Газ занимает…', ['Только дно сосуда','Половину сосуда','Весь сосуд','Часть, равную массе'], 2)
+ quizQuestion('p11-q', 2, 'Жидкость принимает форму…', ['Любую','Сосуда','Кубическую','Шарообразную'], 1)
+ quizQuestion('p11-q', 3, 'В каком состоянии молекулы движутся быстрее всего?', ['В твёрдом','В жидком','В газообразном','Одинаково'], 2)
+ '</div>');
/* IV-3: DnD */
h += wgWrap('p11-iv3', 'DnD', 'Что в каком состоянии?', 'Распредели 9 примеров.',
dndPool('p11-dnd', [
{ id:'a1', cat:'sol', html:'Камень' },
{ id:'a2', cat:'sol', html:'Лёд' },
{ id:'a3', cat:'sol', html:'Железо' },
{ id:'a4', cat:'liq', html:'Молоко' },
{ id:'a5', cat:'liq', html:'Бензин' },
{ id:'a6', cat:'liq', html:'Расплавленный воск' },
{ id:'a7', cat:'gas', html:'Воздух' },
{ id:'a8', cat:'gas', html:'Водяной пар' },
{ id:'a9', cat:'gas', html:'Углекислый газ' }
], [
{ cat:'sol', label:'Твёрдое' },
{ cat:'liq', label:'Жидкое' },
{ cat:'gas', label:'Газообразное' }
]));
/* IV-4: тренажёр */
h += wgWrap('p11-iv4', 'ТРН', 'Тренажёр §11', '5 вопросов.',
'<div id="p11-tr-host">'
+ quizQuestion('p11-tr', 0, 'Можно ли сжать газ в 2 раза в плотно закрытом шприце?', ['Нет','Да, легко','Только при высокой температуре','Только при очень низкой'], 1)
+ quizQuestion('p11-tr', 1, 'Жидкость практически не сжимается, потому что…', ['Молекул мало','Молекулы уже плотно упакованы','Жидкости лёгкие','Молекулы неподвижны'], 1)
+ quizQuestion('p11-tr', 2, 'В каком состоянии вещества молекулы располагаются в строгом порядке (кристалл)?', ['Твёрдое','Жидкое','Газообразное','Ни в каком'], 0)
+ quizQuestion('p11-tr', 3, 'При переходе из льда в воду молекулы $\\text{H}_2\\text{O}$…', ['Распадаются','Превращаются в другие','Остаются теми же, меняется лишь их движение','Исчезают'], 2)
+ quizQuestion('p11-tr', 4, '$0{,}5$ л воды налили в банку $1$ л. Какой объём займёт вода?', ['0,5 л','1 л','0,75 л','Зависит от формы'], 0, 'Жидкость сохраняет свой объём — только форму она меняет.')
+ '</div>');
h += readButton('p11');
body.innerHTML = h;
// Wire 3-state simulator
const st11 = (function(){
const W = 360, H = 180, N = 50;
let state = 'solid';
const parts = [];
for(let i = 0; i < N; i++) parts.push({ x:0, y:0, vx:0, vy:0, hx:0, hy:0 });
function reset(){
if(state === 'solid'){
// Кристаллическая решётка 10×5
for(let i = 0; i < N; i++){
const r = Math.floor(i/10), c = i % 10;
parts[i].hx = 40 + c * 28;
parts[i].hy = 40 + r * 28;
parts[i].x = parts[i].hx; parts[i].y = parts[i].hy;
parts[i].vx = 0; parts[i].vy = 0;
}
} else if(state === 'liquid'){
// Жидкость — занимает нижнюю половину
for(let i = 0; i < N; i++){
parts[i].x = 20 + Math.random() * (W - 40);
parts[i].y = H/2 + Math.random() * (H/2 - 10);
parts[i].vx = (Math.random() - 0.5) * 1;
parts[i].vy = (Math.random() - 0.5) * 1;
}
} else { // gas
for(let i = 0; i < N; i++){
parts[i].x = 10 + Math.random() * (W - 20);
parts[i].y = 10 + Math.random() * (H - 20);
const ang = Math.random() * Math.PI * 2;
parts[i].vx = Math.cos(ang) * 2.5;
parts[i].vy = Math.sin(ang) * 2.5;
}
}
}
function step(){
if(state === 'solid'){
for(let i = 0; i < N; i++){
parts[i].x = parts[i].hx + (Math.random() - 0.5) * 3;
parts[i].y = parts[i].hy + (Math.random() - 0.5) * 3;
}
} else if(state === 'liquid'){
for(let i = 0; i < N; i++){
parts[i].vx += (Math.random() - 0.5) * 0.3;
parts[i].vy += (Math.random() - 0.5) * 0.3;
parts[i].vx *= 0.93; parts[i].vy *= 0.93;
parts[i].x += parts[i].vx; parts[i].y += parts[i].vy;
// Притяжение к дну (как жидкость)
parts[i].vy += 0.1;
if(parts[i].x < 6){ parts[i].x = 6; parts[i].vx = -parts[i].vx; }
if(parts[i].x > W-6){ parts[i].x = W-6; parts[i].vx = -parts[i].vx; }
if(parts[i].y < H/2 + 6){ parts[i].y = H/2 + 6; parts[i].vy = Math.abs(parts[i].vy)*0.5; }
if(parts[i].y > H-6){ parts[i].y = H-6; parts[i].vy = -Math.abs(parts[i].vy)*0.7; }
}
} else {
for(let i = 0; i < N; i++){
parts[i].x += parts[i].vx; parts[i].y += parts[i].vy;
if(parts[i].x < 6){ parts[i].x = 6; parts[i].vx = -parts[i].vx; }
if(parts[i].x > W-6){ parts[i].x = W-6; parts[i].vx = -parts[i].vx; }
if(parts[i].y < 6){ parts[i].y = 6; parts[i].vy = -parts[i].vy; }
if(parts[i].y > H-6){ parts[i].y = H-6; parts[i].vy = -parts[i].vy; }
}
}
}
function render(){
const svg = document.getElementById('p11-sim');
if(!svg) return false;
let s = '';
// Контур сосуда
s += '<rect x="2" y="2" width="' + (W-4) + '" height="' + (H-4) + '" fill="none" stroke="' + ACCENT_D + '" stroke-width="1.5" stroke-dasharray="4 3" rx="6"/>';
// Уровень жидкости — линия
if(state === 'liquid'){
s += '<line x1="3" y1="' + (H/2) + '" x2="' + (W-3) + '" y2="' + (H/2) + '" stroke="#0891b2" stroke-width="1.5"/>';
}
const col = state === 'solid' ? '#4f46e5' : (state === 'liquid' ? '#0891b2' : '#64748b');
parts.forEach(p => {
s += '<circle cx="' + p.x.toFixed(1) + '" cy="' + p.y.toFixed(1) + '" r="4" fill="' + col + '" stroke="#0f172a" stroke-width="0.6" opacity="0.9"/>';
});
svg.innerHTML = s;
return true;
}
return {
setState(st){ state = st; reset(); updateInfo(); },
step, render, getState(){ return state; }
};
})();
function updateInfo(){
const st = st11.getState();
const descs = {
solid: '<b style="color:#4f46e5">Твёрдое:</b> молекулы в узлах решётки, только колеблются. Форма и объём сохраняются.',
liquid: '<b style="color:#0891b2">Жидкость:</b> молекулы плотно упакованы и «перескакивают». Объём сохраняется, форма — нет.',
gas: '<b style="color:#64748b">Газ:</b> молекулы летают свободно. Ни форма, ни объём не сохраняются — газ занимает весь сосуд.'
};
document.getElementById('p11-info').innerHTML = descs[st];
}
body.querySelectorAll('.p11-st').forEach(btn => btn.addEventListener('click', () => {
body.querySelectorAll('.p11-st').forEach(b => { b.style.background = '#fff'; b.style.color = b.style.borderColor; });
btn.style.background = btn.style.borderColor; btn.style.color = '#fff';
st11.setState(btn.dataset.st);
}));
st11.setState('solid');
body.querySelector('.p11-st[data-st="solid"]').style.background = '#4f46e5';
body.querySelector('.p11-st[data-st="solid"]').style.color = '#fff';
let raf11 = 0;
function loop11(){
st11.step();
if(!st11.render()){ cancelAnimationFrame(raf11); return; }
raf11 = requestAnimationFrame(loop11);
}
raf11 = requestAnimationFrame(loop11);
wireDnd('p11-dnd', [
{ id:'a1', cat:'sol' },{ id:'a2', cat:'sol' },{ id:'a3', cat:'sol' },
{ id:'a4', cat:'liq' },{ id:'a5', cat:'liq' },{ id:'a6', cat:'liq' },
{ id:'a7', cat:'gas' },{ id:'a8', cat:'gas' },{ id:'a9', cat:'gas' }
]);
wireQuiz('p11-q-host', () => { if(window.addXp) window.addXp(10, 'q-p11'); });
wireQuiz('p11-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p11'); });
wireReadBtn('p11');
renderMath(body);
}
/* ========================================================== */
/* §12 — Тепловое расширение */
/* ========================================================== */
function add_p12(){
const body = document.getElementById('p12-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Почему тела расширяются при нагреве', '§ 12.1',
'При нагревании молекулы движутся быстрее и амплитуда их колебаний возрастает. '
+ 'Среднее расстояние между молекулами <b>увеличивается</b> — тело расширяется. '
+ 'При охлаждении наоборот: тело сжимается.<br><br>'
+ 'Тепловое расширение есть у <b>всех</b> веществ — твёрдых, жидких и газообразных. '
+ 'Сильнее всех расширяются газы, меньше всех — твёрдые тела.');
h += makeCard('rule', 'Где это важно учитывать', '§ 12.2',
'<ul style="padding-left:20px;margin:6px 0">'
+ '<li><b>Рельсы</b> укладывают с зазорами — летом сталь удлиняется.</li>'
+ '<li><b>Мосты</b> опирают через катки или прокладки — иначе бы трескались.</li>'
+ '<li><b>Провода ЛЭП</b> летом провисают сильнее, чем зимой.</li>'
+ '<li><b>Биметаллическая пластина</b> — два металла спаяны вместе, гнётся от температуры. Используется в утюгах и термостатах.</li>'
+ '</ul>');
h += makeCard('example', 'Аномалия воды', '§ 12.3',
'Большинство веществ при нагревании расширяются. Но у воды есть <b>исключение</b>: '
+ 'при $t$ от $0$ до $+4$ °C она <b>сжимается</b>, а только начиная с $+4$ °C — расширяется. '
+ 'Поэтому самая плотная вода — при $+4$ °C; она опускается на дно водоёма. '
+ 'Это <b>спасает</b> жизнь в озёрах зимой: лёд плавает сверху, а под ним вода с $+4$ °C, где могут жить рыбы.');
/* IV-1: расширение стержня + биметалла */
h += wgWrap('p12-iv1', 'СИМ', 'Тепловое расширение стержня', 'Меняй температуру — наблюдай длину.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Нагрев $\\Delta T$, °C: <b id="p12-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">50</b><input type="range" id="p12-T-r" min="0" max="200" step="5" value="50" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<svg id="p12-svg" viewBox="0 0 380 140" width="100%" style="max-width:600px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div id="p12-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:10px 14px;margin-top:8px;font-size:.9rem;text-align:center"></div>');
/* IV-2: биметалл */
h += wgWrap('p12-iv2', 'СИМ', 'Биметаллическая пластина', 'Два металла расширяются по-разному — пластина гнётся.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Нагрев $\\Delta T$, °C: <b id="p12b-T" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">60</b><input type="range" id="p12b-T-r" min="-50" max="100" step="5" value="60" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<svg id="p12b-svg" viewBox="0 0 280 200" width="100%" style="max-width:400px;display:block;margin:0 auto;background:#faf5ff;border-radius:9px;border:1px solid ' + ACCENT_SOFT + '"></svg>'
+ '<div style="text-align:center;font-size:.84rem;color:#64748b;margin-top:6px">Жёлтый слой — латунь (сильнее расширяется), серый — сталь. Принцип термостата.</div>');
/* IV-3: DnD */
h += wgWrap('p12-iv3', 'DnD', 'Кто сильнее расширяется?', 'Расставь по убыванию теплового расширения.',
dndPool('p12-dnd', [
{ id:'a1', cat:'gas', html:'Воздух в шарике' },
{ id:'a2', cat:'gas', html:'Гелий в баллоне' },
{ id:'a3', cat:'liq', html:'Спирт в термометре' },
{ id:'a4', cat:'liq', html:'Ртуть в термометре' },
{ id:'a5', cat:'sol', html:'Железный рельс' },
{ id:'a6', cat:'sol', html:'Кварцевое стекло' }
], [
{ cat:'gas', label:'Сильно (газ)' },
{ cat:'liq', label:'Средне (жидкость)' },
{ cat:'sol', label:'Слабо (твёрдое)' }
]));
/* IV-4: тренажёр */
h += wgWrap('p12-iv4', 'ТРН', 'Тренажёр §12', '5 вопросов.',
'<div id="p12-tr-host">'
+ quizQuestion('p12-tr', 0, 'Почему между рельсами оставляют зазоры?', ['Для экономии металла','Чтобы рельсы могли расширяться летом','Для прохода животных','Не оставляют, это миф'], 1)
+ quizQuestion('p12-tr', 1, 'При охлаждении тело…', ['Расширяется','Сжимается','Не меняется','Может то и другое'], 1)
+ quizQuestion('p12-tr', 2, 'У какой воды максимальная плотность?', ['При 0 °C','При +4 °C','При +100 °C','Не зависит от t'], 1, 'Это уникальная аномалия воды — спасает водоёмы зимой.')
+ quizQuestion('p12-tr', 3, 'Биметаллическая пластина при нагревании…', ['Не изменяется','Гнётся в одну сторону','Гнётся в случайную сторону','Распадается'], 1, 'Один металл расширяется сильнее, и пластина изгибается.')
+ quizQuestion('p12-tr', 4, 'Что сильнее расширяется при $\\Delta T = 50$ °C?', ['Стальной стержень','Воздушный шарик','Кварц','Лёд'], 1, 'Газы расширяются в сотни раз сильнее твёрдых тел.')
+ '</div>');
h += readButton('p12');
body.innerHTML = h;
// §12 IV-1
function drawRod(){
const dT = +document.getElementById('p12-T-r').value;
document.getElementById('p12-T').textContent = dT;
const W = 380, baseLen = 200, alpha = 12e-6; // сталь
const dl = baseLen * alpha * dT * 200; // визуально усилено
const len = baseLen + dl;
const y = 60, h = 22;
const x = 30;
// Цвет = функция температуры (0..200 → синий → красный)
const hue = 240 - 240 * Math.min(1, dT / 200);
const col = 'hsl(' + hue + ',70%,55%)';
let s = '';
// Базовая длина — пунктир
s += '<rect x="' + x + '" y="' + (y-3) + '" width="' + baseLen + '" height="' + (h+6) + '" fill="none" stroke="#94a3b8" stroke-width="1" stroke-dasharray="3 2" rx="3"/>';
// Реальный стержень
s += '<rect x="' + x + '" y="' + y + '" width="' + len.toFixed(1) + '" height="' + h + '" fill="' + col + '" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
// Подписи
s += '<text x="' + (x + baseLen/2) + '" y="' + (y - 8) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" fill="#64748b">базовая длина (при 0 °C)</text>';
if(Math.abs(dl) > 1){
s += '<line x1="' + (x + baseLen) + '" y1="' + (y + h + 8) + '" x2="' + (x + len) + '" y2="' + (y + h + 8) + '" stroke="#dc2626" stroke-width="2"/>';
s += '<text x="' + (x + baseLen + dl/2) + '" y="' + (y + h + 24) + '" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#dc2626">Δl = ' + dl.toFixed(1) + ' px</text>';
}
document.getElementById('p12-svg').innerHTML = s;
const realDl = (baseLen * alpha * dT * 100).toFixed(3); // реалистично в мм для l0=1 м
document.getElementById('p12-info').innerHTML = 'Сталь, $l_0 = 1$ м, нагрев на $\\Delta T = ' + dT + '$ °C: реально удлинится примерно на $' + (alpha * 1000 * dT).toFixed(3) + '$ мм (масштаб усилен).';
renderMath(document.getElementById('p12-info'));
}
document.getElementById('p12-T-r').addEventListener('input', drawRod);
drawRod();
// §12 IV-2 биметалл
function drawBimet(){
const dT = +document.getElementById('p12b-T-r').value;
document.getElementById('p12b-T').textContent = dT;
const ang = Math.max(-30, Math.min(30, -dT * 0.3));
const cx = 140, cy = 50;
let s = '';
// Опора
s += '<rect x="' + (cx - 30) + '" y="' + (cy - 8) + '" width="60" height="8" fill="#475569" stroke="#0f172a" stroke-width="1"/>';
// Пластина с поворотом
s += '<g transform="translate(' + cx + ',' + cy + ') rotate(' + ang + ')">';
s += '<rect x="0" y="0" width="120" height="10" fill="#fbbf24" stroke="#92400e" stroke-width="1"/>';
s += '<rect x="0" y="10" width="120" height="10" fill="#94a3b8" stroke="#374151" stroke-width="1"/>';
s += '<text x="60" y="38" text-anchor="middle" font-family="Inter,sans-serif" font-size="10" font-weight="600" fill="#374151">Δt = ' + dT + ' °C</text>';
s += '</g>';
// Подписи цветов
s += '<rect x="10" y="180" width="14" height="6" fill="#fbbf24"/>';
s += '<text x="28" y="187" font-family="Inter,sans-serif" font-size="9" fill="#374151">латунь (сильнее расширяется)</text>';
s += '<rect x="10" y="190" width="14" height="6" fill="#94a3b8"/>';
s += '<text x="28" y="197" font-family="Inter,sans-serif" font-size="9" fill="#374151">сталь</text>';
document.getElementById('p12b-svg').innerHTML = s;
}
document.getElementById('p12b-T-r').addEventListener('input', drawBimet);
drawBimet();
wireDnd('p12-dnd', [
{ id:'a1', cat:'gas' },{ id:'a2', cat:'gas' },{ id:'a3', cat:'liq' },
{ id:'a4', cat:'liq' },{ id:'a5', cat:'sol' },{ id:'a6', cat:'sol' }
]);
wireQuiz('p12-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p12'); });
wireReadBtn('p12');
renderMath(body);
}
/* ========================================================== */
/* §13 — Температура. Термометры */
/* ========================================================== */
function add_p13(){
const body = document.getElementById('p13-body');
if(!body) return;
let h = '';
h += makeCard('theory', 'Что такое температура', '§ 13.1',
'<b>Температура</b> — физическая величина, которая характеризует степень нагретости тела. '
+ 'Чем быстрее в среднем движутся молекулы — тем выше температура.<br><br>'
+ 'Обозначается $t$ (или $T$), измеряется в <b>градусах Цельсия</b> ($°C$). '
+ 'В физике также используют <b>Кельвины</b> ($K$); связь: $T = t + 273{,}15$.');
h += makeCard('rule', 'Шкала Цельсия', '§ 13.2',
'Шкала строится по двум опорным точкам:'
+ '<ul style="padding-left:20px;margin:6px 0">'
+ '<li><b>$0$ °C</b> — температура таяния льда (при нормальном давлении);</li>'
+ '<li><b>$100$ °C</b> — температура кипения чистой воды (при нормальном давлении).</li>'
+ '</ul>'
+ 'Промежуток разбит на $100$ равных частей — отсюда «градус Цельсия».');
h += makeCard('example', 'Виды термометров', '§ 13.3',
'<ul style="padding-left:20px;margin:6px 0">'
+ '<li><b>Жидкостный</b> (спирт, ртуть) — расширение жидкости в капилляре. От $-40$ до $+50$ °C — бытовой; до $+300$ °C — ртутный лабораторный.</li>'
+ '<li><b>Биметаллический</b> — стрелка двигается за счёт изгиба пластины. На печках, духовках.</li>'
+ '<li><b>Электронный</b> — термопара или термистор + дисплей. От $-200$ до $+1000$ °C.</li>'
+ '<li><b>Инфракрасный (пирометр)</b> — измеряет тепловое излучение без контакта. До тысяч °C.</li>'
+ '</ul>');
/* IV-1: виртуальный термометр */
h += wgWrap('p13-iv1', 'СИМ', 'Виртуальный термометр', 'Двигай слайдер — наблюдай столбик и сравнивай с реальными ситуациями.',
'<div style="margin-bottom:10px"><label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">Температура $t$, °C: <b id="p13-t" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">22</b><input type="range" id="p13-t-r" min="-50" max="150" step="1" value="22" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label></div>'
+ '<div style="display:grid;grid-template-columns:140px 1fr;gap:14px;align-items:center">'
+ '<svg id="p13-svg" viewBox="0 0 100 220" width="100%" style="max-width:140px"></svg>'
+ '<div id="p13-info" style="background:' + ACCENT_SOFT + ';border-radius:9px;padding:12px 14px;font-size:.92rem;line-height:1.65"></div>'
+ '</div>');
/* IV-2: конвертер °C ↔ K */
h += wgWrap('p13-iv2', 'КАЛЬК', 'Конвертер °C ↔ K', 'Кельвин и Цельсий — две шкалы для одной температуры.',
'<div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-bottom:10px">'
+ '<label style="display:block;font-size:.86rem;color:#475569;background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + '">$t$, °C: <b id="p13c-c" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">25</b><input type="range" id="p13c-c-r" min="-273" max="500" step="1" value="25" style="display:block;width:100%;margin-top:6px;accent-color:' + ACCENT + '"></label>'
+ '<div style="background:#fff;padding:8px 12px;border-radius:8px;border:1px solid ' + ACCENT_SOFT + ';font-size:.86rem;color:#475569">'
+ '$T = t + 273{,}15 = $ <b id="p13c-k" style="color:' + ACCENT_D + ';font-family:JetBrains Mono,monospace">298,15</b> K'
+ '<div style="font-size:.78rem;color:#64748b;margin-top:4px">Абсолютный нуль: $T = 0$ K $= -273{,}15$ °C — теоретический предел холода.</div>'
+ '</div>'
+ '</div>');
/* IV-3: DnD температуры */
h += wgWrap('p13-iv3', 'DnD', 'Соотнеси температуру и объект', '',
dndPool('p13-dnd', [
{ id:'a1', cat:'cold', html:'$-180$ °C' },
{ id:'a2', cat:'cold', html:'$-15$ °C' },
{ id:'a3', cat:'room', html:'$+20$ °C' },
{ id:'a4', cat:'room', html:'$+37$ °C' },
{ id:'a5', cat:'hot', html:'$+100$ °C' },
{ id:'a6', cat:'hot', html:'$+1500$ °C' }
], [
{ cat:'cold', label:'Холод (морозильник / жидкий азот)' },
{ cat:'room', label:'Норма (комната / тело человека)' },
{ cat:'hot', label:'Горячо (кипяток / расплав металла)' }
]));
/* IV-4: тренажёр */
h += wgWrap('p13-iv4', 'ТРН', 'Тренажёр §13', '5 вопросов.',
'<div id="p13-tr-host">'
+ quizQuestion('p13-tr', 0, 'Температура $t = 0$ °C соответствует…', ['Таянию льда','Кипению воды','Замерзанию ртути','Абсолютному нулю'], 0)
+ quizQuestion('p13-tr', 1, 'Сколько Кельвинов в $0$ °C?', ['0','100','273,15','373,15'], 2, '$T = 0 + 273{,}15 = 273{,}15$ K.')
+ quizQuestion('p13-tr', 2, 'В каком термометре используется расширение жидкости?', ['Биметаллическом','Электронном','Жидкостном (спиртовом/ртутном)','Инфракрасном'], 2)
+ quizQuestion('p13-tr', 3, 'Тело человека: $36{,}6$ °C $= ?$ K', ['36,6','273,15','309,75','310'], 2, '$T = 36{,}6 + 273{,}15 \\approx 309{,}75$ K.')
+ quizQuestion('p13-tr', 4, 'Может ли быть температура $-300$ °C?', ['Да','Нет, ниже -273,15 °C ничего не бывает','Только в космосе','Только в опытах'], 1)
+ '</div>');
h += readButton('p13');
body.innerHTML = h;
// §13 IV-1 thermometer
function drawTherm(){
const t = +document.getElementById('p13-t-r').value;
document.getElementById('p13-t').textContent = t;
const W = 100, H = 220;
const xC = 50, tubeTop = 20, tubeBot = 180, tubeW = 14;
const minT = -50, maxT = 150;
const frac = Math.max(0, Math.min(1, (t - minT) / (maxT - minT)));
const colTop = tubeBot - (tubeBot - tubeTop) * frac;
// Резервуар
const bulbR = 18;
const bulbY = 196;
let s = '';
s += '<rect x="' + (xC - tubeW/2 - 2) + '" y="' + tubeTop + '" width="' + (tubeW + 4) + '" height="' + (tubeBot - tubeTop + 6) + '" fill="#fff" stroke="#0f172a" stroke-width="1.5" rx="' + tubeW/2 + '"/>';
s += '<circle cx="' + xC + '" cy="' + bulbY + '" r="' + bulbR + '" fill="#fff" stroke="#0f172a" stroke-width="1.5"/>';
// Столбик
const hue = 240 - 240 * frac;
const col = 'hsl(' + hue + ',75%,50%)';
s += '<rect x="' + (xC - tubeW/2 + 2) + '" y="' + colTop + '" width="' + (tubeW - 4) + '" height="' + (tubeBot - colTop + 8) + '" fill="' + col + '"/>';
s += '<circle cx="' + xC + '" cy="' + bulbY + '" r="' + (bulbR - 4) + '" fill="' + col + '"/>';
// Шкала
for(let T = minT; T <= maxT; T += 10){
const y = tubeBot - (tubeBot - tubeTop) * (T - minT) / (maxT - minT);
const isBig = T % 50 === 0 || T === 0 || T === 100;
s += '<line x1="' + (xC + tubeW/2 + 4) + '" y1="' + y + '" x2="' + (xC + tubeW/2 + (isBig ? 12 : 8)) + '" y2="' + y + '" stroke="#0f172a" stroke-width="' + (isBig ? 1.5 : 1) + '"/>';
if(isBig) s += '<text x="' + (xC + tubeW/2 + 15) + '" y="' + (y + 3) + '" font-family="Inter,sans-serif" font-size="9" font-weight="600" fill="#0f172a">' + T + '</text>';
}
// Указатель текущей
const tY = tubeBot - (tubeBot - tubeTop) * (t - minT) / (maxT - minT);
s += '<polygon points="' + (xC - tubeW/2 - 14) + ',' + (tY - 5) + ' ' + (xC - tubeW/2 - 4) + ',' + tY + ' ' + (xC - tubeW/2 - 14) + ',' + (tY + 5) + '" fill="#dc2626"/>';
s += '<text x="3" y="14" font-family="Inter,sans-serif" font-size="10" font-weight="700" fill="#92400e">°C</text>';
document.getElementById('p13-svg').innerHTML = s;
// Info
let label;
if(t < -50) label = 'Очень холодно (вряд ли встретишь в природе на Земле).';
else if(t < -30) label = '<b>Сильный мороз</b> — Север, Сибирь зимой.';
else if(t < 0) label = '<b>Минусовая температура</b> — вода замерзает.';
else if(t < 10) label = '<b>Прохладно</b> — поздняя осень.';
else if(t < 25) label = '<b>Комфортно</b> — обычная комнатная температура.';
else if(t < 37) label = '<b>Тепло</b> — летний день.';
else if(t < 60) label = '<b>Жарко</b> — около температуры тела или горячая вода из крана.';
else if(t < 100) label = '<b>Очень горячо</b> — нельзя касаться, можно обжечься.';
else if(t < 120) label = '<b>Кипяток / пар</b> — кипящая вода.';
else label = '<b>Очень горячо</b> — выше точки кипения воды.';
document.getElementById('p13-info').innerHTML = label + '<br><span style="font-size:.84rem;color:#64748b">$T = t + 273{,}15 = ' + (t + 273.15).toFixed(2) + '$ K</span>';
renderMath(document.getElementById('p13-info'));
}
document.getElementById('p13-t-r').addEventListener('input', drawTherm);
drawTherm();
// §13 IV-2 converter
document.getElementById('p13c-c-r').addEventListener('input', () => {
const c = +document.getElementById('p13c-c-r').value;
document.getElementById('p13c-c').textContent = c;
document.getElementById('p13c-k').textContent = (c + 273.15).toFixed(2);
});
wireDnd('p13-dnd', [
{ id:'a1', cat:'cold' },{ id:'a2', cat:'cold' },{ id:'a3', cat:'room' },
{ id:'a4', cat:'room' },{ id:'a5', cat:'hot' },{ id:'a6', cat:'hot' }
]);
wireQuiz('p13-tr-host', () => { if(window.addXp) window.addXp(15, 'tr-p13'); });
wireReadBtn('p13');
renderMath(body);
}
/* ========================================================== */
/* Финал главы 2 — 5 боссов + ачивка «Знаток вещества» */
/* ========================================================== */
function add_final2(){
const body = document.getElementById('final2-body');
if(!body) return;
let h = '';
h += '<div style="background:linear-gradient(135deg,' + ACCENT_SOFT + ',#fdf4ff);border:1.5px solid ' + ACCENT + ';border-radius:14px;padding:16px;margin-bottom:14px;text-align:center">'
+ '<div style="font-family:Unbounded,sans-serif;font-weight:800;font-size:1.12rem;color:' + ACCENT_D + '">Финал главы 2: победи 5 боссов</div>'
+ '<div style="font-size:.88rem;color:#475569;margin-top:5px">Реши все 5 задач — получишь ачивку «Знаток вещества» и +50 XP.</div>'
+ '<div style="height:10px;background:#fff;border-radius:6px;overflow:hidden;margin-top:12px;border:1px solid ' + ACCENT_SOFT + '"><div id="ch2-fin-fill" style="height:100%;background:linear-gradient(90deg,' + ACCENT + ',' + ACCENT_D + ');width:0%;transition:width .4s"></div></div>'
+ '<div id="ch2-fin-lab" style="font-size:.84rem;color:#475569;margin-top:6px">Побеждено: 0 / 5</div>'
+ '</div>';
const bosses = [
{ n:1, tag:'§8', title:'Размер молекулы',
q:'Во сколько раз молекула воды ($\\sim 10^{-10}$ м) меньше толщины волоса ($\\sim 10^{-4}$ м)?',
hint:'$10^{-4} / 10^{-10} = 10^6$ — в миллион раз.',
ans:1000000, tol:50000, step:'1' },
{ n:2, tag:'§9', title:'Диффузия и температура',
q:'Стакан кипятка ($+95$ °C) и стакан воды из-под крана ($+10$ °C). В обоих растворяют одинаковую щепотку соли. Через сколько минут вода в первом будет соленее по всему объёму, если во втором — за $30$ мин? Считать, что скорость диффузии примерно $\\sim T$ (в Кельвинах). Ответ — приблизительно в минутах (округли до целого).',
hint:'$T_1 = 95+273 = 368$ K, $T_2 = 10+273 = 283$ K. Отношение $283/368 \\approx 0{,}77$. Время в горячей: $30 \\cdot 0{,}77 \\approx 23$ мин.',
ans:23, tol:2, step:'1' },
{ n:3, tag:'§11', title:'Газ в шприце',
q:'В шприце $V_1 = 50$ см³ воздуха. Поршнем сжали так, что объём стал $V_2 = 20$ см³. Какую часть от первоначального объёма занял газ (в процентах, округли до целого)?',
hint:'$V_2/V_1 \\cdot 100\\% = 20/50 \\cdot 100\\% = 40\\,\\%$.',
ans:40, tol:1, step:'1' },
{ n:4, tag:'§12', title:'Тепловое расширение рельса',
q:'Стальной рельс длиной $l_0 = 25$ м летом нагревается с зимних $-20$ °C до летних $+40$ °C ($\\Delta T = 60$ °C). Коэффициент линейного расширения стали $\\alpha = 12 \\cdot 10^{-6}$ 1/°C. На сколько мм он удлинится?',
hint:'$\\Delta l = l_0 \\alpha \\Delta T = 25 \\cdot 12 \\cdot 10^{-6} \\cdot 60 = 1{,}8 \\cdot 10^{-2}$ м $= 18$ мм.',
ans:18, tol:1, step:'0.1' },
{ n:5, tag:'§13', title:'Знаток вещества (термометр)',
q:'Термометр показывает $t = 27$ °C. Сколько это Кельвинов? Округли до десятых.',
hint:'$T = t + 273{,}15 = 27 + 273{,}15 = 300{,}2$ K (при округлении до десятых).',
ans:300.2, tol:0.2, step:'0.1' }
];
const STATE_KEY = 'physics7_ch2_final_bosses';
let solved = {};
try{ solved = JSON.parse(localStorage.getItem(STATE_KEY) || '{}') || {}; }catch(e){}
bosses.forEach(b => {
const isSolved = !!solved[b.n];
h += '<div data-boss="' + b.n + '" style="background:#fff;border:2px solid ' + (isSolved ? '#10b981' : ACCENT_SOFT) + ';border-radius:12px;padding:14px 16px;margin-bottom:12px;box-shadow:' + (isSolved ? '0 0 0 3px rgba(16,185,129,.16)' : '0 2px 8px rgba(0,0,0,.05)') + '">'
+ '<div style="display:flex;align-items:center;gap:10px;margin-bottom:8px;flex-wrap:wrap">'
+ '<span style="background:' + ACCENT + ';color:#fff;padding:3px 10px;border-radius:99px;font-size:.7rem;font-weight:800;letter-spacing:.04em">' + b.tag + '</span>'
+ '<span style="font-family:Unbounded,sans-serif;font-weight:800;font-size:.96rem;color:#0f172a">Босс ' + b.n + '. ' + b.title + '</span>'
+ '</div>'
+ '<div style="padding:10px 12px;background:' + ACCENT_SOFT + ';border-radius:8px;margin-bottom:10px;font-size:.94rem;line-height:1.55">' + b.q + '</div>'
+ '<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">'
+ '<input type="number" step="' + b.step + '" class="boss-inp" data-n="' + b.n + '" placeholder="число" style="padding:8px 12px;border:1.5px solid ' + ACCENT_SOFT + ';border-radius:8px;width:140px;text-align:center;font-family:JetBrains Mono,monospace;font-size:.95rem"' + (isSolved ? ' value="' + b.ans + '" disabled' : '') + '>'
+ '<button class="boss-go" data-n="' + b.n + '" type="button" style="background:linear-gradient(135deg,' + ACCENT + ',' + ACCENT_D + ');color:#fff;border:none;padding:8px 16px;border-radius:9px;font-weight:700;font-size:.88rem;cursor:pointer;font-family:inherit"' + (isSolved ? ' disabled' : '') + '>Атаковать</button>'
+ '<button class="boss-hint" data-n="' + b.n + '" type="button" style="background:#fff;color:#475569;border:1.5px solid ' + ACCENT_SOFT + ';padding:8px 14px;border-radius:9px;font-weight:600;font-size:.86rem;cursor:pointer;font-family:inherit">Подсказка</button>'
+ '</div>'
+ '<div class="boss-hint-txt" data-n="' + b.n + '" style="margin-top:8px;padding:9px 13px;background:#fef3c7;border-left:3px solid #f59e0b;border-radius:6px;font-size:.86rem;line-height:1.5;display:none">' + b.hint + '</div>'
+ '<div class="boss-fb" data-n="' + b.n + '" style="margin-top:8px;padding:9px 13px;border-radius:8px;font-weight:600;font-size:.88rem;line-height:1.45;' + (isSolved ? 'background:#d1fae5;color:#065f46;border-left:4px solid #10b981' : 'display:none') + '">' + (isSolved ? '&#10003; Босс повержен! +20 XP.' : '') + '</div>'
+ '</div>';
});
h += '<div id="ch2-mastered" style="margin-top:14px;padding:14px 18px;border-radius:12px;background:linear-gradient(135deg,#fef3c7,#fde68a);border:1.5px solid #f59e0b;display:none;align-items:center;gap:12px"><svg style="width:32px;height:32px;stroke:#92400e;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round" viewBox="0 0 24 24"><polygon points="12,2 15,9 22,9.3 17,14 18.5,21 12,17 5.5,21 7,14 2,9.3 9,9"/></svg><div style="flex:1"><div style="font-weight:800;color:#92400e;font-family:Unbounded,sans-serif">Ачивка «Знаток вещества» получена!</div><div style="font-size:.86rem;color:#78350f;margin-top:2px">+50 XP &middot; Глава 2 полностью пройдена.</div></div></div>';
body.innerHTML = h;
renderMath(body);
function updateBar(){
const cnt = bosses.filter(b => solved[b.n]).length;
document.getElementById('ch2-fin-fill').style.width = (cnt * 100 / bosses.length) + '%';
document.getElementById('ch2-fin-lab').textContent = 'Побеждено: ' + cnt + ' / ' + bosses.length;
if(cnt === bosses.length){
document.getElementById('ch2-mastered').style.display = 'flex';
const ACH_KEY = 'physics7_ch2_master';
if(localStorage.getItem(ACH_KEY) !== '1'){
localStorage.setItem(ACH_KEY, '1');
if(window.addXp) window.addXp(50, 'ach-ch2-master');
if(window.achievement) window.achievement('ch_done', 'Знаток вещества');
}
}
}
updateBar();
body.querySelectorAll('.boss-hint').forEach(btn => btn.addEventListener('click', () => {
const n = btn.dataset.n;
const txt = body.querySelector('.boss-hint-txt[data-n="' + n + '"]');
if(txt) txt.style.display = txt.style.display === 'none' ? 'block' : 'none';
}));
body.querySelectorAll('.boss-go').forEach(btn => btn.addEventListener('click', () => {
const n = +btn.dataset.n;
const b = bosses.find(x => x.n === n);
const inp = body.querySelector('.boss-inp[data-n="' + n + '"]');
const fb = body.querySelector('.boss-fb[data-n="' + n + '"]');
const card = body.querySelector('[data-boss="' + n + '"]');
const v = parseFloat((inp.value || '').replace(',', '.'));
if(isNaN(v)){
fb.style.display = 'block';
fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.textContent = 'Введи число.';
return;
}
if(Math.abs(v - b.ans) < b.tol){
fb.style.display = 'block';
fb.style.background = '#d1fae5'; fb.style.color = '#065f46'; fb.style.borderLeft = '4px solid #10b981';
fb.innerHTML = '&#10003; Босс повержен! +20 XP.';
card.style.border = '2px solid #10b981';
card.style.boxShadow = '0 0 0 3px rgba(16,185,129,.16)';
btn.disabled = true; inp.disabled = true;
if(!solved[n]){
solved[n] = true;
try{ localStorage.setItem(STATE_KEY, JSON.stringify(solved)); }catch(e){}
if(window.addXp) window.addXp(20, 'boss-ch2-' + n);
updateBar();
}
} else {
fb.style.display = 'block';
fb.style.background = '#fee2e2'; fb.style.color = '#7f1d1d'; fb.style.borderLeft = '4px solid #dc2626';
fb.textContent = 'Не то. Перепроверь решение.';
}
}));
body.querySelectorAll('.boss-inp').forEach(inp => inp.addEventListener('keydown', e => {
if(e.key === 'Enter'){ e.preventDefault(); body.querySelector('.boss-go[data-n="' + inp.dataset.n + '"]').click(); }
}));
}
window.PHYS7_CH2_WIDGETS = {
p8: add_p8,
p9: add_p9,
p10: add_p10,
p11: add_p11,
p12: add_p12,
p13: add_p13,
final2: add_final2
};
})();