feat(phys8 ch1): Phase 1 visual hero + IV-6 §1 drag-thermometer
Визуальный редизайн ch1 Тепловые явления: - Hero: заменён старый .hdr на новый .p8-hero с анимированным градиентом (thermal-shift 14s), огненным SVG-watermark справа (дышащая анимация 6s), live-meter в углу с пульсацией и плавной анимацией значения 37 → 100 → 0 → -10 → 25 → 80 °C. - Eyebrow 'Глава 1 · 11 параграфов', крупный title, sub-описание. - Section watermarks: в каждой <section sec-pN> добавлены тематические SVG (атом, конвекция, солнце, сосуд, фазовый переход, пузыри и т.д.) с opacity .07 на правой стороне. IV-6 §1 flagship interactive — Drag thermometer: - SVG-sandbox 560×320 с 4 телами (лёд, вода, чай, пар) разной T и относительной U. - Draggable термометр (P8Drag.attach + P8Helpers.svg). - При наведении на тело — изменяется цвет термометра по P8Helpers.thermal.tempColor(), readout табло показывают T (°C) и U (отн.). - +5 XP за 12 сек исследования. IV-6 stubs для §2-§11: 'Coming soon' плашки с тематическим SVG-иконкой clock. Расширим в Phase 1.2.
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
// Phase 1 — визуальный редизайн ch1 (Тепловые явления):
|
||||
// 1. Hero: заменяет старый <header class="hdr"> на p8-hero с
|
||||
// eyebrow, title, sub, live meter, watermark (огонь SVG).
|
||||
// 2. Section watermarks: в каждом <section id="sec-pN"> добавляет
|
||||
// тематический SVG-watermark (пламя/термометр/снежинка).
|
||||
// 3. Inject IV-6 (drag-thermometer) в §1 — flagship интерактив.
|
||||
// Остальные §2-11 получают IV-6 stub-placeholder с заголовком.
|
||||
'use strict';
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const DST = path.join(__dirname, '..', '..', 'frontend', 'textbooks', 'physics_8_ch1.html');
|
||||
let h = fs.readFileSync(DST, 'utf8');
|
||||
|
||||
// === 1. Replace .hdr block with p8-hero ===
|
||||
const FIRE_WM = `<svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<path d="M50 8 C 52 22 65 30 64 46 C 63 56 56 60 55 48 C 53 56 48 60 42 58 C 36 56 32 50 34 42 C 30 52 22 60 24 72 C 26 84 36 92 50 92 C 64 92 76 84 76 70 C 76 50 60 40 56 22 C 54 14 52 10 50 8 Z"/>
|
||||
</svg>`;
|
||||
|
||||
const NEW_HERO = `<header class="p8-hero">
|
||||
<div class="p8-hero-wm">${FIRE_WM}</div>
|
||||
<div class="p8-hero-meter" id="p8-meter-ch1"><span id="p8-meter-val">37</span>°C</div>
|
||||
<div class="p8-hero-inner">
|
||||
<div class="p8-hero-eyebrow">Глава 1 · 11 параграфов</div>
|
||||
<h1 class="p8-hero-title">Тепловые явления</h1>
|
||||
<div class="p8-hero-sub">Внутренняя энергия, способы теплопередачи, плавление и кипение. Перетаскивайте термометры, нагреватели и материалы — наблюдайте поведение тепла в реальном времени.</div>
|
||||
<div class="hdr-side" style="margin-top:18px;display:flex;gap:8px;flex-wrap:wrap;position:relative;z-index:1">
|
||||
<a href="/textbook/physics-8" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 8</a>
|
||||
<button id="search-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> Поиск</button>
|
||||
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
|
||||
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
|
||||
</div>
|
||||
</div>
|
||||
</header>`;
|
||||
|
||||
const oldHdrRegex = /<header class="hdr">[\s\S]*?<\/header>/;
|
||||
if (h.match(oldHdrRegex)) {
|
||||
h = h.replace(oldHdrRegex, NEW_HERO);
|
||||
console.log('Hero replaced');
|
||||
}
|
||||
|
||||
// === 2. Update meter live: добавим скрипт, который анимирует значение в углу ===
|
||||
const METER_SCRIPT = `
|
||||
<script>
|
||||
/* P8 hero meter — анимированный счётчик в углу (Phase 1 thermal) */
|
||||
(function(){
|
||||
function init(){
|
||||
const el = document.getElementById('p8-meter-val');
|
||||
if (!el || !window.P8Anim) return;
|
||||
const targets = [37, 100, 0, -10, 25, 80];
|
||||
let i = 0;
|
||||
function step(){
|
||||
const from = parseInt(el.textContent) || 0;
|
||||
const to = targets[i % targets.length];
|
||||
P8Anim.tween({
|
||||
from, to, duration: 1400, easing: 'cubicInOut',
|
||||
onUpdate: v => { el.textContent = Math.round(v); },
|
||||
onComplete: () => { i++; setTimeout(step, 1800); }
|
||||
});
|
||||
}
|
||||
setTimeout(step, 1200);
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
||||
else init();
|
||||
})();
|
||||
</script>
|
||||
`;
|
||||
if (!h.includes('P8 hero meter')) {
|
||||
h = h.replace('</body>', METER_SCRIPT + '\n</body>');
|
||||
console.log('Meter animation script added');
|
||||
}
|
||||
|
||||
// === 3. Section watermarks — добавить data-attribute, CSS подхватит ===
|
||||
// Используем pseudo-element через inline стиль не получится; вместо этого
|
||||
// инжектим <div class="p8-sec-wm"> в каждую секцию.
|
||||
|
||||
// Watermark SVG-символы по §
|
||||
const SEC_SYMBOLS = {
|
||||
p1: '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="28" stroke="currentColor" stroke-width="6" fill="none"/><path d="M50 22 v56 M22 50 h56" stroke="currentColor" stroke-width="3"/></svg>', // атом
|
||||
p2: '<svg viewBox="0 0 100 100"><path d="M50 12 v76 M50 12 l-14 16 M50 12 l14 16 M50 88 l-14-16 M50 88 l14-16" stroke="currentColor" stroke-width="4" fill="none"/></svg>', // вверх/вниз
|
||||
p3: '<svg viewBox="0 0 100 100"><path d="M14 50 h72 M86 50 l-14-14 M86 50 l-14 14" stroke="currentColor" stroke-width="5" fill="none"/></svg>', // правая стрелка
|
||||
p4: '<svg viewBox="0 0 100 100"><path d="M30 80 C 30 50, 70 50, 70 30 M30 30 C 30 60, 70 60, 70 80" stroke="currentColor" stroke-width="4" fill="none"/></svg>', // спирали (конвекция)
|
||||
p5: '<svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="14" fill="currentColor"/><g stroke="currentColor" stroke-width="4" fill="none"><line x1="50" y1="6" x2="50" y2="22"/><line x1="50" y1="78" x2="50" y2="94"/><line x1="6" y1="50" x2="22" y2="50"/><line x1="78" y1="50" x2="94" y2="50"/><line x1="18" y1="18" x2="30" y2="30"/><line x1="70" y1="70" x2="82" y2="82"/><line x1="82" y1="18" x2="70" y2="30"/><line x1="30" y1="70" x2="18" y2="82"/></g></svg>', // солнце
|
||||
p6: '<svg viewBox="0 0 100 100"><rect x="20" y="35" width="60" height="35" rx="4" stroke="currentColor" stroke-width="4" fill="none"/><path d="M28 35 v-8 M50 35 v-8 M72 35 v-8" stroke="currentColor" stroke-width="3"/></svg>', // сосуд
|
||||
p7: '<svg viewBox="0 0 100 100"><path d="M28 78 L50 22 L72 78 Z" stroke="currentColor" stroke-width="4" fill="none"/><path d="M40 60 L60 60" stroke="currentColor" stroke-width="3"/></svg>', // пламя/огонь
|
||||
p8: '<svg viewBox="0 0 100 100"><path d="M30 30 L70 30 L70 70 L30 70 Z" stroke="currentColor" stroke-width="4" fill="none"/><path d="M30 50 L70 50" stroke="currentColor" stroke-width="3" stroke-dasharray="4 3"/></svg>', // фазовый переход
|
||||
p9: '<svg viewBox="0 0 100 100"><path d="M50 14 L70 50 L50 86 L30 50 Z" stroke="currentColor" stroke-width="4" fill="none"/></svg>', // ромб
|
||||
p10: '<svg viewBox="0 0 100 100"><path d="M20 70 Q 35 50, 50 65 T 80 60" stroke="currentColor" stroke-width="4" fill="none"/><circle cx="78" cy="32" r="6" fill="currentColor"/></svg>', // капля + пар
|
||||
p11: '<svg viewBox="0 0 100 100"><circle cx="35" cy="55" r="6" fill="currentColor"/><circle cx="55" cy="45" r="8" fill="currentColor"/><circle cx="65" cy="65" r="5" fill="currentColor"/><circle cx="50" cy="75" r="4" fill="currentColor"/></svg>', // пузыри
|
||||
};
|
||||
|
||||
let secWmInjected = 0;
|
||||
for (const pid of Object.keys(SEC_SYMBOLS)) {
|
||||
const symbol = SEC_SYMBOLS[pid];
|
||||
const secOpenRegex = new RegExp(`(<section[^>]+id="sec-${pid}"[^>]*>)`);
|
||||
if (h.match(secOpenRegex) && !h.includes(`p8-sec-wm-${pid}`)) {
|
||||
const wmDiv = `<div class="p8-sec-wm" id="p8-sec-wm-${pid}" aria-hidden="true">${symbol}</div>`;
|
||||
h = h.replace(secOpenRegex, '$1\n ' + wmDiv);
|
||||
secWmInjected++;
|
||||
}
|
||||
}
|
||||
console.log('Section watermarks injected:', secWmInjected);
|
||||
|
||||
// Обеспечиваем что section имеет position:relative — добавляем inline-стиль
|
||||
// (или полагаемся на существующий CSS .sec, который позиционирован)
|
||||
// Проверим: ищем `.sec{` в style
|
||||
// (Это уже есть в существующем CSS, sec — позиционирован относительно)
|
||||
|
||||
// === 4. IV-6 flagship: для §1 добавляем drag-thermometer интерактив ===
|
||||
// Patch build_p1 — добавим IV-6 widget HTML + _initP1_iv6 функцию.
|
||||
|
||||
const IV6_P1_WIDGET = `
|
||||
/* IV6 — Drag thermometer (Phase 1 flagship interactive) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Перетащи термометр</div></div>'
|
||||
+'<div class="wg-help">Перетащи термометр на одно из четырёх тел и наблюдай, как меняется его температурный отсчёт. Тела разной массы и при разных условиях — оцени, в каком из них больше внутренней энергии.</div>'
|
||||
+'<div class="p8-sandbox" id="p1-iv6-sandbox" style="height:320px"></div>'
|
||||
+'<div class="actions" style="margin-top:10px;display:flex;gap:10px;flex-wrap:wrap">'
|
||||
+'<div class="p8-readout"><span class="p8-readout-label">T</span><span class="p8-readout-value" id="p1-iv6-T">—</span><span class="p8-readout-unit">°C</span></div>'
|
||||
+'<div class="p8-readout"><span class="p8-readout-label">U отн.</span><span class="p8-readout-value" id="p1-iv6-U">—</span></div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
`;
|
||||
|
||||
const IV6_P1_INIT = `
|
||||
function _initP1_iv6(){
|
||||
const sandbox = document.getElementById('p1-iv6-sandbox');
|
||||
if (!sandbox || !window.P8Helpers || !window.P8Drag) return;
|
||||
const svg = P8Helpers.svg.create(560, 320);
|
||||
svg.setAttribute('width', '100%');
|
||||
svg.setAttribute('height', '100%');
|
||||
svg.style.display = 'block';
|
||||
sandbox.appendChild(svg);
|
||||
/* 4 тела: имя, T (°C), относительная U */
|
||||
const bodies = [
|
||||
{ name:'Лёд 1 кг', cx: 95, cy: 200, T: -10, U: 14, color:'#bfdbfe' },
|
||||
{ name:'Вода 1 кг', cx: 230, cy: 200, T: 20, U: 100, color:'#7dd3fc' },
|
||||
{ name:'Чай 0,3 кг',cx: 365, cy: 200, T: 80, U: 80, color:'#fb923c' },
|
||||
{ name:'Пар 0,5 кг',cx: 500, cy: 200, T: 110, U: 200, color:'#ef4444' }
|
||||
];
|
||||
bodies.forEach(b => {
|
||||
const g = P8Helpers.svg.el('g', { transform: 'translate('+b.cx+','+b.cy+')' });
|
||||
g.appendChild(P8Helpers.svg.el('rect', {
|
||||
x: -50, y: -55, width: 100, height: 110, rx: 12,
|
||||
fill: b.color, stroke: '#0f172a', 'stroke-width': 1.5, opacity: 0.88
|
||||
}));
|
||||
g.appendChild(P8Helpers.svg.el('text', {
|
||||
x: 0, y: -68,
|
||||
'font-family': "'JetBrains Mono', monospace",
|
||||
'font-size': 11, 'font-weight': 700,
|
||||
fill: '#0f172a', 'text-anchor': 'middle',
|
||||
text: b.name
|
||||
}));
|
||||
g.dataset = b;
|
||||
svg.appendChild(g);
|
||||
});
|
||||
/* Термометр (draggable group) */
|
||||
let thermoX = 50, thermoY = 70;
|
||||
const thermoG = P8Helpers.svg.el('g', { transform: 'translate('+thermoX+','+thermoY+')', 'class': 'p8-draggable' });
|
||||
/* Drop shadow rect */
|
||||
thermoG.appendChild(P8Helpers.svg.el('rect', { x: -22, y: -10, width: 44, height: 130, fill: 'transparent' }));
|
||||
/* Tube */
|
||||
thermoG.appendChild(P8Helpers.svg.el('rect', {
|
||||
x: -5, y: 0, width: 10, height: 100, rx: 5,
|
||||
fill: '#f3f4f6', stroke: '#475569', 'stroke-width': 1.5
|
||||
}));
|
||||
const fill = P8Helpers.svg.el('rect', {
|
||||
x: -3, y: 70, width: 6, height: 30, rx: 2, fill: '#f97316'
|
||||
});
|
||||
thermoG.appendChild(fill);
|
||||
/* Bulb */
|
||||
const bulb = P8Helpers.svg.el('circle', { cx: 0, cy: 110, r: 12, fill: '#f97316', stroke: '#475569', 'stroke-width': 1.5 });
|
||||
thermoG.appendChild(bulb);
|
||||
thermoG.appendChild(P8Helpers.svg.el('text', {
|
||||
x: 0, y: -2,
|
||||
'font-family': "'Inter', sans-serif", 'font-size': 10, 'font-weight': 700,
|
||||
fill: '#0f172a', 'text-anchor': 'middle', text: 'Drag'
|
||||
}));
|
||||
svg.appendChild(thermoG);
|
||||
/* Show current readout */
|
||||
const tEl = document.getElementById('p1-iv6-T');
|
||||
const uEl = document.getElementById('p1-iv6-U');
|
||||
function checkHit(cx, cy){
|
||||
for (const b of bodies){
|
||||
if (Math.abs(cx - b.cx) < 50 && Math.abs(cy - b.cy) < 55){
|
||||
const tColor = P8Helpers.thermal.tempColor((b.T + 20) / 130);
|
||||
fill.setAttribute('fill', tColor);
|
||||
bulb.setAttribute('fill', tColor);
|
||||
if (tEl) tEl.textContent = b.T;
|
||||
if (uEl) uEl.textContent = b.U;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
fill.setAttribute('fill', '#94a3b8');
|
||||
bulb.setAttribute('fill', '#94a3b8');
|
||||
if (tEl) tEl.textContent = '—';
|
||||
if (uEl) uEl.textContent = '—';
|
||||
return null;
|
||||
}
|
||||
P8Drag.attach(thermoG, {
|
||||
container: svg,
|
||||
onMove: (ev, pos) => {
|
||||
thermoX = Math.max(20, Math.min(540, pos.x));
|
||||
thermoY = Math.max(10, Math.min(200, pos.y));
|
||||
thermoG.setAttribute('transform', 'translate('+thermoX+','+thermoY+')');
|
||||
checkHit(thermoX, thermoY + 110);
|
||||
}
|
||||
});
|
||||
if (window.addXp) {
|
||||
setTimeout(() => addXp(5, 'p1-iv6-explore'), 12000);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const insertMarker = `box.innerHTML = h + secNavFor('p1') + readButton('p1');`;
|
||||
if (!h.includes('p1-iv6-sandbox') && h.includes(insertMarker)) {
|
||||
h = h.replace(insertMarker, IV6_P1_WIDGET.trim() + '\n\n ' + insertMarker);
|
||||
// Add init call after wireReadBtn
|
||||
h = h.replace(`wireReadBtn('p1');`, `wireReadBtn('p1');\n _initP1_iv6();`);
|
||||
// Append init function after build_p1
|
||||
const p1Start = h.indexOf('function build_p1()');
|
||||
const p1End = h.indexOf('\n}\n', p1Start);
|
||||
h = h.slice(0, p1End + 3) + '\n' + IV6_P1_INIT.trim() + '\n' + h.slice(p1End + 3);
|
||||
console.log('IV-6 §1 drag-thermometer injected');
|
||||
}
|
||||
|
||||
// === 5. Stub IV-6 placeholders для §2-11 ===
|
||||
for (let n = 2; n <= 11; n++) {
|
||||
const pid = 'p' + n;
|
||||
const stubHtml = `
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.${n}) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §${n}</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.${n} — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
`;
|
||||
const marker = `box.innerHTML = h + secNavFor('${pid}') + readButton('${pid}');`;
|
||||
if (!h.includes(`p8-iv6-${pid}`) && !h.includes(`Новый интерактив §${n}`) && h.includes(marker)) {
|
||||
h = h.replace(marker, stubHtml.trim() + '\n\n ' + marker);
|
||||
console.log(` ${pid}: IV-6 stub added`);
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(DST, h);
|
||||
console.log('ch1 final size:', h.length);
|
||||
|
||||
// Sanity parse
|
||||
const scripts = [...h.matchAll(/<script>([\s\S]*?)<\/script>/g)];
|
||||
for (const m of scripts) {
|
||||
try { new Function(m[1]); }
|
||||
catch (e) { console.error('JS PARSE FAIL:', e.message.slice(0, 100)); process.exit(1); }
|
||||
}
|
||||
console.log('inline JS parses OK');
|
||||
@@ -170,13 +170,16 @@ a{color:inherit;text-decoration:none}
|
||||
</head>
|
||||
<body class="p8-theme-thermal">
|
||||
|
||||
<header class="hdr">
|
||||
<div class="hdr-row">
|
||||
<div>
|
||||
<h1>Физика 8 · Глава 1</h1>
|
||||
<div class="hdr-sub">Внутренняя энергия · теплопередача · фазовые переходы</div>
|
||||
</div>
|
||||
<div class="hdr-side">
|
||||
<header class="p8-hero">
|
||||
<div class="p8-hero-wm"><svg viewBox="0 0 100 100" aria-hidden="true">
|
||||
<path d="M50 8 C 52 22 65 30 64 46 C 63 56 56 60 55 48 C 53 56 48 60 42 58 C 36 56 32 50 34 42 C 30 52 22 60 24 72 C 26 84 36 92 50 92 C 64 92 76 84 76 70 C 76 50 60 40 56 22 C 54 14 52 10 50 8 Z"/>
|
||||
</svg></div>
|
||||
<div class="p8-hero-meter" id="p8-meter-ch1"><span id="p8-meter-val">37</span>°C</div>
|
||||
<div class="p8-hero-inner">
|
||||
<div class="p8-hero-eyebrow">Глава 1 · 11 параграфов</div>
|
||||
<h1 class="p8-hero-title">Тепловые явления</h1>
|
||||
<div class="p8-hero-sub">Внутренняя энергия, способы теплопередачи, плавление и кипение. Перетаскивайте термометры, нагреватели и материалы — наблюдайте поведение тепла в реальном времени.</div>
|
||||
<div class="hdr-side" style="margin-top:18px;display:flex;gap:8px;flex-wrap:wrap;position:relative;z-index:1">
|
||||
<a href="/textbook/physics-8" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 8</a>
|
||||
<button id="search-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> Поиск</button>
|
||||
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
|
||||
@@ -207,17 +210,28 @@ a{color:inherit;text-decoration:none}
|
||||
<div id="psel-grid" class="psel-grid"></div>
|
||||
</section>
|
||||
|
||||
<section id="sec-p1" class="sec"><div class="sec-header"><span class="sec-num">§ 1</span><h2 class="sec-h">Внутренняя энергия</h2></div><div id="p1-body"></div></section>
|
||||
<section id="sec-p2" class="sec"><div class="sec-header"><span class="sec-num">§ 2</span><h2 class="sec-h">Способы изменения внутренней энергии</h2></div><div id="p2-body"></div></section>
|
||||
<section id="sec-p3" class="sec"><div class="sec-header"><span class="sec-num">§ 3</span><h2 class="sec-h">Теплопроводность</h2></div><div id="p3-body"></div></section>
|
||||
<section id="sec-p4" class="sec"><div class="sec-header"><span class="sec-num">§ 4</span><h2 class="sec-h">Конвекция</h2></div><div id="p4-body"></div></section>
|
||||
<section id="sec-p5" class="sec"><div class="sec-header"><span class="sec-num">§ 5</span><h2 class="sec-h">Излучение</h2></div><div id="p5-body"></div></section>
|
||||
<section id="sec-p6" class="sec"><div class="sec-header"><span class="sec-num">§ 6</span><h2 class="sec-h">Расчёт количества теплоты при нагревании и охлаждении. Удельная теплоёмкость</h2></div><div id="p6-body"></div></section>
|
||||
<section id="sec-p7" class="sec"><div class="sec-header"><span class="sec-num">§ 7</span><h2 class="sec-h">Горение. Удельная теплота сгорания топлива</h2></div><div id="p7-body"></div></section>
|
||||
<section id="sec-p8" class="sec"><div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Плавление и кристаллизация</h2></div><div id="p8-body"></div></section>
|
||||
<section id="sec-p9" class="sec"><div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Удельная теплота плавления и кристаллизации</h2></div><div id="p9-body"></div></section>
|
||||
<section id="sec-p10" class="sec"><div class="sec-header"><span class="sec-num">§ 10</span><h2 class="sec-h">Испарение жидкостей. Факторы, влияющие на скорость испарения</h2></div><div id="p10-body"></div></section>
|
||||
<section id="sec-p11" class="sec"><div class="sec-header"><span class="sec-num">§ 11</span><h2 class="sec-h">Кипение жидкостей. Удельная теплота парообразования</h2></div><div id="p11-body"></div></section>
|
||||
<section id="sec-p1" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p1" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="28" stroke="currentColor" stroke-width="6" fill="none"/><path d="M50 22 v56 M22 50 h56" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 1</span><h2 class="sec-h">Внутренняя энергия</h2></div><div id="p1-body"></div></section>
|
||||
<section id="sec-p2" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p2" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M50 12 v76 M50 12 l-14 16 M50 12 l14 16 M50 88 l-14-16 M50 88 l14-16" stroke="currentColor" stroke-width="4" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 2</span><h2 class="sec-h">Способы изменения внутренней энергии</h2></div><div id="p2-body"></div></section>
|
||||
<section id="sec-p3" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p3" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M14 50 h72 M86 50 l-14-14 M86 50 l-14 14" stroke="currentColor" stroke-width="5" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 3</span><h2 class="sec-h">Теплопроводность</h2></div><div id="p3-body"></div></section>
|
||||
<section id="sec-p4" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p4" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M30 80 C 30 50, 70 50, 70 30 M30 30 C 30 60, 70 60, 70 80" stroke="currentColor" stroke-width="4" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 4</span><h2 class="sec-h">Конвекция</h2></div><div id="p4-body"></div></section>
|
||||
<section id="sec-p5" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p5" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="50" cy="50" r="14" fill="currentColor"/><g stroke="currentColor" stroke-width="4" fill="none"><line x1="50" y1="6" x2="50" y2="22"/><line x1="50" y1="78" x2="50" y2="94"/><line x1="6" y1="50" x2="22" y2="50"/><line x1="78" y1="50" x2="94" y2="50"/><line x1="18" y1="18" x2="30" y2="30"/><line x1="70" y1="70" x2="82" y2="82"/><line x1="82" y1="18" x2="70" y2="30"/><line x1="30" y1="70" x2="18" y2="82"/></g></svg></div><div class="sec-header"><span class="sec-num">§ 5</span><h2 class="sec-h">Излучение</h2></div><div id="p5-body"></div></section>
|
||||
<section id="sec-p6" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p6" aria-hidden="true"><svg viewBox="0 0 100 100"><rect x="20" y="35" width="60" height="35" rx="4" stroke="currentColor" stroke-width="4" fill="none"/><path d="M28 35 v-8 M50 35 v-8 M72 35 v-8" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 6</span><h2 class="sec-h">Расчёт количества теплоты при нагревании и охлаждении. Удельная теплоёмкость</h2></div><div id="p6-body"></div></section>
|
||||
<section id="sec-p7" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p7" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M28 78 L50 22 L72 78 Z" stroke="currentColor" stroke-width="4" fill="none"/><path d="M40 60 L60 60" stroke="currentColor" stroke-width="3"/></svg></div><div class="sec-header"><span class="sec-num">§ 7</span><h2 class="sec-h">Горение. Удельная теплота сгорания топлива</h2></div><div id="p7-body"></div></section>
|
||||
<section id="sec-p8" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p8" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M30 30 L70 30 L70 70 L30 70 Z" stroke="currentColor" stroke-width="4" fill="none"/><path d="M30 50 L70 50" stroke="currentColor" stroke-width="3" stroke-dasharray="4 3"/></svg></div><div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Плавление и кристаллизация</h2></div><div id="p8-body"></div></section>
|
||||
<section id="sec-p9" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p9" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M50 14 L70 50 L50 86 L30 50 Z" stroke="currentColor" stroke-width="4" fill="none"/></svg></div><div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Удельная теплота плавления и кристаллизации</h2></div><div id="p9-body"></div></section>
|
||||
<section id="sec-p10" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p10" aria-hidden="true"><svg viewBox="0 0 100 100"><path d="M20 70 Q 35 50, 50 65 T 80 60" stroke="currentColor" stroke-width="4" fill="none"/><circle cx="78" cy="32" r="6" fill="currentColor"/></svg></div><div class="sec-header"><span class="sec-num">§ 10</span><h2 class="sec-h">Испарение жидкостей. Факторы, влияющие на скорость испарения</h2></div><div id="p10-body"></div></section>
|
||||
<section id="sec-p11" class="sec">
|
||||
<div class="p8-sec-wm" id="p8-sec-wm-p11" aria-hidden="true"><svg viewBox="0 0 100 100"><circle cx="35" cy="55" r="6" fill="currentColor"/><circle cx="55" cy="45" r="8" fill="currentColor"/><circle cx="65" cy="65" r="5" fill="currentColor"/><circle cx="50" cy="75" r="4" fill="currentColor"/></svg></div><div class="sec-header"><span class="sec-num">§ 11</span><h2 class="sec-h">Кипение жидкостей. Удельная теплота парообразования</h2></div><div id="p11-body"></div></section>
|
||||
<section id="sec-final1" class="sec"><div class="sec-header"><span class="sec-num">★</span><h2 class="sec-h">Финал главы</h2></div><div id="final1-body"></div></section>
|
||||
|
||||
</div>
|
||||
@@ -826,9 +840,21 @@ function build_p1(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p1-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p1-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — Drag thermometer (Phase 1 flagship interactive) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Перетащи термометр</div></div>'
|
||||
+'<div class="wg-help">Перетащи термометр на одно из четырёх тел и наблюдай, как меняется его температурный отсчёт. Тела разной массы и при разных условиях — оцени, в каком из них больше внутренней энергии.</div>'
|
||||
+'<div class="p8-sandbox" id="p1-iv6-sandbox" style="height:320px"></div>'
|
||||
+'<div class="actions" style="margin-top:10px;display:flex;gap:10px;flex-wrap:wrap">'
|
||||
+'<div class="p8-readout"><span class="p8-readout-label">T</span><span class="p8-readout-value" id="p1-iv6-T">—</span><span class="p8-readout-unit">°C</span></div>'
|
||||
+'<div class="p8-readout"><span class="p8-readout-label">U отн.</span><span class="p8-readout-value" id="p1-iv6-U">—</span></div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p1') + readButton('p1');
|
||||
renderMath(box);
|
||||
wireReadBtn('p1');
|
||||
_initP1_iv6();
|
||||
_initp1_iv5();
|
||||
|
||||
_initP1_sim();
|
||||
@@ -837,6 +863,94 @@ function build_p1(){
|
||||
_initP1_mcq();
|
||||
}
|
||||
|
||||
function _initP1_iv6(){
|
||||
const sandbox = document.getElementById('p1-iv6-sandbox');
|
||||
if (!sandbox || !window.P8Helpers || !window.P8Drag) return;
|
||||
const svg = P8Helpers.svg.create(560, 320);
|
||||
svg.setAttribute('width', '100%');
|
||||
svg.setAttribute('height', '100%');
|
||||
svg.style.display = 'block';
|
||||
sandbox.appendChild(svg);
|
||||
/* 4 тела: имя, T (°C), относительная U */
|
||||
const bodies = [
|
||||
{ name:'Лёд 1 кг', cx: 95, cy: 200, T: -10, U: 14, color:'#bfdbfe' },
|
||||
{ name:'Вода 1 кг', cx: 230, cy: 200, T: 20, U: 100, color:'#7dd3fc' },
|
||||
{ name:'Чай 0,3 кг',cx: 365, cy: 200, T: 80, U: 80, color:'#fb923c' },
|
||||
{ name:'Пар 0,5 кг',cx: 500, cy: 200, T: 110, U: 200, color:'#ef4444' }
|
||||
];
|
||||
bodies.forEach(b => {
|
||||
const g = P8Helpers.svg.el('g', { transform: 'translate('+b.cx+','+b.cy+')' });
|
||||
g.appendChild(P8Helpers.svg.el('rect', {
|
||||
x: -50, y: -55, width: 100, height: 110, rx: 12,
|
||||
fill: b.color, stroke: '#0f172a', 'stroke-width': 1.5, opacity: 0.88
|
||||
}));
|
||||
g.appendChild(P8Helpers.svg.el('text', {
|
||||
x: 0, y: -68,
|
||||
'font-family': "'JetBrains Mono', monospace",
|
||||
'font-size': 11, 'font-weight': 700,
|
||||
fill: '#0f172a', 'text-anchor': 'middle',
|
||||
text: b.name
|
||||
}));
|
||||
g.dataset = b;
|
||||
svg.appendChild(g);
|
||||
});
|
||||
/* Термометр (draggable group) */
|
||||
let thermoX = 50, thermoY = 70;
|
||||
const thermoG = P8Helpers.svg.el('g', { transform: 'translate('+thermoX+','+thermoY+')', 'class': 'p8-draggable' });
|
||||
/* Drop shadow rect */
|
||||
thermoG.appendChild(P8Helpers.svg.el('rect', { x: -22, y: -10, width: 44, height: 130, fill: 'transparent' }));
|
||||
/* Tube */
|
||||
thermoG.appendChild(P8Helpers.svg.el('rect', {
|
||||
x: -5, y: 0, width: 10, height: 100, rx: 5,
|
||||
fill: '#f3f4f6', stroke: '#475569', 'stroke-width': 1.5
|
||||
}));
|
||||
const fill = P8Helpers.svg.el('rect', {
|
||||
x: -3, y: 70, width: 6, height: 30, rx: 2, fill: '#f97316'
|
||||
});
|
||||
thermoG.appendChild(fill);
|
||||
/* Bulb */
|
||||
const bulb = P8Helpers.svg.el('circle', { cx: 0, cy: 110, r: 12, fill: '#f97316', stroke: '#475569', 'stroke-width': 1.5 });
|
||||
thermoG.appendChild(bulb);
|
||||
thermoG.appendChild(P8Helpers.svg.el('text', {
|
||||
x: 0, y: -2,
|
||||
'font-family': "'Inter', sans-serif", 'font-size': 10, 'font-weight': 700,
|
||||
fill: '#0f172a', 'text-anchor': 'middle', text: 'Drag'
|
||||
}));
|
||||
svg.appendChild(thermoG);
|
||||
/* Show current readout */
|
||||
const tEl = document.getElementById('p1-iv6-T');
|
||||
const uEl = document.getElementById('p1-iv6-U');
|
||||
function checkHit(cx, cy){
|
||||
for (const b of bodies){
|
||||
if (Math.abs(cx - b.cx) < 50 && Math.abs(cy - b.cy) < 55){
|
||||
const tColor = P8Helpers.thermal.tempColor((b.T + 20) / 130);
|
||||
fill.setAttribute('fill', tColor);
|
||||
bulb.setAttribute('fill', tColor);
|
||||
if (tEl) tEl.textContent = b.T;
|
||||
if (uEl) uEl.textContent = b.U;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
fill.setAttribute('fill', '#94a3b8');
|
||||
bulb.setAttribute('fill', '#94a3b8');
|
||||
if (tEl) tEl.textContent = '—';
|
||||
if (uEl) uEl.textContent = '—';
|
||||
return null;
|
||||
}
|
||||
P8Drag.attach(thermoG, {
|
||||
container: svg,
|
||||
onMove: (ev, pos) => {
|
||||
thermoX = Math.max(20, Math.min(540, pos.x));
|
||||
thermoY = Math.max(10, Math.min(200, pos.y));
|
||||
thermoG.setAttribute('transform', 'translate('+thermoX+','+thermoY+')');
|
||||
checkHit(thermoX, thermoY + 110);
|
||||
}
|
||||
});
|
||||
if (window.addXp) {
|
||||
setTimeout(() => addXp(5, 'p1-iv6-explore'), 12000);
|
||||
}
|
||||
}
|
||||
|
||||
function _initp1_iv5(){
|
||||
const TASKS = [{"q":"Переведите температуру $t = 27\\,^\\circ$C в кельвины. ($T = t + 273$)","ans":300,"tol":1,"why":"$T = 27 + 273 = 300$ К."},{"q":"Температура воды $T = 373$ К. Чему равно $t$ в градусах Цельсия?","ans":100,"tol":1,"why":"$t = T - 273 = 373 - 273 = 100\\,^\\circ$C — кипение воды."},{"q":"У стакана воды массой $m_1 = 0{,}5$ кг и у бочки воды массой $m_2 = 50$ кг одинаковая температура. У кого внутренняя энергия больше во сколько раз?","ans":100,"tol":1,"why":"$U \\propto m$ при одинаковой $T$. $U_2/U_1 = m_2/m_1 = 50/0{,}5 = 100$."},{"q":"Тело нагрели на $\\Delta T = 30$ К. На сколько градусов Цельсия изменилась его температура?","ans":30,"tol":0.5,"why":"Шкалы Кельвина и Цельсия отличаются только сдвигом — разность температур одинакова."},{"q":"При какой температуре по шкале Цельсия средняя кинетическая энергия молекул равна нулю (абсолютный ноль)?","ans":-273,"tol":1,"why":"Абсолютный ноль $T = 0$ К соответствует $t = 0 - 273 = -273\\,^\\circ$C."}];
|
||||
let i = 0, ok = 0, awarded = false;
|
||||
@@ -1180,6 +1294,16 @@ function build_p2(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p2-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p2-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.2) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §2</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.2 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p2') + readButton('p2');
|
||||
renderMath(box);
|
||||
wireReadBtn('p2');
|
||||
@@ -1547,6 +1671,16 @@ function build_p3(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p3-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p3-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.3) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §3</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.3 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p3') + readButton('p3');
|
||||
renderMath(box);
|
||||
wireReadBtn('p3');
|
||||
@@ -1811,6 +1945,16 @@ function build_p4(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p4-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p4-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.4) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §4</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.4 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p4') + readButton('p4');
|
||||
renderMath(box);
|
||||
wireReadBtn('p4');
|
||||
@@ -2118,6 +2262,16 @@ function build_p5(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p5-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p5-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.5) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §5</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.5 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p5') + readButton('p5');
|
||||
renderMath(box);
|
||||
wireReadBtn('p5');
|
||||
@@ -2456,6 +2610,16 @@ function build_p6(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p6-task-i">1</b> / 6</span><span>Правильно: <b id="p6-task-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.6) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §6</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.6 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p6') + readButton('p6');
|
||||
renderMath(box);
|
||||
wireReadBtn('p6');
|
||||
@@ -2657,6 +2821,16 @@ function build_p7(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p7-task-i">1</b> / 5</span><span>Правильно: <b id="p7-task-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.7) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §7</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.7 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p7') + readButton('p7');
|
||||
renderMath(box);
|
||||
wireReadBtn('p7');
|
||||
@@ -2899,6 +3073,16 @@ function build_p8(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p8-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p8-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.8) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §8</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.8 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p8') + readButton('p8');
|
||||
renderMath(box);
|
||||
wireReadBtn('p8');
|
||||
@@ -3161,6 +3345,16 @@ function build_p9(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p9-task-i">1</b> / 6</span><span>Правильно: <b id="p9-task-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.9) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §9</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.9 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p9') + readButton('p9');
|
||||
renderMath(box);
|
||||
wireReadBtn('p9');
|
||||
@@ -3374,6 +3568,16 @@ function build_p10(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p10-tasks5-i">1</b> / 5</span><span>Правильно: <b id="p10-tasks5-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.10) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §10</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.10 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p10') + readButton('p10');
|
||||
renderMath(box);
|
||||
wireReadBtn('p10');
|
||||
@@ -3685,6 +3889,16 @@ function build_p11(){
|
||||
+'<div class="score-display" style="margin-top:10px"><span>Задача: <b id="p11-task-i">1</b> / 6</span><span>Правильно: <b id="p11-task-ok">0</b></span></div>'
|
||||
+'</div>';
|
||||
|
||||
/* IV6 — flagship интерактив (заглушка Phase 1, наполнение в Phase 1.11) */
|
||||
h += '<div class="wg p8-iv6">'
|
||||
+'<div class="wg-header"><span class="wg-badge p8-badge p8-badge-thermal">IV-6</span><div class="wg-title">Новый интерактив §11</div></div>'
|
||||
+'<div class="wg-help">Готовится: интерактивная визуализация с drag-and-drop для углубления темы. Скоро будет доступна.</div>'
|
||||
+'<div style="padding:30px;text-align:center;color:var(--p8-muted);font-style:italic">'
|
||||
+'<svg viewBox="0 0 24 24" style="width:32px;height:32px;stroke:currentColor;fill:none;stroke-width:1.5;opacity:.4"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>'
|
||||
+'<div style="margin-top:8px;font-size:.86rem">Phase 1.11 — coming soon</div>'
|
||||
+'</div>'
|
||||
+'</div>';
|
||||
|
||||
box.innerHTML = h + secNavFor('p11') + readButton('p11');
|
||||
renderMath(box);
|
||||
wireReadBtn('p11');
|
||||
@@ -3939,5 +4153,30 @@ document.addEventListener('DOMContentLoaded', init);
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
/* P8 hero meter — анимированный счётчик в углу (Phase 1 thermal) */
|
||||
(function(){
|
||||
function init(){
|
||||
const el = document.getElementById('p8-meter-val');
|
||||
if (!el || !window.P8Anim) return;
|
||||
const targets = [37, 100, 0, -10, 25, 80];
|
||||
let i = 0;
|
||||
function step(){
|
||||
const from = parseInt(el.textContent) || 0;
|
||||
const to = targets[i % targets.length];
|
||||
P8Anim.tween({
|
||||
from, to, duration: 1400, easing: 'cubicInOut',
|
||||
onUpdate: v => { el.textContent = Math.round(v); },
|
||||
onComplete: () => { i++; setTimeout(step, 1800); }
|
||||
});
|
||||
}
|
||||
setTimeout(step, 1200);
|
||||
}
|
||||
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
|
||||
else init();
|
||||
})();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user