feat(phys8 ch2): Phase 2 Wave 1 — §12 электризация + §13 пров/диэл + §14 индукция

§12 Электризация тел. Взаимодействие зарядов:
- 3 теории: 2 рода зарядов, закон взаимодействия, примеры
- IV-1: виртуальный электроскоп — кнопки «потереть» и «поднести»,
  листочки расходятся при поднесении заряженной палочки
- IV-2: 5 опытов «знак заряда» (стекло о шёлк, эбонит о шерсть...)
- IV-3: DnD 8 пар (одноим./разноим./нейтральные) на 2 категории
- IV-4: 6 MCQ

§13 Проводники и диэлектрики:
- 3 теории: свободные носители, таблица примеров, бытовая электротехника
- IV-1: симуляция «куда уходит заряд?» — на металле заряды разлетаются
  по поверхности (анимация движения по окружности), на пластике —
  остаются в точке касания
- IV-2: 8 материалов «проводник/диэлектрик»
- IV-3: DnD 8 материалов на 2 категории
- IV-4: 6 MCQ

§14 Электризация через влияние:
- 3 теории: что такое индукция, механизм, примеры (молниеотвод)
- IV-1: симуляция «палочка возле металл. шара» — slider положения
  и dropdown знака; шарик «реагирует» — разделение зарядов
  (-+ интенсивность зависит от расстояния)
- IV-2: 5 ситуаций «что произойдёт?»
- IV-3: DnD 8 примеров «индукция (проводник) / поляризация (диэлектрик)»
- IV-4: 6 MCQ

Добавлены _SIMS/_killSim/_isVisible для управления RAF в ch2.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-29 23:14:40 +03:00
parent 2dac331aa3
commit ed6fea460c
+712 -9
View File
@@ -307,9 +307,26 @@ const ACH_LABELS = {
};
const SIDEBARS = {
p12:{title:"Шпаргалка § 12",rows:[["В разработке","Phase 2 Wave 1"]]},
p13:{title:"Шпаргалка § 13",rows:[["В разработке","Phase 2 Wave 1"]]},
p14:{title:"Шпаргалка § 14",rows:[["В разработке","Phase 2 Wave 1"]]},
p12:{title:"Шпаргалка § 12",rows:[
["2 рода зарядов","+ (стекло о шёлк), &minus; (эбонит о шерсть)"],
["Одноимённые","отталкиваются"],
["Разноимённые","притягиваются"],
["При трении","заряд один — &plus;, другой — &minus;"],
["Сумма","сохраняется (закон сохр. заряда)"]
]},
p13:{title:"Шпаргалка § 13",rows:[
["Проводники","есть свободные носители"],
["Примеры пров.","металлы, графит, растворы солей, кислот, щелочей"],
["Диэлектрики","эбонит, стекло, дерево, пластик, дист. вода"],
["В проводнике","заряд по поверхности"],
["В диэлектрике","остаётся где появился"]
]},
p14:{title:"Шпаргалка § 14",rows:[
["Индукция","перераспределение зарядов в проводнике"],
["Без касания","нейтральный проводник $\\to$ разделение"],
["Ближний конец","заряд противоположного знака"],
["Если разделить","на 2 заряженные части"]
]},
p15:{title:"Шпаргалка § 15",rows:[["В разработке","Phase 2 Wave 2"]]},
p16:{title:"Шпаргалка § 16",rows:[["В разработке","Phase 2 Wave 2"]]},
p17:{title:"Шпаргалка § 17",rows:[["В разработке","Phase 2 Wave 3"]]},
@@ -331,9 +348,9 @@ const SIDEBARS = {
};
const TIPS=[
{sec:'p12',html:араграф § 12 будет реализован в Phase 2 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p13',html:"Параграф § 13 будет реализован в Phase 2 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p14',html:араграф § 14 будет реализован в Phase 2 Wave 1. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p12',html:отри расчёску о волосы — она начнёт притягивать клочки бумаги. Это <b>электризация</b>. При трении один предмет получает <b>положительный</b> заряд, другой — <b>отрицательный</b>. Одноимённые отталкиваются, разноимённые — притягиваются."},
{sec:'p13',html:"Металлы — отличные проводники: их электроны легко двигаются. Эбонит, стекло, пластик — диэлектрики: электроны связаны атомами. Поэтому ручка отвёртки из пластика — а сама отвёртка металлическая."},
{sec:'p14',html:однеси заряженный шар к незаряженному металлическому шарику — он притянется. В нейтральном проводнике под действием внешнего заряда электроны перераспределяются, и ближний конец получает противоположный знак."},
{sec:'p15',html:"Параграф § 15 будет реализован в Phase 2 Wave 2. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p16',html:"Параграф § 16 будет реализован в Phase 2 Wave 2. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
{sec:'p17',html:"Параграф § 17 будет реализован в Phase 2 Wave 3. Используем хелперы из <code>phys.js</code> и <code>optics.js</code>."},
@@ -355,9 +372,9 @@ const TIPS=[
];
const BUILDERS = {
p12: ()=>{ const box=document.getElementById('p12-body'); box.innerHTML = buildStub('p12', 'Электризация тел. Взаимодействие зарядов', 'Phase 2 Wave 1') + secNavFor('p12') + readButton('p12'); renderMath(box); wireReadBtn('p12'); },
p13: ()=>{ const box=document.getElementById('p13-body'); box.innerHTML = buildStub('p13', 'Проводники и диэлектрики', 'Phase 2 Wave 1') + secNavFor('p13') + readButton('p13'); renderMath(box); wireReadBtn('p13'); },
p14: ()=>{ const box=document.getElementById('p14-body'); box.innerHTML = buildStub('p14', 'Электризация через влияние', 'Phase 2 Wave 1') + secNavFor('p14') + readButton('p14'); renderMath(box); wireReadBtn('p14'); },
p12: ()=>{ build_p12(); },
p13: ()=>{ build_p13(); },
p14: ()=>{ build_p14(); },
p15: ()=>{ const box=document.getElementById('p15-body'); box.innerHTML = buildStub('p15', 'Электрический заряд. Элементарный заряд', 'Phase 2 Wave 2') + secNavFor('p15') + readButton('p15'); renderMath(box); wireReadBtn('p15'); },
p16: ()=>{ const box=document.getElementById('p16-body'); box.innerHTML = buildStub('p16', 'Строение атома. Ионы', 'Phase 2 Wave 2') + secNavFor('p16') + readButton('p16'); renderMath(box); wireReadBtn('p16'); },
p17: ()=>{ const box=document.getElementById('p17-body'); box.innerHTML = buildStub('p17', 'Электрическое поле. Электрическое напряжение', 'Phase 2 Wave 3') + secNavFor('p17') + readButton('p17'); renderMath(box); wireReadBtn('p17'); },
@@ -715,6 +732,692 @@ function initSidebarToggle(){
document.addEventListener('keydown',e=>{ if(e.key==='Escape') close(); });
}
/* ======================================================================
PHASE 2 · WAVE 1 — §12, §13, §14
====================================================================== */
/* Sim-management */
const _SIMS = {};
function _killSim(key){ if(_SIMS[key] && _SIMS[key].raf){ cancelAnimationFrame(_SIMS[key].raf); _SIMS[key].raf=0; } }
function _isVisible(secId){ const el=document.getElementById('sec-'+secId); return el && el.classList.contains('active'); }
/* ======== §12 — Электризация тел ======== */
function build_p12(){
const box = document.getElementById('p12-body');
let h = '';
h += makeCard('theory', 'Электрический заряд', '§ 12.1',
'<p>При трении некоторых тел друг о друга они приобретают свойство притягивать лёгкие предметы — клочки бумаги, волоски. Говорят: тело <b>электризуется</b>, на нём появляется <b>электрический заряд</b>.</p>'
+'<p>Опыты показывают: существует <b>два рода</b> зарядов.</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li><b>Положительный (+):</b> возникает на стекле, потёртом о шёлк.</li>'
+'<li><b>Отрицательный (&minus;):</b> возникает на эбоните или пластике, потёртом о шерсть.</li>'
+'</ul>'
);
h += makeCard('rule', 'Закон взаимодействия зарядов', '§ 12.2',
'<p><b>Одноимённые</b> заряды (++ или &minus;&minus;) — <b>отталкиваются</b>.<br>'
+'<b>Разноимённые</b> заряды (+&minus;) — <b>притягиваются</b>.</p>'
+'<p>При электризации трением заряды на двух телах <b>равны по модулю</b> и <b>противоположны</b> по знаку. Это закон <b>сохранения электрического заряда</b>.</p>'
+'<p style="margin-top:6px">Электризация происходит из-за переноса электронов с одного тела на другое: потерявшее электроны становится «+», получившее — «&minus;».</p>'
);
h += makeCard('example', 'Примеры', '§ 12.3',
'<ul style="padding-left:20px;margin:6px 0">'
+'<li>Расчёска после волос притягивает мелкие бумажки.</li>'
+'<li>Воздушный шарик после трения о волосы прилипает к стене.</li>'
+'<li>Снятие шерстяного свитера — иногда искрит.</li>'
+'<li>Молния — гигантский электрический разряд между облаком и землёй.</li>'
+'</ul>'
);
/* IV1 — виртуальный электроскоп */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Виртуальный электроскоп</div></div>'
+'<div class="wg-help">Потри палочку о ткань — она зарядится. Поднеси её к электроскопу — листочки разойдутся: одноимённые заряды отталкиваются.</div>'
+'<svg id="p12-sim" viewBox="0 0 460 240" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'<div class="actions" style="margin-top:10px"><button class="btn primary" id="p12-rub">Потереть палочку</button><button class="btn" id="p12-touch">Поднести к электроскопу</button><button class="btn" id="p12-reset">Сброс</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Заряд палочки: <b id="p12-q">0</b></span><span>Угол листочков: <b id="p12-a">0&#176;</b></span></div>'
+'</div>';
/* IV2 — викторина «знаки зарядов» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Каков знак заряда?</div></div>'
+'<div class="wg-help">По опыту с трением определи знак заряда тела.</div>'
+'<div id="p12-quiz"></div>'
+'<div class="actions"><button class="btn" id="p12-quiz-next">Следующий</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p12-quiz-r">1</b> / 5</span><span>Правильно: <b id="p12-quiz-ok">0</b></span></div>'
+'</div>';
/* IV3 — DnD «притягивает / отталкивает» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Что происходит при контакте?</div></div>'
+'<div class="wg-help">Распредели пары зарядов по типу взаимодействия.</div>'
+'<div id="p12-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
+'<div class="drop-box"><h5>Притягиваются</h5><div class="drop-items" data-cat="attr"></div></div>'
+'<div class="drop-box"><h5>Отталкиваются</h5><div class="drop-items" data-cat="rep"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p12-dnd-check">Проверить</button><button class="btn" id="p12-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p12-dnd-fb"></div>'
+'</div>';
/* IV4 — MCQ */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
+'<div id="p12-mcq"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p12-mcq-i">1</b> / 6</span><span>Правильно: <b id="p12-mcq-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p12') + readButton('p12');
renderMath(box);
wireReadBtn('p12');
_initP12_sim();
_initP12_quiz();
_initP12_dnd();
_initP12_mcq();
}
function _initP12_sim(){
const svg = document.getElementById('p12-sim'); if(!svg) return;
let charged = false; /* палочка заряжена */
let touched = false; /* поднесено к электроскопу */
function draw(){
let s = '';
/* электроскоп: стеклянная колба, металлический стержень, два листочка */
const escCx = 320, escCy = 130;
s += '<rect x="'+(escCx-50)+'" y="'+(escCy-20)+'" width="100" height="120" fill="rgba(186,230,253,.35)" stroke="#0f172a" stroke-width="1.6" rx="4"/>';
/* шар сверху */
s += '<circle cx="'+escCx+'" cy="'+(escCy-40)+'" r="14" fill="#94a3b8" stroke="#0f172a" stroke-width="1.6"/>';
/* стержень */
s += '<line x1="'+escCx+'" y1="'+(escCy-26)+'" x2="'+escCx+'" y2="'+(escCy+50)+'" stroke="#475569" stroke-width="3"/>';
/* листочки */
const leafAng = touched && charged ? 35 : 4;
document.getElementById('p12-a').textContent = leafAng+'&#176;';
const lx1 = escCx, ly1 = escCy+50;
const len = 36;
const lx2L = lx1 - len*Math.sin(leafAng*Math.PI/180);
const ly2L = ly1 + len*Math.cos(leafAng*Math.PI/180);
const lx2R = lx1 + len*Math.sin(leafAng*Math.PI/180);
const ly2R = ly1 + len*Math.cos(leafAng*Math.PI/180);
s += '<line x1="'+lx1+'" y1="'+ly1+'" x2="'+lx2L+'" y2="'+ly2L+'" stroke="#fbbf24" stroke-width="3"/>';
s += '<line x1="'+lx1+'" y1="'+ly1+'" x2="'+lx2R+'" y2="'+ly2R+'" stroke="#fbbf24" stroke-width="3"/>';
/* если заряжен и поднесён — рисуем + + на листочках */
if(touched && charged){
s += '<text x="'+(lx2L-8)+'" y="'+(ly2L+6)+'" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">&minus;</text>';
s += '<text x="'+(lx2R+4)+'" y="'+(ly2R+6)+'" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">&minus;</text>';
s += '<text x="'+escCx+'" y="'+(escCy-40+4)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="#dc2626">&minus;</text>';
}
/* палочка — слева */
const rodX = touched ? 260 : 100;
const rodY = 100;
s += '<rect x="'+rodX+'" y="'+(rodY-10)+'" width="100" height="20" fill="#1e1b4b" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
if(charged){
for(let i=0;i<5;i++) s += '<text x="'+(rodX+10+i*20)+'" y="'+(rodY+5)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#fca5a5">&minus;</text>';
}
/* ткань (если ещё не тёрли) */
if(!charged){
s += '<rect x="20" y="160" width="80" height="40" fill="#f87171" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
s += '<text x="60" y="184" text-anchor="middle" font-family="Inter,sans-serif" font-size="11" font-weight="700" fill="#fff">шерсть</text>';
}
/* подпись */
s += '<text x="150" y="50" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" fill="#475569">палочка (эбонит)</text>';
s += '<text x="320" y="220" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" fill="#475569">электроскоп</text>';
svg.innerHTML = s;
}
document.getElementById('p12-rub').addEventListener('click', ()=>{ charged = true; document.getElementById('p12-q').textContent = '5 нКл'; draw(); });
document.getElementById('p12-touch').addEventListener('click', ()=>{
if(!charged){
const fb = document.getElementById('p12-q'); fb.textContent = 'сначала потри!'; return;
}
touched = true; draw();
});
document.getElementById('p12-reset').addEventListener('click', ()=>{ charged=false; touched=false; document.getElementById('p12-q').textContent='0'; draw(); });
draw();
}
function _initP12_quiz(){
const QS = [
{sit:'Стеклянная палочка, потёртая о шёлк', ans:'+', why:'По таблице: стекло о шёлк — стекло положительное.'},
{sit:'Эбонитовая палочка о шерсть', ans:'-', why:'Эбонит получает электроны от шерсти — становится отрицательным.'},
{sit:'Шёлк после трения о стекло', ans:'-', why:'Шёлк забирает электроны со стекла — отрицательный.'},
{sit:'Шерсть после трения об эбонит', ans:'+', why:'Шерсть отдала электроны эбониту — положительная.'},
{sit:'Воздушный шарик о волосы', ans:'-', why:'Шарик принимает электроны с волос.'}
];
let i = 0, ok = 0;
function render(){
const q = QS[i]; const wrap = document.getElementById('p12-quiz'); if(!wrap) return;
wrap.innerHTML =
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
+'<button class="btn" data-pick="+" style="padding:14px;font-size:1.1rem"><b>+</b> положительный</button>'
+'<button class="btn" data-pick="-" style="padding:14px;font-size:1.1rem"><b>&minus;</b> отрицательный</button>'
+'</div>'
+'<div class="feedback" id="p12-quiz-fb"></div>';
document.getElementById('p12-quiz-r').textContent = (i+1);
document.getElementById('p12-quiz-ok').textContent = ok;
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
const fb = document.getElementById('p12-quiz-fb');
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(3,'p12-quiz'); bumpProgress('p12', 4); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p12-quiz-ok').textContent = ok;
});
});
}
document.getElementById('p12-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
render();
}
function _initP12_dnd(){
const items = [
{id:'pp', cat:'rep', html:'$+q$ и $+q$'},
{id:'mm', cat:'rep', html:'$-q$ и $-q$'},
{id:'pm', cat:'attr', html:'$+q$ и $-q$'},
{id:'mp', cat:'attr', html:'$-q$ и $+q$'},
{id:'p0', cat:'attr', html:'$+q$ и нейтральный проводник'},
{id:'m0', cat:'attr', html:'$-q$ и нейтральный проводник'},
{id:'pn', cat:'attr', html:'$+q$ и капля воды (диэл.)'},
{id:'pf', cat:'attr', html:'$+q$ и металл. шарик'}
];
const dnd = setupSorter({ poolId:'p12-dnd-pool', scopeSelector:'#sec-p12', cats:['attr','rep'], items, columnLayout:false });
document.getElementById('p12-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p12-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. Заряженный объект <b>всегда</b> притягивает нейтральные (индукция).'; addXp(15,'p12-dnd'); bumpProgress('p12', 20); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'. Подсказка: одноимённые отталкиваются; нейтральные всегда притягиваются.'; }
});
document.getElementById('p12-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p12-dnd-fb'); fb.style.display='none'; });
}
function _initP12_mcq(){
const QS = [
{q:'Сколько родов зарядов существует?', opts:['один','два','три','бесконечно много'], ans:1, why:'+ и &minus;, всего два.'},
{q:'При электризации стекла о шёлк стекло становится…', opts:['отрицательным','положительным','не заряжается','любым'], ans:1, why:'Стекло теряет электроны → +.'},
{q:'Что переносится при трении?', opts:['атомы','молекулы','электроны','ядра'], ans:2, why:'Электроны переходят с одного тела на другое.'},
{q:'Два одинаково заряженных шарика…', opts:['притягиваются','отталкиваются','неподвижны','зависит от размера'], ans:1, why:'Одноимённые всегда отталкиваются.'},
{q:'Сумма зарядов при трении двух нейтральных тел…', opts:['растёт','становится 0','остаётся 0','становится +'], ans:2, why:'Заряд сохраняется: было 0, стало $+q$ и $-q$, сумма всё ещё 0.'},
{q:'Почему стенка притягивает шарик после трения о голову?', opts:['стенка тоже зарядилась','индукция в нейтральной стенке','гравитация','клей'], ans:1, why:'В диэлектрике стенки происходит небольшая поляризация — она притягивается к шарику.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const q = QS[i]; const wrap = document.getElementById('p12-mcq'); if(!wrap) return;
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
h += '</div><div class="feedback" id="p12-mcq-fb"></div><div class="actions"><button class="btn" id="p12-mcq-next">Следующий</button></div>';
wrap.innerHTML = h;
document.getElementById('p12-mcq-i').textContent = (i+1);
document.getElementById('p12-mcq-ok').textContent = ok;
wrap.querySelectorAll('[data-k]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
const k = +btn.dataset.k; const fb = document.getElementById('p12-mcq-fb');
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(2,'p12-mcq'); bumpProgress('p12', 3); }
else { done++; fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p12-mcq-ok').textContent = ok;
renderMath(wrap);
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p12-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p12-mcq-bonus'); bumpProgress('p12', 15); }, 600); }
});
});
const nb = document.getElementById('p12-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
renderMath(wrap);
}
render();
}
/* ======== §13 — Проводники и диэлектрики ======== */
function build_p13(){
const box = document.getElementById('p13-body');
let h = '';
h += makeCard('theory', 'Свободные носители заряда', '§ 13.1',
'<p>Все вещества разделяют на два больших класса по способности проводить электрический заряд:</p>'
+'<ul style="padding-left:20px;margin:6px 0">'
+'<li><b>Проводники</b> — есть свободные носители заряда (например, свободные электроны у металлов). Заряд легко перемещается внутри.</li>'
+'<li><b>Диэлектрики</b> (изоляторы) — носители связаны с атомами/молекулами и не могут свободно перемещаться. Заряд «застревает» там, куда попал.</li>'
+'</ul>'
);
h += makeCard('rule', 'Примеры', '§ 13.2',
'<table style="width:100%;border-collapse:collapse;font-size:.92rem"><thead><tr style="background:rgba(15,23,42,.04)"><th style="padding:6px;text-align:left">Проводники</th><th style="padding:6px;text-align:left">Диэлектрики</th></tr></thead>'
+'<tbody><tr><td style="padding:6px;border-bottom:1px dashed var(--border)">все металлы</td><td style="padding:6px;border-bottom:1px dashed var(--border)">эбонит, стекло, янтарь</td></tr>'
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">графит</td><td style="padding:6px;border-bottom:1px dashed var(--border)">дерево (сухое), пластик, резина</td></tr>'
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">растворы солей, кислот, щелочей</td><td style="padding:6px;border-bottom:1px dashed var(--border)">фарфор, бумага (сухая)</td></tr>'
+'<tr><td style="padding:6px;border-bottom:1px dashed var(--border)">тело человека (через жидкости)</td><td style="padding:6px;border-bottom:1px dashed var(--border)">дистиллированная вода, воздух (сухой)</td></tr>'
+'<tr><td style="padding:6px">влажная земля</td><td style="padding:6px">шёлк, мех</td></tr></tbody></table>'
);
h += makeCard('example', 'Где это видно', '§ 13.3',
'<ul style="padding-left:20px;margin:6px 0">'
+'<li>Провода — медные (проводник), но в изоляции из пластика (диэлектрик).</li>'
+'<li>Розетки и выключатели — пластиковые корпуса.</li>'
+'<li>Заряд на металлическом шарике распределяется по всей поверхности — потому что он проводник.</li>'
+'<li>Заряд на пластиковой расчёске остаётся в месте трения — там, где «потёрли».</li>'
+'</ul>'
);
/* IV1 — Анимация: заряд на проводнике vs диэлектрике */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Куда уходит заряд?</div></div>'
+'<div class="wg-help">Сравни: на металлическом шарике заряд <b>распределяется</b> по всей поверхности. На пластиковом — остаётся в одном месте.</div>'
+'<svg id="p13-sim" viewBox="0 0 460 220" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'<div class="actions" style="margin-top:10px"><button class="btn primary" id="p13-charge">Дать заряд в одной точке</button><button class="btn" id="p13-reset">Сброс</button></div>'
+'</div>';
/* IV2 — викторина пров/диэл */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Проводник или диэлектрик?</div></div>'
+'<div class="wg-help">Назови материал — выбери тип.</div>'
+'<div id="p13-quiz"></div>'
+'<div class="actions"><button class="btn" id="p13-quiz-next">Следующий</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p13-quiz-r">1</b> / 8</span><span>Правильно: <b id="p13-quiz-ok">0</b></span></div>'
+'</div>';
/* IV3 — DnD */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Сортировка материалов</div></div>'
+'<div class="wg-help">Перетащи материалы в нужную колонку.</div>'
+'<div id="p13-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
+'<div class="drop-box"><h5>Проводники</h5><div class="drop-items" data-cat="cond"></div></div>'
+'<div class="drop-box"><h5>Диэлектрики</h5><div class="drop-items" data-cat="diel"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p13-dnd-check">Проверить</button><button class="btn" id="p13-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p13-dnd-fb"></div>'
+'</div>';
/* IV4 — MCQ */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
+'<div id="p13-mcq"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p13-mcq-i">1</b> / 6</span><span>Правильно: <b id="p13-mcq-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p13') + readButton('p13');
renderMath(box);
wireReadBtn('p13');
_initP13_sim();
_initP13_quiz();
_initP13_dnd();
_initP13_mcq();
}
function _initP13_sim(){
_killSim('p13sim');
const svg = document.getElementById('p13-sim'); if(!svg) return;
/* два шара: металлический (слева) и пластиковый (справа). При нажатии «дать заряд» — на метал. заряды разлетаются по поверхности, на пласт. остаются. */
const metCx = 130, metCy = 110, R = 60;
const plCx = 330, plCy = 110;
let charges = []; /* {x, y, target: 'met'|'pla', angTarget, sett: bool, settAng } */
let phase = 0; /* 0 = пусто, 1 = заряд дан */
function reset(){ charges = []; phase = 0; draw(); }
function giveCharge(){
/* добавляем 14 минус-зарядов в одной точке (верх каждого шара) */
if(phase > 0) return;
phase = 1;
for(let i=0;i<14;i++){
const a = Math.PI * 2 * i / 14;
charges.push({ targetA: a, x: metCx, y: metCy - R + 6, kind:'met', settled: false, t: 0 });
charges.push({ targetA: 0, x: plCx, y: plCy - R + 6, kind:'pla', settled: true, t: 0 });
}
}
function tick(){
if(!_isVisible('p13')){ _SIMS.p13sim.raf = requestAnimationFrame(tick); return; }
for(const c of charges){
if(c.kind === 'met' && !c.settled){
/* движение к точке на окружности (под углом targetA) */
c.t += 0.025;
const tx = metCx + (R-8) * Math.cos(c.targetA);
const ty = metCy + (R-8) * Math.sin(c.targetA);
c.x += (tx - c.x) * 0.06;
c.y += (ty - c.y) * 0.06;
if(Math.abs(c.x - tx) < 1 && Math.abs(c.y - ty) < 1) c.settled = true;
}
/* пластиковые сразу осели */
}
let s = '';
/* шары */
s += '<circle cx="'+metCx+'" cy="'+metCy+'" r="'+R+'" fill="#cbd5e1" stroke="#0f172a" stroke-width="2"/>';
s += '<text x="'+metCx+'" y="'+(metCy+R+22)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">МЕТАЛЛ (проводник)</text>';
s += '<circle cx="'+plCx+'" cy="'+plCy+'" r="'+R+'" fill="#fde68a" stroke="#0f172a" stroke-width="2"/>';
s += '<text x="'+plCx+'" y="'+(plCy+R+22)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">ПЛАСТИК (диэлектрик)</text>';
/* заряды */
for(const c of charges){
s += '<text x="'+c.x.toFixed(1)+'" y="'+(c.y+5).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="#dc2626">&minus;</text>';
}
/* стрелки касания если phase=0 */
if(phase === 0){
s += window.PHYS.drawArrow(metCx-30, metCy-R-30, metCx, metCy-R+2, '#10b981', 2, 9);
s += window.PHYS.drawArrow(plCx-30, plCy-R-30, plCx, plCy-R+2, '#10b981', 2, 9);
s += '<text x="'+(metCx-60)+'" y="'+(metCy-R-34)+'" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">касание</text>';
s += '<text x="'+(plCx-60)+'" y="'+(plCy-R-34)+'" font-family="Inter,sans-serif" font-size="11" fill="#0f172a">касание</text>';
}
svg.innerHTML = s;
_SIMS.p13sim.raf = requestAnimationFrame(tick);
}
_SIMS.p13sim = { raf: 0 };
_SIMS.p13sim.raf = requestAnimationFrame(tick);
document.getElementById('p13-charge').addEventListener('click', giveCharge);
document.getElementById('p13-reset').addEventListener('click', reset);
}
function _initP13_quiz(){
const QS = [
{mat:'медь', ans:'C', why:'Металл — проводник.'},
{mat:'эбонит', ans:'D', why:'Эбонит — классический диэлектрик.'},
{mat:'графит (карандаш)', ans:'C', why:'Графит — проводник.'},
{mat:'стекло', ans:'D', why:'Стекло не проводит ток.'},
{mat:'раствор поваренной соли', ans:'C', why:'В растворе есть свободные ионы — проводит.'},
{mat:'дистиллированная вода', ans:'D', why:'Чистая вода — диэлектрик (нет ионов).'},
{mat:'железо', ans:'C', why:'Металл.'},
{mat:'фарфор', ans:'D', why:'Фарфор — изолятор, поэтому из него делают изоляторы на линиях электропередачи.'}
];
let i = 0, ok = 0;
function render(){
const q = QS[i]; const wrap = document.getElementById('p13-quiz'); if(!wrap) return;
wrap.innerHTML =
'<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5;font-weight:700;font-size:1rem">'+q.mat+'</div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">'
+'<button class="btn" data-pick="C" style="padding:14px"><b>Проводник</b></button>'
+'<button class="btn" data-pick="D" style="padding:14px"><b>Диэлектрик</b></button>'
+'</div>'
+'<div class="feedback" id="p13-quiz-fb"></div>';
document.getElementById('p13-quiz-r').textContent = (i+1);
document.getElementById('p13-quiz-ok').textContent = ok;
wrap.querySelectorAll('[data-pick]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-pick]').forEach(b=>b.disabled=true);
const fb = document.getElementById('p13-quiz-fb');
if(btn.dataset.pick === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(3,'p13-quiz'); bumpProgress('p13', 4); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p13-quiz-ok').textContent = ok;
});
});
}
document.getElementById('p13-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
render();
}
function _initP13_dnd(){
const items = [
{id:'cu', cat:'cond', html:'медь'},
{id:'al', cat:'cond', html:'алюминий'},
{id:'gr', cat:'cond', html:'графит'},
{id:'sl', cat:'cond', html:'солёная вода'},
{id:'eb', cat:'diel', html:'эбонит'},
{id:'gl', cat:'diel', html:'стекло'},
{id:'pl', cat:'diel', html:'пластик'},
{id:'dw', cat:'diel', html:'дистил. вода'}
];
const dnd = setupSorter({ poolId:'p13-dnd-pool', scopeSelector:'#sec-p13', cats:['cond','diel'], items, columnLayout:false });
document.getElementById('p13-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p13-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. Металлы и растворы — проводники, остальные — диэлектрики.'; addXp(15,'p13-dnd'); bumpProgress('p13', 20); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'. Дистиллированная вода — диэлектрик (нет ионов).'; }
});
document.getElementById('p13-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p13-dnd-fb'); fb.style.display='none'; });
}
function _initP13_mcq(){
const QS = [
{q:'Чем отличаются проводники от диэлектриков?', opts:['массой','цветом','свободными носителями зарядов','температурой'], ans:2, why:'У проводников есть свободные заряды, у диэлектриков — нет.'},
{q:'Какие частицы свободны в металлах?', opts:['атомы','протоны','электроны','нейтроны'], ans:2, why:'Свободные электроны переносят заряд в металлах.'},
{q:'Заряд на металлическом шарике распределяется…', opts:['в центре','в одной точке','по всей поверхности','внутри'], ans:2, why:'Свободные заряды отталкиваются и оседают по поверхности.'},
{q:'Заряд на пластиковой расчёске…', opts:['распределяется','остаётся в месте трения','исчезает','уходит в землю'], ans:1, why:'Диэлектрик не позволяет заряду перемещаться.'},
{q:'Что используют для изоляции проводов?', opts:['медь','алюминий','пластик','графит'], ans:2, why:'Пластик — хороший диэлектрик.'},
{q:'Можно ли «зарядить» проводник, держа в руке голыми пальцами?', opts:['да','нет, заряд уйдёт через тело','зависит от металла','только летом'], ans:1, why:'Тело — проводник (через жидкости), заряд уходит в землю.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const q = QS[i]; const wrap = document.getElementById('p13-mcq'); if(!wrap) return;
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
h += '</div><div class="feedback" id="p13-mcq-fb"></div><div class="actions"><button class="btn" id="p13-mcq-next">Следующий</button></div>';
wrap.innerHTML = h;
document.getElementById('p13-mcq-i').textContent = (i+1);
document.getElementById('p13-mcq-ok').textContent = ok;
wrap.querySelectorAll('[data-k]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
const k = +btn.dataset.k; const fb = document.getElementById('p13-mcq-fb');
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(2,'p13-mcq'); bumpProgress('p13', 3); }
else { done++; fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p13-mcq-ok').textContent = ok;
renderMath(wrap);
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p13-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p13-mcq-bonus'); bumpProgress('p13', 15); }, 600); }
});
});
const nb = document.getElementById('p13-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
renderMath(wrap);
}
render();
}
/* ======== §14 — Электризация через влияние (индукция) ======== */
function build_p14(){
const box = document.getElementById('p14-body');
let h = '';
h += makeCard('theory', 'Что такое индукция', '§ 14.1',
'<p>Если поднести заряженное тело к нейтральному <b>проводнику</b>, не касаясь его, в проводнике произойдёт <b>перераспределение</b> свободных электронов.</p>'
+'<p><b>Электризация через влияние</b> (или <b>индукция</b>) — это разделение зарядов в проводнике под действием внешнего заряда без непосредственного контакта.</p>'
+'<p>Ближний к источнику конец проводника получает заряд <b>противоположного</b> знака, дальний — того же знака.</p>'
);
h += makeCard('rule', 'Как это работает', '§ 14.2',
'<p>Подносим $+q$ к незаряженному металлическому шарику:</p>'
+'<ol style="padding-left:20px;margin:6px 0">'
+'<li>Свободные электроны (отрицательные) притягиваются к $+q$ — собираются на <b>ближнем</b> конце.</li>'
+'<li>На <b>дальнем</b> конце остаются положительные ионы — некомпенсированный $+q$.</li>'
+'<li>В целом шарик остался нейтральным, но <b>заряды разделились</b>.</li>'
+'<li>Если теперь шарик разделить на 2 половинки — каждая будет заряжена!</li>'
+'</ol>'
);
h += makeCard('example', 'Примеры явления', '§ 14.3',
'<ul style="padding-left:20px;margin:6px 0">'
+'<li>Заряженный шарик притягивает любой кусочек металла — даже нейтральный.</li>'
+'<li>Расчёска (заряженная) притягивает бумажки (диэлектрик слегка поляризуется).</li>'
+'<li>В стенке (диэлектрик) поляризация молекул — шарик прилипает.</li>'
+'<li>Молниеотвод собирает индукцией заряд из грозовой тучи и отводит в землю.</li>'
+'</ul>'
);
/* IV1 — Симуляция: палочка + металлический шарик */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-1</span><div class="wg-title">Поднеси заряд — увидь индукцию</div></div>'
+'<div class="wg-help">Двигай заряженную палочку (slider) — наблюдай, как электроны в металлическом шарике перераспределяются.</div>'
+'<div class="sliders" style="margin-bottom:10px">'
+'<label>Положение палочки: <b id="p14-xv">слева</b><input type="range" id="p14-x" min="40" max="160" step="5" value="60"></label>'
+'<label>Знак: <select id="p14-sig" class="tinp" style="width:auto;padding:6px 10px;font-size:.92rem"><option value="-1">отрицательная (&minus;)</option><option value="1">положительная (+)</option></select></label>'
+'</div>'
+'<svg id="p14-sim" viewBox="0 0 460 200" style="width:100%;height:auto;background:#f8fafc;border-radius:9px;border:1px solid var(--border)"></svg>'
+'<div class="score-display" style="margin-top:10px;flex-direction:column;align-items:flex-start;gap:4px">'
+'<span>Ближний конец шара: <b id="p14-near">+</b> (противоположный палочке)</span>'
+'<span>Дальний конец шара: <b id="p14-far">&minus;</b> (того же знака)</span>'
+'</div>'
+'</div>';
/* IV2 — викторина: «что будет с шаром если…» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-2</span><div class="wg-title">Что произойдёт?</div></div>'
+'<div class="wg-help">Дана ситуация — определи итог.</div>'
+'<div id="p14-quiz"></div>'
+'<div class="actions"><button class="btn" id="p14-quiz-next">Следующий</button></div>'
+'<div class="score-display" style="margin-top:10px"><span>Раунд: <b id="p14-quiz-r">1</b> / 5</span><span>Правильно: <b id="p14-quiz-ok">0</b></span></div>'
+'</div>';
/* IV3 — DnD: «в проводнике / в диэлектрике» */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-3</span><div class="wg-title">Где идёт индукция, а где — поляризация?</div></div>'
+'<div class="wg-help">В проводниках — <b>индукция</b> (электроны бегут); в диэлектриках — <b>поляризация</b> (молекулы поворачиваются).</div>'
+'<div id="p14-dnd-pool"></div>'
+'<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">'
+'<div class="drop-box"><h5>Индукция (в проводнике)</h5><div class="drop-items" data-cat="ind"></div></div>'
+'<div class="drop-box"><h5>Поляризация (в диэлектрике)</h5><div class="drop-items" data-cat="pol"></div></div>'
+'</div>'
+'<div class="actions"><button class="btn primary" id="p14-dnd-check">Проверить</button><button class="btn" id="p14-dnd-reset">Сброс</button></div>'
+'<div class="feedback" id="p14-dnd-fb"></div>'
+'</div>';
/* IV4 — MCQ */
h += '<div class="wg">'
+'<div class="wg-header"><span class="wg-badge">IV-4</span><div class="wg-title">Тренажёр: 6 вопросов</div></div>'
+'<div class="wg-help">4+ правильных — +15 XP.</div>'
+'<div id="p14-mcq"></div>'
+'<div class="score-display" style="margin-top:10px"><span>Вопрос: <b id="p14-mcq-i">1</b> / 6</span><span>Правильно: <b id="p14-mcq-ok">0</b></span></div>'
+'</div>';
box.innerHTML = h + secNavFor('p14') + readButton('p14');
renderMath(box);
wireReadBtn('p14');
_initP14_sim();
_initP14_quiz();
_initP14_dnd();
_initP14_mcq();
}
function _initP14_sim(){
const svg = document.getElementById('p14-sim'); if(!svg) return;
function draw(){
const sx = +document.getElementById('p14-x').value;
const sig = +document.getElementById('p14-sig').value;
document.getElementById('p14-xv').textContent = sx < 80 ? 'далеко' : (sx < 130 ? 'близко' : 'почти касается');
/* у шарика: nearLabel = противоп. знаку палочки */
const nearSym = sig > 0 ? '&minus;' : '+';
const farSym = sig > 0 ? '+' : '&minus;';
document.getElementById('p14-near').innerHTML = nearSym;
document.getElementById('p14-far').innerHTML = farSym;
/* draw */
let s = '';
/* палочка слева */
s += '<rect x="'+(sx-50)+'" y="80" width="50" height="20" fill="#1e1b4b" stroke="#0f172a" stroke-width="1.5" rx="3"/>';
const rodCol = sig > 0 ? '#dc2626' : '#2563eb';
const rodTxt = sig > 0 ? '+' : '&minus;';
for(let i=0;i<4;i++) s += '<text x="'+(sx-42+i*12)+'" y="95" font-family="Inter,sans-serif" font-size="14" font-weight="800" fill="'+rodCol+'">'+rodTxt+'</text>';
/* металлический шарик в центре */
const shCx = 260, shCy = 90, shR = 56;
s += '<circle cx="'+shCx+'" cy="'+shCy+'" r="'+shR+'" fill="#cbd5e1" stroke="#0f172a" stroke-width="2"/>';
/* концентрация электронов на ближнем конце (если sig=+, электроны к палочке) или ионов */
const intensity = Math.min(1, (180 - sx) / 100); /* чем ближе палочка, тем сильнее эффект */
/* near = слева от шара (ближе к палочке), far = справа */
/* ставим знаки. Если палочка -, на ближнем + (т.е. на левой стороне +) */
const nearCol = sig > 0 ? '#2563eb' : '#dc2626';
const farCol = sig > 0 ? '#dc2626' : '#2563eb';
const nearTxt = sig > 0 ? '&minus;' : '+';
const farTxt = sig > 0 ? '+' : '&minus;';
for(let i=0;i<6;i++){
const ang = -Math.PI/2 + (i-2.5)*0.18;
const r = shR - 14;
/* near (слева) */
const nx = shCx + r*Math.cos(Math.PI + ang*0.4);
const ny = shCy + r*Math.sin(Math.PI + ang*0.4) - i*0;
s += '<text x="'+nx.toFixed(1)+'" y="'+(ny+5).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="'+nearCol+'" opacity="'+intensity.toFixed(2)+'">'+nearTxt+'</text>';
/* far (справа) */
const fx = shCx + r*Math.cos(ang*0.4);
const fy = shCy + r*Math.sin(ang*0.4);
s += '<text x="'+fx.toFixed(1)+'" y="'+(fy+5).toFixed(1)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="13" font-weight="800" fill="'+farCol+'" opacity="'+intensity.toFixed(2)+'">'+farTxt+'</text>';
}
s += '<text x="'+shCx+'" y="'+(shCy+shR+18)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#0f172a">МЕТАЛЛ. ШАР (нейтральный)</text>';
/* подпись индукции */
if(intensity > 0.3){
s += '<text x="230" y="40" text-anchor="middle" font-family="Inter,sans-serif" font-size="12" font-weight="700" fill="#7c3aed">индукция!</text>';
}
svg.innerHTML = s;
}
document.getElementById('p14-x').addEventListener('input', draw);
document.getElementById('p14-sig').addEventListener('change', draw);
draw();
}
function _initP14_quiz(){
const QS = [
{sit:'$+q$ поднесли к нейтральному металлическому шару, не касаясь.', opts:['шар стал +','шар стал ','шар стал нейтральным с разделёнными зарядами','шар не изменился'], ans:2, why:'Произошла индукция: внутри шара разделились заряды, но в целом он остался нейтральным.'},
{sit:'$-q$ поднесли к шару и коснулись его.', opts:['заряды шара не изменились','шар стал отрицательным','шар стал положительным','шар стал нейтральным'], ans:1, why:'Электроны с палочки перешли на шар.'},
{sit:'$+q$ долго держали возле шара, а потом убрали (не касаясь).', opts:['шар остался заряженным','шар нейтральный','шар стал отрицательным','шар стал положительным'], ans:1, why:'Без касания заряд просто перераспределялся; при удалении источника всё возвращается, шар нейтрален.'},
{sit:'$+q$ поднесли к двум прижатым друг к другу шарам. Их разъединили (не убирая $+q$), затем убрали $+q$.', opts:['оба нейтральны','оба +','оба ','один +, другой '], ans:3, why:'При разделении в присутствии $+q$ заряды зафиксировались: дальний шар стал +, ближний −.'},
{sit:'$-q$ поднесли к листку бумаги (диэлектрик).', opts:['ничего','бумага зарядилась +','в бумаге поляризация, она притянулась','бумага оттолкнулась'], ans:2, why:'В диэлектрике молекулы поляризуются, листок притягивается.'}
];
let i = 0, ok = 0;
function render(){
const q = QS[i]; const wrap = document.getElementById('p14-quiz'); if(!wrap) return;
let html = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin:8px 0;line-height:1.5">'+q.sit+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
q.opts.forEach((opt,k)=>{ html += '<button class="btn" data-k="'+k+'" style="padding:10px 14px;text-align:left">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
html += '</div><div class="feedback" id="p14-quiz-fb"></div>';
wrap.innerHTML = html;
document.getElementById('p14-quiz-r').textContent = (i+1);
document.getElementById('p14-quiz-ok').textContent = ok;
wrap.querySelectorAll('[data-k]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
const k = +btn.dataset.k; const fb = document.getElementById('p14-quiz-fb');
if(k===q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(3,'p14-quiz'); bumpProgress('p14', 4); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p14-quiz-ok').textContent = ok;
});
});
}
document.getElementById('p14-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
render();
}
function _initP14_dnd(){
const items = [
{id:'ms', cat:'ind', html:'$+q$ возле металлического шара'},
{id:'mf', cat:'ind', html:'заряженный шар возле фольги'},
{id:'mp', cat:'ind', html:'заряженный шар возле железной пластины'},
{id:'mw', cat:'ind', html:'$+q$ возле провода'},
{id:'pl', cat:'pol', html:'$-q$ возле клочка бумаги'},
{id:'pg', cat:'pol', html:'$+q$ возле стеклянной палочки'},
{id:'pw', cat:'pol', html:'$-q$ возле деревянной планки'},
{id:'pp', cat:'pol', html:'$+q$ возле пластиковой пластины'}
];
const dnd = setupSorter({ poolId:'p14-dnd-pool', scopeSelector:'#sec-p14', cats:['ind','pol'], items, columnLayout:false });
document.getElementById('p14-dnd-check').addEventListener('click', ()=>{
const fb = document.getElementById('p14-dnd-fb');
let wrong = 0; items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wrong++; });
if(wrong===0){ fb.className='feedback ok'; fb.innerHTML='&#10003; Идеально! +15 XP. В проводниках индукция, в диэлектриках поляризация — оба эффекта приводят к притяжению.'; addXp(15,'p14-dnd'); bumpProgress('p14', 20); }
else { fb.className='feedback fail'; fb.innerHTML='&#10007; Ошибок: '+wrong+'. Металлы и фольга — проводники, остальное — диэлектрики.'; }
});
document.getElementById('p14-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); const fb=document.getElementById('p14-dnd-fb'); fb.style.display='none'; });
}
function _initP14_mcq(){
const QS = [
{q:'Что такое электризация через влияние?', opts:['заряжение трением','перенос заряда касанием','разделение зарядов в проводнике без касания','испускание электронов'], ans:2, why:'Это разделение зарядов внутри проводника под действием внешнего заряда.'},
{q:'Ближний к источнику конец проводника получает заряд…', opts:['того же знака','противоположного','становится нейтральным','положительный'], ans:1, why:'Притягиваются заряды противоположного знака.'},
{q:'После убирания внешнего заряда (без касания) проводник…', opts:['остаётся заряженным','становится нейтральным','меняет знак','раскалывается'], ans:1, why:'Перераспределение исчезает, и проводник снова нейтрален.'},
{q:'Если в присутствии $+q$ разъединить шар на 2 части, что станет с частями после убирания $+q$?', opts:['обе +','обе ','одна +, другая ','обе нейтральны'], ans:2, why:'Разделение зафиксировалось: ближняя часть −, дальняя +.'},
{q:'Почему листочки бумаги притягиваются к расчёске?', opts:['индукция','поляризация молекул в диэлектрике','магнетизм','гравитация'], ans:1, why:'В диэлектрике молекулы поляризуются, и листок притягивается.'},
{q:'Молниеотвод использует…', opts:['индукцию','теплопередачу','излучение','реакцию горения'], ans:0, why:'Индукция собирает заряд из тучи на острие и отводит его в землю.'}
];
let i = 0, ok = 0, done = 0, awarded = false;
function render(){
const q = QS[i]; const wrap = document.getElementById('p14-mcq'); if(!wrap) return;
let h = '<div style="padding:10px 14px;background:rgba(15,23,42,.04);border-radius:9px;margin-bottom:10px;font-size:.95rem;line-height:1.5"><b>Вопрос '+(i+1)+'.</b> '+q.q+'</div><div style="display:grid;grid-template-columns:1fr;gap:6px">';
q.opts.forEach((opt,k)=>{ h += '<button class="btn" data-k="'+k+'" style="text-align:left;padding:10px 14px">'+String.fromCharCode(65+k)+'. '+opt+'</button>'; });
h += '</div><div class="feedback" id="p14-mcq-fb"></div><div class="actions"><button class="btn" id="p14-mcq-next">Следующий</button></div>';
wrap.innerHTML = h;
document.getElementById('p14-mcq-i').textContent = (i+1);
document.getElementById('p14-mcq-ok').textContent = ok;
wrap.querySelectorAll('[data-k]').forEach(btn=>{
btn.addEventListener('click', ()=>{
if(btn.disabled) return; wrap.querySelectorAll('[data-k]').forEach(b=>b.disabled=true);
const k = +btn.dataset.k; const fb = document.getElementById('p14-mcq-fb');
if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='&#10003; Верно. '+q.why; addXp(2,'p14-mcq'); bumpProgress('p14', 3); }
else { done++; fb.className='feedback fail'; fb.innerHTML='&#10007; Не то. '+q.why; }
document.getElementById('p14-mcq-ok').textContent = ok;
renderMath(wrap);
if(done >= QS.length && !awarded && ok >= 4){ awarded = true; setTimeout(()=>{ const wf=document.getElementById('p14-mcq-fb'); wf.className='feedback ok'; wf.innerHTML='&#10003; +15 XP — тренажёр пройден ('+ok+'/'+QS.length+').'; addXp(15,'p14-mcq-bonus'); bumpProgress('p14', 15); }, 600); }
});
});
const nb = document.getElementById('p14-mcq-next'); if(nb) nb.addEventListener('click', ()=>{ i=(i+1)%QS.length; render(); });
renderMath(wrap);
}
render();
}
function init(){
loadProgress(); initTheme(); initSidebarToggle(); initSearch();
buildParaSelector(); refreshProgressUI(); loadServerReadState(); goTo(PARAS[0].id);