feat(math5): Phase 0 — фундамент учебника «Математика 5»

План (PLAN_MATH_5 + VISUAL: карта 22 визуал-компонентов), миграция
050_math5_hub (хаб math-5 + 3 главы: Натуральные числа §1–17, Выражения.
Уравнения §1–9, Обыкновенные дроби §1–18), страница-хаб (3 карточки +
курсовой финал из 3 боссов + звание «Математик 5 класса») и 3 каркаса глав
на ОБЩЕМ движке math6 (window.M6 с slug math-5-chN, ключи math5_*).
Baseline-тест math5-page: 6/6. § без билдера → заглушка движка.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-03 09:09:42 +03:00
parent 21c18ce477
commit c020a2c948
8 changed files with 1052 additions and 0 deletions
@@ -0,0 +1,36 @@
-- Math 5 hub migration.
-- Creates math-5 as a full hub textbook (3 chapters) in the style of math-6:
-- math-5 (hub, html_path = math_5_hub.html)
-- math-5-ch1 (Натуральные числа, §§1–17) → math_5_ch1.html
-- math-5-ch2 (Выражения. Уравнения, §§1–9) → math_5_ch2.html
-- math-5-ch3 (Обыкновенные дроби, §§1–18) → math_5_ch3.html
--
-- Source: Герасимов В. Д., Пирютко О. Н., Лобанов А. П., «Математика. 5 класс»,
-- в 2 частях, Минск: Адукацыя і выхаванне, 2020 (2-е изд.). Контент авторский (наш).
-- Author left empty per project policy.
-- 1. Parent hub row.
INSERT OR IGNORE INTO textbooks
(slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active, parent_slug)
VALUES
('math-5', 'math', 5, 'Математика — 5 класс',
'',
'Полный курс математики 5 класса: натуральные числа и действия с ними, делимость, степень, выражения и уравнения, углы, обыкновенные дроби и смешанные числа, периметр, площадь и объём. 3 главы, 44 параграфа, интерактивные тренажёры, визуализации и финалы-боссы.',
'math_5_hub.html', 47, 'indigo', 5, 1, NULL);
-- 2. Three chapters.
INSERT OR IGNORE INTO textbooks
(slug, subject, grade, title, author, description, html_path, para_count, color, sort_order, is_active, parent_slug)
VALUES
('math-5-ch1', 'math', 5, 'Математика 5 · Натуральные числа',
'',
'§§1–17: как решать задачу, чтение и запись чисел и разряды, сравнение, точка/прямая/луч/отрезок, измерение отрезков, координатный луч, округление, сложение/вычитание/умножение/деление, степень, деление с остатком, делители, НОД и НОК, признаки делимости, простые и составные числа, разложение на множители.',
'math_5_ch1.html', 18, 'indigo', 1, 1, 'math-5'),
('math-5-ch2', 'math', 5, 'Математика 5 · Выражения. Уравнения',
'',
'§§1–9: числовые выражения и порядок действий, выражения с переменными, уравнение и его корень, формулы, решение задач с помощью уравнений, угол — измерение и построение углов транспортиром.',
'math_5_ch2.html', 10, 'teal', 2, 1, 'math-5'),
('math-5-ch3', 'math', 5, 'Математика 5 · Обыкновенные дроби',
'',
'§§1–18: обыкновенные дроби и доли, основное свойство дроби, правильные/неправильные и смешанные числа, сравнение, сложение и вычитание, умножение и деление дробей, задачи на дроби, параллельные и перпендикулярные прямые, ломаная и многоугольник, периметр, площадь и площадь треугольника, среднее арифметическое, диаграммы, прямоугольный параллелепипед и объём.',
'math_5_ch3.html', 19, 'rose', 3, 1, 'math-5');
+97
View File
@@ -0,0 +1,97 @@
'use strict';
/*
* Phase 0 jsdom-каркас «Математика 5»: хаб и 3 главы выполняются на ОБЩЕМ движке
* math6_engine.js (учебник 5 класса переиспользует тот же движок/SVG/anim через
* собственный window.M6 с slug 'math-5-chN'). Проверяется: страницы грузятся без
* ошибок скриптов, para-selector строится с нужным числом карточек, активен § 1,
* заглушка с кнопкой прочтения на месте, финал помечен. Содержание §§ наполняется
* по главам отдельными билдерами — здесь проверяется фундамент.
*/
const test = require('node:test');
const assert = require('node:assert');
const fs = require('node:fs');
const path = require('node:path');
const { JSDOM, VirtualConsole } = require('jsdom');
const ROOT = path.join(__dirname, '..', '..');
const readF = p => fs.readFileSync(path.join(ROOT, p), 'utf8');
const wait = ms => new Promise(r => setTimeout(r, ms));
/* Инлайним внешние скрипты (CDN убираем, api/xp заменяем заглушками). */
function buildPage(file) {
let html = readF('frontend/textbooks/' + file);
const inl = {
'/js/math6_svg.js': readF('frontend/js/math6_svg.js'),
'/js/math6_anim.js': readF('frontend/js/math6_anim.js'),
'/js/math6_engine.js': readF('frontend/js/math6_engine.js')
};
html = html
.replace(/<script defer src="https:\/\/cdn[^"]*"[^>]*><\/script>/g, '')
.replace(/<script src="\/js\/api\.js" defer><\/script>/, '<script>window.renderMathInElement=function(){};</script>')
.replace(/<script src="\/js\/xp\.js" defer><\/script>/, '');
Object.keys(inl).forEach(src => {
html = html.replace(new RegExp('<script src="' + src + '" defer><\\/script>'), () => '<script>\n' + inl[src] + '\n</script>');
});
return html;
}
async function loadDom(file) {
const errors = [];
const vc = new VirtualConsole();
vc.on('jsdomError', e => errors.push(e.message));
const dom = new JSDOM(buildPage(file), {
runScripts: 'dangerously', pretendToBeVisual: true, virtualConsole: vc, url: 'http://localhost/',
beforeParse(w) { w.scrollTo = function () {}; }
});
await wait(160);
return { dom, errors, doc: dom.window.document };
}
const CHAPTERS = [
{ file: 'math_5_ch1.html', cards: 18 },
{ file: 'math_5_ch2.html', cards: 10 },
{ file: 'math_5_ch3.html', cards: 19 }
];
test('engine: init() вызывается ПОСЛЕ экспортов (общий движок math6 — guard от sync-defer бага)', () => {
const src = readF('frontend/js/math6_engine.js');
const exportIdx = src.indexOf('window.makeCard = makeCard');
const initCallIdx = src.lastIndexOf('else init();');
assert.ok(exportIdx > 0, 'есть экспорт window.makeCard');
assert.ok(initCallIdx > exportIdx, 'else init() должен идти ПОСЛЕ window.makeCard = makeCard');
});
for (const ch of CHAPTERS) {
test(`${ch.file}: SPA без ошибок, ${ch.cards} карточек, активен § 1, заглушка`, async () => {
const { doc, errors } = await loadDom(ch.file);
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
assert.equal(doc.querySelectorAll('#psel-grid .psel-card').length, ch.cards, ch.cards + ' карточек');
const active = doc.querySelector('.sec.active');
assert.ok(active && active.id === 'sec-p1', 'активен sec-p1');
const body = doc.querySelector('#p1-body');
assert.ok(body && body.children.length > 0, 'тело § 1 заполнено');
assert.ok(doc.querySelector('#p1-body .m6-placeholder'), 'заглушка § 1 (нет билдера — ожидаемо в каркасе)');
assert.ok(doc.querySelector('#p1-body [data-read]'), 'кнопка прочтения § 1');
assert.ok(doc.querySelector('#psel-grid .psel-card.final'), 'есть карточка финала');
});
}
test('хаб math-5: 3 главы, курсовой финал, ачивка-полоса', async () => {
const { doc, errors } = await loadDom('math_5_hub.html');
assert.deepEqual(errors, [], 'нет ошибок: ' + errors.join(' | '));
assert.equal(doc.querySelectorAll('.ch-grid .ch-card').length, 3, '3 карточки глав');
assert.ok(doc.querySelector('a[href="/textbook/math-5-ch1"]'), 'ссылка на главу 1');
assert.ok(doc.querySelector('a[href="/textbook/math-5-ch3"]'), 'ссылка на главу 3');
assert.ok(doc.querySelector('#cf-go') && doc.querySelector('#cf-q'), 'арена курсового финала');
assert.ok(doc.querySelector('#ach-strip'), 'полоса звания «Математик 5 класса»');
});
test('движок 5 класса: прогресс/XP считаются на math5_*-ключах', async () => {
const { doc } = await loadDom('math_5_ch1.html');
const win = doc.defaultView;
assert.ok(win.M6 && win.M6.slug === 'math-5-ch1', 'M6.slug = math-5-ch1');
assert.equal(win.M6.lsPrefix, 'math5_ch1', 'lsPrefix = math5_ch1');
assert.equal(win.M6.xpKey, 'math5_xp', 'xpKey = math5_xp');
win.bumpProgress('final', 100); await wait(20);
assert.ok(win.M6STATE.achievements.has('ch1_done'), 'достижение «Глава 1 пройдена» при финале 100%');
});
+106
View File
@@ -0,0 +1,106 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Математика 5 · Глава 1 · Натуральные числа</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/math6.css">
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/math6_svg.js" defer></script>
<script src="/js/math6_anim.js" defer></script>
<script src="/js/math6_engine.js" defer></script>
<style>:root{--pri:#4f46e5;--pri2:#3730a3;--pri-soft:#e0e7ff;--acc:#6366f1;--acc2:#4f46e5;--acc-soft:#eef2ff}</style>
</head>
<body>
<header class="hdr" data-wm="123">
<div class="hdr-row">
<div>
<h1>Математика 5 · Глава 1</h1>
<div class="hdr-sub">Натуральные числа: запись и разряды · сравнение и округление · действия · делимость · простые числа</div>
</div>
<div class="hdr-side">
<a href="/textbook/math-5" class="hdr-btn" title="Ко всем главам"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К математике 5</a>
<button id="search-btn" class="hdr-btn" title="Поиск (Ctrl+K)"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> <span>Поиск</span></button>
<button id="sidebar-btn" class="hdr-btn" title="Шпаргалка"><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" title="Сменить тему"><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>
<main class="main">
<div class="col-main">
<section class="hero" data-wm="123">
<h2>Натуральные числа</h2>
<p>Натуральные числа — те, которыми мы считаем предметы: $1, 2, 3, \dots$ В этой главе мы научимся <b>читать и записывать</b> большие числа по разрядам, <b>сравнивать и округлять</b> их, выполнять <b>все четыре действия</b>, возводить в <b>степень</b>, делить <b>с остатком</b>, а также разберём <b>делимость</b>: делители и кратные, НОД и НОК, признаки делимости, простые и составные числа.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p1')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 1</button>
<div class="hero-progress"><span class="hp-label">Прогресс по главе</span><div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div><span id="hero-hp-text" class="hp-text">0%</span></div>
<div id="hero-xp-badge" class="hero-xp-badge" title="Опыт" data-gamified></div>
</div>
</section>
<section class="psel"><div class="psel-title">Параграфы главы</div><div id="psel-grid" class="psel-grid"></div></section>
<div id="sections"></div>
</div>
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
<div class="col-side-backdrop" id="col-side-backdrop"></div>
</main>
<footer class="foot" id="m6-foot">Интерактивный учебник «Математика 5» · Глава 1 · Натуральные числа · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
<div id="gloss-tip" class="gloss-tip"></div>
<div id="search-modal" class="search-modal" role="dialog" aria-label="Поиск по главе">
<div class="search-box">
<input type="text" id="search-input" class="search-input" placeholder="Поиск: понятие, действие, параграф…" autocomplete="off">
<div id="search-results" class="search-results"></div>
<div class="search-foot"><span><kbd>&#8593;&#8595;</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
</div>
</div>
<script>
'use strict';
window.M6 = {
slug: 'math-5-ch1', lsPrefix: 'math5_ch1', xpKey: 'math5_xp', wm: '123',
paras: [
{ id:'p1', num:'§ 1', name:'Как решать задачу', sub:'Условие, план, решение, проверка' },
{ id:'p2', num:'§ 2', name:'Натуральные числа и нуль. Чтение и запись', sub:'Разряды и классы' },
{ id:'p3', num:'§ 3', name:'Сравнение натуральных чисел', sub:'Что больше' },
{ id:'p4', num:'§ 4', name:'Точка, прямая, луч, отрезок, плоскость', sub:'Начала геометрии' },
{ id:'p5', num:'§ 5', name:'Измерение отрезков. Длина отрезка', sub:'Линейка и единицы длины' },
{ id:'p6', num:'§ 6', name:'Координатный луч', sub:'Число как точка на луче' },
{ id:'p7', num:'§ 7', name:'Округление натуральных чисел', sub:'До нужного разряда' },
{ id:'p8', num:'§ 8', name:'Сложение и вычитание', sub:'В столбик' },
{ id:'p9', num:'§ 9', name:'Умножение и деление', sub:'В столбик и уголком' },
{ id:'p10', num:'§ 10', name:'Степень числа', sub:'Квадрат и куб' },
{ id:'p11', num:'§ 11', name:'Деление с остатком', sub:'a = b·q + r' },
{ id:'p12', num:'§ 12', name:'Делители и кратные. НОД и НОК', sub:'Общие делители и кратные' },
{ id:'p13', num:'§ 13', name:'Признаки делимости', sub:'На 2, 3, 4, 5, 9, 10' },
{ id:'p14', num:'§ 14', name:'Простые и составные числа', sub:'Разложение на множители' },
{ id:'p15', num:'§ 15', name:'Математика вокруг нас', sub:'Числа в жизни', applied:true },
{ id:'p16', num:'§ 16', name:'Движение, взвешивание, переливание', sub:'Задачи-головоломки', applied:true },
{ id:'p17', num:'§ 17', name:'Исторические сведения о числах', sub:'Как считали разные народы', applied:true },
{ id:'final', num:'★', name:'Финал главы', sub:'Тест · боссы главы 1', final:true }
],
achLabels: { final_done:'Глава 1 пройдена!' },
finalAch: ['ch1_done', 'Глава 1 «Натуральные числа» пройдена!'],
sidebars: {}, tips: [], glossary: [], searchRows: [], builders: {},
footer: 'Интерактивный учебник «Математика 5» · Глава 1 · Натуральные числа · LearnSpace'
};
</script>
</body>
</html>
+98
View File
@@ -0,0 +1,98 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Математика 5 · Глава 2 · Выражения. Уравнения</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/math6.css">
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/math6_svg.js" defer></script>
<script src="/js/math6_anim.js" defer></script>
<script src="/js/math6_engine.js" defer></script>
<style>:root{--pri:#0d9488;--pri2:#0f766e;--pri-soft:#ccfbf1;--acc:#14b8a6;--acc2:#0d9488;--acc-soft:#f0fdfa}</style>
</head>
<body>
<header class="hdr" data-wm="x=">
<div class="hdr-row">
<div>
<h1>Математика 5 · Глава 2</h1>
<div class="hdr-sub">Выражения и уравнения: порядок действий · переменные · корень уравнения · формулы · углы</div>
</div>
<div class="hdr-side">
<a href="/textbook/math-5" class="hdr-btn" title="Ко всем главам"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К математике 5</a>
<button id="search-btn" class="hdr-btn" title="Поиск (Ctrl+K)"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> <span>Поиск</span></button>
<button id="sidebar-btn" class="hdr-btn" title="Шпаргалка"><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" title="Сменить тему"><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>
<main class="main">
<div class="col-main">
<section class="hero" data-wm="x=">
<h2>Выражения. Уравнения</h2>
<p>Математика говорит на языке <b>выражений</b> и <b>формул</b>. В этой главе мы научимся вычислять числовые выражения, соблюдая <b>порядок действий</b>, работать с <b>выражениями с переменными</b>, решать <b>уравнения</b> (искать неизвестное), пользоваться <b>формулами</b> периметра, площади и пути, а ещё — <b>измерять и строить углы</b> транспортиром.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p1')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 1</button>
<div class="hero-progress"><span class="hp-label">Прогресс по главе</span><div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div><span id="hero-hp-text" class="hp-text">0%</span></div>
<div id="hero-xp-badge" class="hero-xp-badge" title="Опыт" data-gamified></div>
</div>
</section>
<section class="psel"><div class="psel-title">Параграфы главы</div><div id="psel-grid" class="psel-grid"></div></section>
<div id="sections"></div>
</div>
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
<div class="col-side-backdrop" id="col-side-backdrop"></div>
</main>
<footer class="foot" id="m6-foot">Интерактивный учебник «Математика 5» · Глава 2 · Выражения. Уравнения · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
<div id="gloss-tip" class="gloss-tip"></div>
<div id="search-modal" class="search-modal" role="dialog" aria-label="Поиск по главе">
<div class="search-box">
<input type="text" id="search-input" class="search-input" placeholder="Поиск: понятие, действие, параграф…" autocomplete="off">
<div id="search-results" class="search-results"></div>
<div class="search-foot"><span><kbd>&#8593;&#8595;</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
</div>
</div>
<script>
'use strict';
window.M6 = {
slug: 'math-5-ch2', lsPrefix: 'math5_ch2', xpKey: 'math5_xp', wm: 'x=',
paras: [
{ id:'p1', num:'§ 1', name:'Числовые выражения', sub:'Порядок действий' },
{ id:'p2', num:'§ 2', name:'Выражения с переменными', sub:'Буква вместо числа' },
{ id:'p3', num:'§ 3', name:'Уравнение', sub:'Корень уравнения' },
{ id:'p4', num:'§ 4', name:'Формулы', sub:'Периметр, площадь, путь' },
{ id:'p5', num:'§ 5', name:'Решение задач с помощью уравнений', sub:'Составляем уравнение' },
{ id:'p6', num:'§ 6', name:'Угол. Измерение и построение углов', sub:'Транспортир' },
{ id:'p7', num:'§ 7', name:'Математика вокруг нас', sub:'Выражения и формулы в жизни', applied:true },
{ id:'p8', num:'§ 8', name:'Занимательные задачи', sub:'Головоломки', applied:true },
{ id:'p9', num:'§ 9', name:'Исторические сведения', sub:'Как появились уравнения', applied:true },
{ id:'final', num:'★', name:'Финал главы', sub:'Тест · боссы главы 2', final:true }
],
achLabels: { final_done:'Глава 2 пройдена!' },
finalAch: ['ch2_done', 'Глава 2 «Выражения. Уравнения» пройдена!'],
sidebars: {}, tips: [], glossary: [], searchRows: [], builders: {},
footer: 'Интерактивный учебник «Математика 5» · Глава 2 · Выражения. Уравнения · LearnSpace'
};
</script>
</body>
</html>
+107
View File
@@ -0,0 +1,107 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Математика 5 · Глава 3 · Обыкновенные дроби</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/math6.css">
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/math6_svg.js" defer></script>
<script src="/js/math6_anim.js" defer></script>
<script src="/js/math6_engine.js" defer></script>
<style>:root{--pri:#e11d48;--pri2:#be123c;--pri-soft:#ffe4e6;--acc:#f43f5e;--acc2:#e11d48;--acc-soft:#fff1f2}</style>
</head>
<body>
<header class="hdr" data-wm="¾">
<div class="hdr-row">
<div>
<h1>Математика 5 · Глава 3</h1>
<div class="hdr-sub">Обыкновенные дроби: доли · смешанные числа · действия · многоугольники · площадь и объём</div>
</div>
<div class="hdr-side">
<a href="/textbook/math-5" class="hdr-btn" title="Ко всем главам"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К математике 5</a>
<button id="search-btn" class="hdr-btn" title="Поиск (Ctrl+K)"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> <span>Поиск</span></button>
<button id="sidebar-btn" class="hdr-btn" title="Шпаргалка"><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" title="Сменить тему"><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>
<main class="main">
<div class="col-main">
<section class="hero" data-wm="¾">
<h2>Обыкновенные дроби</h2>
<p>Дробь показывает <b>часть целого</b>: половина пиццы, четверть часа, две трети пути. В этой главе мы научимся записывать и сокращать дроби, переводить <b>неправильные дроби в смешанные числа</b>, сравнивать дроби, выполнять <b>сложение, вычитание, умножение и деление</b> дробей, а попутно изучим геометрию: <b>параллельные и перпендикулярные прямые</b>, <b>периметр</b> многоугольников, <b>площадь</b> и <b>объём</b> параллелепипеда.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p1')"><svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg> Начать § 1</button>
<div class="hero-progress"><span class="hp-label">Прогресс по главе</span><div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div><span id="hero-hp-text" class="hp-text">0%</span></div>
<div id="hero-xp-badge" class="hero-xp-badge" title="Опыт" data-gamified></div>
</div>
</section>
<section class="psel"><div class="psel-title">Параграфы главы</div><div id="psel-grid" class="psel-grid"></div></section>
<div id="sections"></div>
</div>
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
<div class="col-side-backdrop" id="col-side-backdrop"></div>
</main>
<footer class="foot" id="m6-foot">Интерактивный учебник «Математика 5» · Глава 3 · Обыкновенные дроби · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><polygon points="12,2 22,20 2,20"/></svg><span id="ach-text">Достижение!</span></div>
<div id="gloss-tip" class="gloss-tip"></div>
<div id="search-modal" class="search-modal" role="dialog" aria-label="Поиск по главе">
<div class="search-box">
<input type="text" id="search-input" class="search-input" placeholder="Поиск: понятие, действие, параграф…" autocomplete="off">
<div id="search-results" class="search-results"></div>
<div class="search-foot"><span><kbd>&#8593;&#8595;</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
</div>
</div>
<script>
'use strict';
window.M6 = {
slug: 'math-5-ch3', lsPrefix: 'math5_ch3', xpKey: 'math5_xp', wm: '¾',
paras: [
{ id:'p1', num:'§ 1', name:'Дробные числа. Обыкновенные дроби', sub:'Доли целого' },
{ id:'p2', num:'§ 2', name:'Деление и дроби. Основное свойство дроби', sub:'Сокращение дробей' },
{ id:'p3', num:'§ 3', name:'Правильные, неправильные и смешанные числа', sub:'Целая и дробная части' },
{ id:'p4', num:'§ 4', name:'Сравнение дробных чисел', sub:'Какая дробь больше' },
{ id:'p5', num:'§ 5', name:'Сложение и вычитание обыкновенных дробей', sub:'Общий знаменатель' },
{ id:'p6', num:'§ 6', name:'Сложение и вычитание смешанных чисел', sub:'Целые и дроби вместе' },
{ id:'p7', num:'§ 7', name:'Умножение дробных чисел', sub:'Дробь на дробь' },
{ id:'p8', num:'§ 8', name:'Деление дробных чисел', sub:'Умножаем на обратную' },
{ id:'p9', num:'§ 9', name:'Задачи на все действия с дробями', sub:'Комбинируем действия' },
{ id:'p10', num:'§ 10', name:'Задачи на применение дробей', sub:'Часть от числа' },
{ id:'p11', num:'§ 11', name:'Параллельные и перпендикулярные прямые', sub:'∥ и ⟂' },
{ id:'p12', num:'§ 12', name:'Ломаная. Многоугольник. Периметр', sub:'Сумма длин сторон' },
{ id:'p13', num:'§ 13', name:'Площадь. Единицы измерения площади', sub:'Квадратные единицы' },
{ id:'p14', num:'§ 14', name:'Площадь прямоугольного треугольника', sub:'Половина прямоугольника' },
{ id:'p15', num:'§ 15', name:'Среднее арифметическое', sub:'Сумма ÷ количество' },
{ id:'p16', num:'§ 16', name:'Линейные и столбчатые диаграммы', sub:'Читаем данные' },
{ id:'p17', num:'§ 17', name:'Прямоугольный параллелепипед. Куб', sub:'Грани, рёбра, вершины' },
{ id:'p18', num:'§ 18', name:'Объём параллелепипеда', sub:'Считаем единичные кубики' },
{ id:'final', num:'★', name:'Финал главы', sub:'Тест · боссы главы 3', final:true }
],
achLabels: { final_done:'Глава 3 пройдена!' },
finalAch: ['ch3_done', 'Глава 3 «Обыкновенные дроби» пройдена!'],
sidebars: {}, tips: [], glossary: [], searchRows: [], builders: {},
footer: 'Интерактивный учебник «Математика 5» · Глава 3 · Обыкновенные дроби · LearnSpace'
};
</script>
</body>
</html>
+328
View File
@@ -0,0 +1,328 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Математика 5 класс — учебник</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&family=Unbounded:wght@400;700;800;900&display=swap" rel="stylesheet">
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<style>
:root{
--bg:#f5f6ff; --card:#fff;
--text:#16162e; --muted:#5b5b78;
--border:#e4e6f7;
--pri:#4f46e5; --pri-d:#3730a3;
--pri-soft:#e0e7ff;
--c1:#4f46e5; --c1-d:#3730a3; /* гл.1 — indigo */
--c2:#0d9488; --c2-d:#0f766e; /* гл.2 — teal */
--c3:#e11d48; --c3-d:#be123c; /* гл.3 — rose */
--sh:0 4px 16px rgba(79,70,229,.10);
--sh-h:0 12px 36px rgba(79,70,229,.18);
}
html.dark{
--bg:#0a0a16; --card:#13131f;
--text:#e8eaf6; --muted:#9aa0c0;
--border:#26263a;
--pri-soft:rgba(79,70,229,.16);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{min-height:100vh}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;transition:background .25s,color .25s}
.hdr{position:relative;background:linear-gradient(110deg,#312e81 0%,#4f46e5 55%,#818cf8 100%);color:#fff;padding:32px 24px 28px;overflow:hidden;border-bottom:2px solid rgba(199,210,254,.18)}
.hdr::before{content:'5';position:absolute;right:24px;top:-30%;font-family:'Unbounded',sans-serif;font-size:clamp(7rem,20vw,15rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(224,231,255,.16);line-height:1;pointer-events:none;user-select:none}
.hdr-inner{position:relative;z-index:1;max-width:1100px;margin:0 auto;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.hdr-back{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;background:rgba(255,255,255,.16);border-radius:9px;color:#fff;text-decoration:none;font-size:.85rem;font-weight:600;transition:background .15s}
.hdr-back:hover{background:rgba(255,255,255,.26)}
.hdr h1{font-family:'Outfit',sans-serif;font-size:1.85rem;font-weight:900;letter-spacing:-.01em}
.hdr-sub{font-size:.92rem;opacity:.9;margin-top:4px}
.hdr-side{margin-left:auto;display:flex;gap:8px}
.hdr-btn{padding:8px 12px;background:rgba(255,255,255,.16);border:none;color:#fff;border-radius:9px;cursor:pointer;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;font-family:inherit}
.hdr-btn:hover{background:rgba(255,255,255,.26)}
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
.prog-overall{background:linear-gradient(135deg,var(--pri-soft),rgba(13,148,136,.10));border:1px solid var(--border);border-radius:14px;padding:14px 18px;margin-bottom:28px;display:flex;gap:14px;align-items:center;flex-wrap:wrap}
.po-icon{width:46px;height:46px;border-radius:12px;background:linear-gradient(135deg,#4f46e5,#0d9488);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-family:'Outfit',sans-serif;font-size:1.4rem;font-weight:900}
.po-text{flex:1;min-width:160px}
.po-label{font-size:.78rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:4px}
.po-bar{height:8px;background:rgba(79,70,229,.14);border-radius:5px;overflow:hidden;margin-top:6px}
.po-fill{height:100%;background:linear-gradient(90deg,var(--pri),#0d9488);border-radius:5px;transition:width .5s}
.po-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;background:linear-gradient(135deg,#f59e0b,var(--pri));color:#fff;border-radius:99px;font-size:.8rem;font-weight:800;font-family:'Unbounded',sans-serif;letter-spacing:.02em;box-shadow:0 4px 12px rgba(79,70,229,.22)}
.ch-grid{display:grid;grid-template-columns:1fr;gap:18px;margin-bottom:30px}
@media(min-width:620px){.ch-grid{grid-template-columns:1fr 1fr}}
@media(min-width:980px){.ch-grid{grid-template-columns:1fr 1fr 1fr}}
.ch-card{background:var(--card);border:1.5px solid var(--border);border-radius:18px;overflow:hidden;display:flex;flex-direction:column;transition:transform .2s,box-shadow .2s,border-color .2s;cursor:pointer;text-decoration:none;color:inherit}
.ch-card:hover{transform:translateY(-4px);box-shadow:var(--sh-h)}
.ch-cover{padding:22px 22px 18px;color:#fff;position:relative;overflow:hidden;min-height:118px}
.ch-cover-wm{position:absolute;right:2px;top:-14px;font-size:4.2rem;font-weight:900;font-family:'Unbounded',sans-serif;line-height:1;color:rgba(255,255,255,.20);pointer-events:none;letter-spacing:-.03em}
.ch-num{display:inline-block;padding:4px 10px;background:rgba(255,255,255,.24);border-radius:99px;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;margin-bottom:8px;position:relative;z-index:1}
.ch-title{font-family:'Outfit',sans-serif;font-size:1.1rem;font-weight:800;letter-spacing:-.01em;position:relative;z-index:1;line-height:1.3}
.ch-range{font-size:.84rem;opacity:.92;margin-top:4px;position:relative;z-index:1;font-weight:500}
.ch-cover.cc1{background:linear-gradient(135deg,#312e81,#4f46e5 60%,#818cf8)}
.ch-cover.cc2{background:linear-gradient(135deg,#115e59,#0d9488 60%,#2dd4bf)}
.ch-cover.cc3{background:linear-gradient(135deg,#881337,#e11d48 60%,#fb7185)}
.ch-body{padding:16px 20px 18px;display:flex;flex-direction:column;flex:1}
.ch-desc{font-size:.88rem;color:var(--text);opacity:.84;flex:1;margin-bottom:12px;line-height:1.55}
.ch-prog{margin-bottom:12px}
.ch-prog-label{display:flex;justify-content:space-between;font-size:.74rem;color:var(--muted);font-weight:600;margin-bottom:4px}
.ch-prog-bar{height:6px;background:rgba(0,0,0,.07);border-radius:4px;overflow:hidden}
.ch-prog-fill{height:100%;border-radius:4px;transition:width .5s}
.ch-card.k1 .ch-prog-fill{background:linear-gradient(90deg,var(--c1),var(--c1-d))}
.ch-card.k2 .ch-prog-fill{background:linear-gradient(90deg,var(--c2),var(--c2-d))}
.ch-card.k3 .ch-prog-fill{background:linear-gradient(90deg,var(--c3),var(--c3-d))}
.ch-action{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:11px;font-weight:700;font-size:.9rem;color:#fff;transition:filter .15s}
.ch-action:hover{filter:brightness(1.08)}
.ch-card.k1 .ch-action{background:linear-gradient(135deg,var(--c1),#818cf8)}
.ch-card.k2 .ch-action{background:linear-gradient(135deg,var(--c2),#2dd4bf)}
.ch-card.k3 .ch-action{background:linear-gradient(135deg,var(--c3),#fb7185)}
.ach-strip{background:var(--card);border:1.5px solid var(--border);border-radius:16px;padding:18px 22px;margin-bottom:28px;display:flex;align-items:center;gap:16px;transition:border-color .4s,box-shadow .4s}
.ach-strip.lit{border-color:#f59e0b;box-shadow:0 0 0 3px rgba(245,158,11,.18)}
.ach-icon{width:52px;height:52px;border-radius:14px;background:rgba(0,0,0,.06);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .4s}
.ach-strip.lit .ach-icon{background:linear-gradient(135deg,#fbbf24,#f59e0b)}
.ach-icon svg{width:28px;height:28px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ach-strip.lit .ach-icon svg{stroke:#fff}
.ach-text{flex:1}
.ach-title{font-weight:800;font-size:1.02rem;color:var(--text)}
.ach-sub{font-size:.85rem;color:var(--muted);margin-top:2px}
.ach-strip.lit .ach-title{color:#92400e}
/* COURSE FINAL */
.cf-wrap{background:var(--card);border:1.5px solid var(--border);border-radius:18px;overflow:hidden;margin-bottom:28px;box-shadow:var(--sh)}
.cf-head{padding:18px 22px;background:linear-gradient(135deg,#312e81,#4f46e5 55%,#0d9488);color:#fff;cursor:pointer;display:flex;align-items:center;gap:14px;user-select:none}
.cf-head:hover{filter:brightness(1.07)}
.cf-hi{width:46px;height:46px;border-radius:12px;background:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.cf-hi svg{width:26px;height:26px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.cf-ht{flex:1;min-width:0}
.cf-tag{display:inline-block;padding:3px 9px;background:rgba(255,255,255,.24);border-radius:99px;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;margin-bottom:4px}
.cf-title{font-family:'Outfit',sans-serif;font-size:1.18rem;font-weight:800;line-height:1.25}
.cf-sub{font-size:.84rem;opacity:.9;margin-top:2px}
.cf-chev{flex-shrink:0;transition:transform .25s}
.cf-chev svg{width:24px;height:24px;stroke:#fff;fill:none;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.cf-wrap.open .cf-chev{transform:rotate(180deg)}
.cf-body{display:none;padding:22px}
.cf-wrap.open .cf-body{display:block}
.cf-hp{height:14px;background:rgba(220,38,38,.12);border-radius:9px;overflow:hidden;border:1px solid #fecaca;margin:6px 0 12px}
.cf-hp-fill{height:100%;background:linear-gradient(90deg,#dc2626,#f59e0b);border-radius:9px;transition:width .5s}
.cf-meta{display:flex;gap:16px;font-size:.9rem;color:var(--muted);margin-bottom:10px;font-weight:600}
.cf-name{font-weight:800;color:#4338ca;text-align:center;margin-bottom:6px}
.cf-q{font-size:1.05rem;line-height:1.5;padding:12px 14px;background:var(--pri-soft);border-radius:9px;margin-bottom:10px;text-align:center}
.cf-row{display:flex;gap:10px;justify-content:center;align-items:center;flex-wrap:wrap}
.cf-inp{padding:9px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);width:140px;text-align:center;font-family:'Outfit',monospace;font-size:1rem}
.cf-btn{padding:9px 18px;border-radius:9px;background:linear-gradient(135deg,#4f46e5,#0d9488);color:#fff;font-weight:700;border:none;cursor:pointer}
.cf-fb{margin-top:10px;padding:10px 14px;border-radius:9px;font-weight:600;font-size:.9rem;display:none}
.cf-fb.ok{display:block;background:#d1fae5;color:#065f46}
.cf-fb.bad{display:block;background:#fee2e2;color:#7f1d1d}
.foot{text-align:center;padding:24px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border)}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-inner">
<div>
<a href="/textbooks" class="hdr-back">
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
К каталогу
</a>
</div>
<div>
<h1>Математика — 5 класс</h1>
<div class="hdr-sub">Натуральные числа · делимость · выражения и уравнения · углы · обыкновенные дроби · площадь и объём</div>
</div>
<div class="hdr-side">
<button id="theme-btn" class="hdr-btn" title="Сменить тему">
<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>
<main>
<section class="prog-overall">
<div class="po-icon"></div>
<div class="po-text">
<div class="po-label">Общий прогресс по курсу</div>
<div id="overall-text" style="font-size:1.05rem;font-weight:700">Загрузка...</div>
<div class="po-bar"><div id="overall-fill" class="po-fill" style="width:0%"></div></div>
</div>
<div id="hero-xp-badge" class="po-xp" style="display:none" data-gamified>0 XP</div>
</section>
<div class="ch-grid">
<a href="/textbook/math-5-ch1" class="ch-card k1" id="ch-1">
<div class="ch-cover cc1"><div class="ch-cover-wm">123</div>
<div class="ch-num">Глава 1</div>
<div class="ch-title">Натуральные числа</div>
<div class="ch-range">§1–§17</div>
</div>
<div class="ch-body">
<div class="ch-desc">Чтение и запись чисел, разряды, сравнение и округление, все четыре действия, степень, деление с остатком, делимость, НОД и НОК, простые числа.</div>
<div class="ch-prog"><div class="ch-prog-label"><span>Прогресс</span><span id="prog-1">0%</span></div><div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-1" style="width:0%"></div></div></div>
<div class="ch-action"><span id="btn-1">Открыть главу</span><svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
</div>
</a>
<a href="/textbook/math-5-ch2" class="ch-card k2" id="ch-2">
<div class="ch-cover cc2"><div class="ch-cover-wm">x=</div>
<div class="ch-num">Глава 2</div>
<div class="ch-title">Выражения. Уравнения</div>
<div class="ch-range">§1–§9</div>
</div>
<div class="ch-body">
<div class="ch-desc">Числовые выражения и порядок действий, выражения с переменными, уравнение и его корень, формулы, решение задач уравнением, измерение и построение углов.</div>
<div class="ch-prog"><div class="ch-prog-label"><span>Прогресс</span><span id="prog-2">0%</span></div><div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-2" style="width:0%"></div></div></div>
<div class="ch-action"><span id="btn-2">Открыть главу</span><svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
</div>
</a>
<a href="/textbook/math-5-ch3" class="ch-card k3" id="ch-3">
<div class="ch-cover cc3"><div class="ch-cover-wm">¾</div>
<div class="ch-num">Глава 3</div>
<div class="ch-title">Обыкновенные дроби</div>
<div class="ch-range">§1–§18</div>
</div>
<div class="ch-body">
<div class="ch-desc">Доли и обыкновенные дроби, основное свойство, смешанные числа, сравнение и все действия, задачи на дроби, прямые, многоугольники, периметр, площадь и объём.</div>
<div class="ch-prog"><div class="ch-prog-label"><span>Прогресс</span><span id="prog-3">0%</span></div><div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-3" style="width:0%"></div></div></div>
<div class="ch-action"><span id="btn-3">Открыть главу</span><svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></div>
</div>
</a>
</div>
<div class="cf-wrap" id="cf-wrap">
<div class="cf-head" id="cf-head">
<div class="cf-hi"><svg viewBox="0 0 24 24"><polygon points="12 2 15 9 22 9 17 14 19 22 12 17 5 22 7 14 2 9 9 9"/></svg></div>
<div class="cf-ht">
<span class="cf-tag">Курсовой финал</span>
<div class="cf-title">3 испытания — по одному из каждой главы</div>
<div class="cf-sub">Победи 2 из 3 и получи звание «Математик 5 класса» (+150 XP)</div>
</div>
<div class="cf-chev"><svg viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"/></svg></div>
</div>
<div class="cf-body">
<div class="cf-hp"><div class="cf-hp-fill" id="cf-hp" style="width:100%"></div></div>
<div class="cf-meta"><span>Испытание <b id="cf-i">1</b> / 3</span><span>Пройдено: <b id="cf-s">0</b> / 3</span></div>
<div class="cf-name" id="cf-name"></div>
<div class="cf-q" id="cf-q"></div>
<div class="cf-row"><input type="text" id="cf-a" class="cf-inp" placeholder="ответ"><button class="cf-btn" id="cf-go">Ответить</button></div>
<div class="cf-fb" id="cf-fb"></div>
</div>
</div>
<div class="ach-strip" id="ach-strip">
<div class="ach-icon">
<svg viewBox="0 0 24 24"><path d="M6 9H4l-1-3h18l-1 3h-2M6 9l1 6h10l1-6M6 9h12"/><path d="M9 21h6M12 15v6"/></svg>
</div>
<div class="ach-text">
<div class="ach-title">Математик 5 класса</div>
<div class="ach-sub" id="ach-sub">Пройдите все параграфы трёх глав, чтобы получить достижение</div>
</div>
</div>
</main>
<footer class="foot">Интерактивный учебник «Математика — 5 класс» · LearnSpace</footer>
<script>
'use strict';
(function(){
var saved = localStorage.getItem('math5_theme') || localStorage.getItem('theme') || 'light';
if (saved === 'dark') document.documentElement.classList.add('dark');
var lab = document.getElementById('theme-lab'); if (lab) lab.textContent = saved === 'dark' ? 'Светлая' : 'Тёмная';
document.getElementById('theme-btn').addEventListener('click', function(){
document.documentElement.classList.toggle('dark');
var dark = document.documentElement.classList.contains('dark');
localStorage.setItem('math5_theme', dark ? 'dark' : 'light'); localStorage.setItem('theme', dark ? 'dark' : 'light');
if (lab) lab.textContent = dark ? 'Светлая' : 'Тёмная';
});
})();
var TOTAL = 47;
var CH_IDX = { 'math-5-ch1':1,'math-5-ch2':2,'math-5-ch3':3 };
var CH_PARA = { 'math-5-ch1':18,'math-5-ch2':10,'math-5-ch3':19 };
function setChProg(idx, read, total){
var pct = total ? Math.round(read*100/total) : 0;
var l=document.getElementById('prog-'+idx),f=document.getElementById('fill-'+idx),b=document.getElementById('btn-'+idx);
if(l)l.textContent=pct+'%'; if(f)f.style.width=pct+'%';
if(b){ if(read>0&&read<total)b.textContent='Продолжить'; else if(read>=total)b.textContent='Открыть снова'; else b.textContent='Открыть главу'; }
}
function renderProgress(children){
var totalRead=0;
for(var i=0;i<children.length;i++){ var ch=children[i],idx=CH_IDX[ch.slug]; if(!idx)continue; var read=ch.progress?ch.progress.read.length:0; var total=ch.para_count||CH_PARA[ch.slug]||1; totalRead+=read; setChProg(idx,read,total); }
var pct=Math.round(totalRead*100/TOTAL);
var o=document.getElementById('overall-text'),f=document.getElementById('overall-fill');
if(o)o.textContent=totalRead+' из '+TOTAL+' параграфов · '+pct+'%'; if(f)f.style.width=pct+'%';
var xpBadge=document.getElementById('hero-xp-badge'),xp=parseInt(localStorage.getItem('math5_xp')||'0',10)||0;
if(xpBadge&&xp>0){ xpBadge.style.display=''; xpBadge.textContent=xp+' XP'; }
if(totalRead>=TOTAL){ var s=document.getElementById('ach-strip'),sub=document.getElementById('ach-sub'); if(s)s.classList.add('lit'); if(sub)sub.textContent='Выполнено! Вы прошли весь курс математики 5 класса.'; }
}
function loadProgress(){
if(typeof window.LS==='undefined'||typeof window.LS.api!=='function'){ renderProgress([]); return; }
window.LS.api('/api/textbooks/math-5/children').then(function(data){ renderProgress(data&&data.children?data.children:[]); }).catch(function(){ renderProgress([]); });
}
if(document.readyState==='loading') document.addEventListener('DOMContentLoaded', loadProgress); else loadProgress();
window.addEventListener('focus', loadProgress);
/* ===================== КУРСОВОЙ ФИНАЛ ===================== */
(function(){
function _ri(a,b){ return a + Math.floor(Math.random()*(b-a+1)); }
function _pick(a){ return a[_ri(0,a.length-1)]; }
function comma(x){ return String(x).replace('.',','); }
var head=document.getElementById('cf-head'), wrap=document.getElementById('cf-wrap');
if(!head) return;
head.addEventListener('click', function(){ wrap.classList.toggle('open'); });
function litAch(text){ var s=document.getElementById('ach-strip'), sub=document.getElementById('ach-sub'); if(s)s.classList.add('lit'); if(sub)sub.textContent=text||'Звание «Математик 5 класса» получено!'; }
if(localStorage.getItem('math5_course_done')==='1') litAch();
var bosses=[
function(){ var p=_pick([[2,5,32],[3,3,27],[5,2,25],[2,6,64],[4,3,64],[10,3,1000]]); return {name:'Глава 1 · Натуральные числа', q:'Вычисли '+p[0]+' в степени '+p[1]+'.', ans:p[2]}; },
function(){ var a=_ri(3,12), x=_ri(2,15), b=a+x; return {name:'Глава 2 · Уравнения', q:'Реши уравнение: x + '+a+' = '+b+'.', ans:x}; },
function(){ var d=_pick([4,5,3,10,2,6]), n=d*_ri(2,7), m=_ri(1,d-1); return {name:'Глава 3 · Дроби', q:'Найди '+m+'/'+d+' от числа '+n+'.', ans:n*m/d}; }
];
var i=0, score=0, cur=null, done=false;
function show(){
if(i>=3){ done=true;
document.getElementById('cf-name').textContent='';
document.getElementById('cf-q').innerHTML=(score>=2?'<b>Победа!</b> Звание «Математик 5 класса» ваше!':'<b>Бой окончен.</b> Пройдено '+score+' / 3. Попробуйте ещё раз!');
document.getElementById('cf-hp').style.width=(score>=2?0:40)+'%';
document.querySelector('.cf-row').style.display='none';
if(score>=2){ if(localStorage.getItem('math5_course_done')!=='1'){ localStorage.setItem('math5_course_done','1'); if(window.LS&&window.LS.xp)window.LS.xp.add(150,'math5-course'); } litAch(); }
return; }
cur=bosses[i](); document.getElementById('cf-i').textContent=i+1; document.getElementById('cf-s').textContent=score;
document.getElementById('cf-name').textContent=cur.name;
document.getElementById('cf-hp').style.width=(100-i*100/3)+'%';
document.getElementById('cf-q').textContent=cur.q;
document.getElementById('cf-a').value=''; document.getElementById('cf-fb').style.display='none';
}
function go(){ if(done||i>=3)return; var fb=document.getElementById('cf-fb'), v=parseFloat(document.getElementById('cf-a').value.replace(',','.').trim());
if(isNaN(v)){ fb.className='cf-fb bad'; fb.textContent='Введите число.'; return; }
if(Math.abs(v-cur.ans)<0.011){ score++; fb.className='cf-fb ok'; fb.textContent='✓ Верно! Ответ '+comma(cur.ans)+'.'; }
else { fb.className='cf-fb bad'; fb.textContent='✗ Неверно. Правильно: '+comma(cur.ans)+'.'; }
document.getElementById('cf-s').textContent=score; i++; setTimeout(show,1300);
}
document.getElementById('cf-go').addEventListener('click', go);
document.getElementById('cf-a').addEventListener('keydown', function(e){ if(e.key==='Enter')go(); });
show();
})();
</script>
</body>
</html>
+191
View File
@@ -0,0 +1,191 @@
# PLAN — Интерактивный учебник «Математика. 5 класс»
> Составлен 2026-06-03 (Opus). Источник: **Герасимов В. Д., Пирютко О. Н., Лобанов А. П.
> «Математика. 5 класс»**, в 2 частях, Минск: Адукацыя і выхаванне, 2020 (2-е изд.).
> PDF: `G:\Dev\Тесты\Методички\Разное\Книги\matematika_5kl_ch1_gerasimov_rus_2020 (1).pdf` (181 стр.)
> и `…_ch2_… .pdf` (197 стр.). Контент пишем авторский (свой), не копируем книгу.
Цель: красивый, **интерактивный, визуальный** учебник того же класса качества, что
«Математика 6», — с тренажёрами, canvas/SVG-анимациями, пошаговыми разборами, финалами-боссами
и курсовым финалом. Реализация — Opus делает фундамент + эталонную Главу 1, Главы 2–3 тиражирует
Sonnet по образцу.
---
## 1. Структура книги (оглавление, 3 главы)
Книга Герасимова **переплетает геометрию внутрь числовых глав** (это её замысел) — не выделяем
геометрию отдельно, а сохраняем авторский порядок.
### Часть 1
**Глава 1. Натуральные числа** (§1–17)
1. Как решать задачу
2. Натуральные числа и число нуль. Чтение и запись
3. Сравнение натуральных чисел
4. Точка, прямая, луч, отрезок, плоскость
5. Измерение отрезков. Длина отрезка
6. Изображение натуральных чисел на координатном луче
7. Округление натуральных чисел
8. Сложение и вычитание натуральных чисел
9. Умножение и деление натуральных чисел
10. Степень числа с натуральным показателем
11. Деление с остатком
12. Делители, кратные. НОД и НОК
13. Признаки делимости
14. Простые и составные числа. Разложение на множители
15. *Математика вокруг нас* (прикладной)
16. *Задачи на движение, взвешивание, переливание* (занимательный/прикладной)
17. *Исторические сведения о числах* (история)
**Глава 2. Выражения. Уравнения** (§19)
1. Числовые выражения
2. Выражения с переменными
3. Уравнение
4. Формулы
5. Решение задач с помощью уравнений
6. Угол. Измерение и построение углов
7. *Математика вокруг нас* (прикладной)
8. *Занимательные задачи*
9. *Исторические сведения*
### Часть 2
**Глава 3. Обыкновенные дроби** (§1–18)
1. Дробные числа. Обыкновенные дроби
2. Деление и дроби. Основное свойство дроби
3. Правильные и неправильные дроби. Смешанные числа
4. Сравнение дробных чисел
5. Сложение и вычитание обыкновенных дробей
6. Сложение и вычитание смешанных чисел
7. Умножение дробных чисел
8. Деление дробных чисел
9. Задачи на все действия с дробными числами
10. Задачи на применение дробей
11. Параллельные и перпендикулярные прямые *(геом.)*
12. Ломаная. Многоугольник. Периметр *(геом.)*
13. Площадь. Единицы измерения площади *(геом.)*
14. Площадь прямоугольного треугольника и многоугольников *(геом.)*
15. Среднее арифметическое
16. Линейные и столбчатые диаграммы
17. Прямоугольный параллелепипед. Куб *(геом.)*
18. Объём. Единицы измерения объёма. Объём параллелепипеда *(геом.)*
> Бэк-материя ч.2 (Задачи с геом. фигурами, Повторение и обобщение, Задания для тренировки,
> Задачи для любознательных, Логические задачи, Наглядная геометрия) — **банки упражнений**, не §.
> Из них черпаем задачи для тренажёров и финала, отдельными § не делаем.
Каждая глава в книге завершается **тестом** («Ответы к тесту: 1в); 2г)…») → в нашем учебнике это
**Финал главы** (бой с боссами).
---
## 2. Архитектура — ПОЛНОЕ переиспользование движка «Математики 6»
Движок `math6_engine.js` уже **generic**: читает `window.M6` со своими `slug / lsPrefix / xpKey`,
строит para-selector, навигацию, прогресс/XP/достижения, сайдбар, поиск, глоссарий, тему, финалы.
**Ничего форкать не нужно.** Страницы 5 класса подключают те же ассеты:
```
/css/math6.css (общий фреймворк)
/js/api.js /js/xp.js
/js/math6_svg.js (window.Math6 — статичные SVG-фигуры)
/js/math6_anim.js (window.Math6Anim — canvas/SVG-демо) ← ПЕРЕД engine
/js/math6_engine.js (window.M6engine — плумбинг)
```
> Эти файлы — общая **визуальная библиотека математики**, а не «6 класс». Новые компоненты для
> 5 класса дописываем в `math6_svg.js` / `math6_anim.js` (выигрывают обе параллели). При желании
> позже переименуем в `math_svg.js` — сейчас не трогаем имена, чтобы не плодить churn.
**Страница главы** = `head` (KaTeX CDN + шрифты + math6.css + 5 скриптов) → inline `:root`-палитра
→ chrome (`hdr / hero / psel / #sections / sidebar / search / ach-popup`) → inline `<script>`:
объявить `data + builders`, затем `Object.assign(window.M6, {...})`.
### КРИТИЧНЫЕ правила (грабли с 6 класса — не наступать снова)
- **`init()` движка вызывается ПОСЛЕ всех `window.*`-экспортов** — у defer-скрипта `readyState`
уже `interactive`, и `else init()` срабатывает синхронно. Если builder зовёт `makeCard` до экспорта
`ReferenceError` → ВСЕ §1 показывают заглушку. (В нашем случае init внутри самого движка уже
корректен — мы лишь не нарушаем порядок: `Object.assign(window.M6,…)` до подключения движка не
нужен, движок читает `window.M6` лениво в `init`.)
- **Русская запятая в KaTeX = `2{,}5`** (иначе сбитый кернинг). В JS-билдерах — хелпер `_kf(x)`.
- **`applied:true`** у прикладных/исторических § (не входят в боссов финала), **`final:true`** у финала.
- **⛔ эмодзи** — только inline SVG `.ic`. **⛔ Grep-tool** — ast-index/vex. Edit-флака на кириллице —
верифицировать зелёным тестом.
---
## 3. Маппинг глав → LearnSpace
| slug | Глава | § (paras) | para_count | Цвет |
|------|-------|-----------|-----------|------|
| `math-5` | **Хаб** | — | 47 (Σ) | indigo |
| `math-5-ch1` | Натуральные числа | p1–p14 + 3 прикладных + final | 18 | indigo `#4f46e5` |
| `math-5-ch2` | Выражения. Уравнения | p1–p6 + 3 прикладных + final | 10 | teal `#0d9488` |
| `math-5-ch3` | Обыкновенные дроби | p1p18 + final | 19 | rose `#e11d48` |
`para_count = paras.length` (включая прикладные и финал — как в 6 классе). Хаб TOTAL = 18+10+19 = **47**.
Хаб закрыт по умолчанию (allowlist) → доступ выдаём в самом конце через `/api/access` ([[project_content_access]]).
Миграция: **`050_math5_hub.sql`** (следующий свободный номер; 049 = math-6). Хаб `sort_order` = 5
(перед math-6=6), дети 1/2/3.
---
## 4. Фазы реализации (волны)
### Phase 0 — Фундамент (Opus) ✦ делаем первым
- [ ] `backend/src/db/migrations/050_math5_hub.sql` (+ `npm run migrate`)
- [ ] `frontend/textbooks/math_5_hub.html` (клон math_6_hub: 3 карточки + курсовой финал из 3 боссов
+ ach-strip «Математик 5 класса», водяной знак «5», палитра indigo/teal/rose)
- [ ] 3 каркаса `math_5_ch1.html` / `ch2` / `ch3` — head + chrome + `window.M6` ТОЛЬКО с `paras`
(без билдеров → движок рисует заглушки; страницы живые, навигация работает)
- [ ] Тест `backend/tests/math5-page.test.js` (jsdom-over-HTML, инлайнит svg/anim/engine): страницы
грузятся, секции/psel генерируются, нет рантайм-ошибок, init после экспортов
- [ ] Commit + push
### Phase 1 — Глава 1 «Натуральные числа» (эталон, Opus)
Полные билдеры §1–17 + финал. 2+ интерактива на §, тренажёры со счётом+XP, DnD, пошаговые разборы,
визуализации (см. §5). Это **образец**, по которому Sonnet делает остальное.
### Phase 2 — Глава 2 «Выражения. Уравнения» (Sonnet-агент по образцу Главы 1)
### Phase 3 — Глава 3 «Обыкновенные дроби» (Sonnet-агент; самая визуальная — дроби + геометрия)
### Phase 4 — Обогащение + полировка
По образцу 6 класса: в каждый § «Где это в жизни» (хук) / «Разбор по шагам» (→ авто-stepPlayer) /
«А знаешь ли ты?» (факт); добить визуализации; прогон тестов.
### Phase 5 — Курсовой финал на хабе + звание «Математик 5 класса» (+150 XP)
3 боссовых испытания (по одному из главы): натуральные числа · уравнение/угол · дроби.
### Phase 6 — Доступ ученикам/классам (`/api/access`) — действие админа.
---
## 5. Визуальная карта — см. `PLAN_MATH_5_VISUAL.md`
Кратко: **что уже есть** в `Math6`/`Math6Anim` (numberLine, plane, pie, venn, areaModel,
numberLineWalk/Jumps, coordGame, balanceScale, triangleDrag, stepPlayer…) переиспользуем; **новое**
для 5 класса — `protractor` (угломер, §2.6), семейство дробей (`fractionBar`, `equivFractions`,
`fractionAdd`, `fractionMulArea`, `improperMixed`), `sieve` (решето Эратосфена, §1.14), `factorTree`,
`divisibilityChecker` (§1.13), `divisorsLadder` (НОД/НОК, §1.12), `powerBlocks` (степень, §1.10),
`rulerMeasure` (§1.5), `linePrimitives` (точка/прямая/луч, §1.4), `polygonPerimeter` (§1.12 ч.2 /3.12),
`areaGrid` + `triangleArea` (§3.1314), `averageBars` (§3.15), `barChart`/`lineChart` (§3.16),
`box3d` + `volumeCubes` (§3.1718, **2D-изометрия**, не интерактивный 3D — это допустимо и нужно).
---
## 6. Геймификация / тесты / гочи
- XP/уровни (общий `math5_xp`), прогресс `math5_chN_*`, финал главы = боссы (HP-бар), 4/5 → +40 XP
и ачивка «Глава N пройдена». Курсовой финал → звание + 150 XP (`localStorage math5_course_done`).
- Тесты: `backend/tests/math5-page.test.js` по образцу math6 (jsdom, инлайн ассетов, HEADLESS-guard
canvas). Прогон: `node -e "require('./tests/math5-page.test.js')"` из `backend/`.
- pre-commit hook гоняет полный backend-прогон при staged backend-файлах (baseline 3 Auth-фейла).
- Коммитить поимённо (не `git add -A`), push сразу. fetch перед работой ([[project_concurrent_sessions_branch]]).
---
## 7. Замечание про §3.17–18 (параллелепипед, куб, объём)
В 6 классе пользователь **исключил интерактивные 3D-тела**. Здесь иначе: параллелепипед/куб/объём —
**обязательная программа** 5 класса, и рисуются стандартной **2D-изометрией** (статичный чертёж с
подписанными рёбрами + анимация заполнения единичными кубиками). Это не «3D-движок», а плоский
SVG-рисунок — включаем.
+89
View File
@@ -0,0 +1,89 @@
# PLAN — Визуализации «Математика 5»
Карта «§ → визуальный компонент». Опора — существующая библиотека `window.Math6` (статичные SVG)
и `window.Math6Anim` (canvas/SVG-демо, headless-safe). **Переиспользуем максимум**, новое дописываем
в те же два файла.
Легенда: ✅ уже есть · 🆕 новый компонент · ♻️ есть, нужна лёгкая доработка.
---
## Уже готово (наследуем без изменений)
`Math6`: `fmt, box, numberLine(line/ray, ticks, points, segments), plane(+polyline,plot), pie, venn`.
`Math6Anim`: `rollingCircle, sweepArea, areaModel, numberLineWalk, carGraph, plotLive, thermometer,
numberLineJumps, coordGame, reflectFold, barModel, setFilter, pieGrow, balanceScale, constAreaRect,
triangleDrag` + `stepPlayer`/`stepifyExamples` (авто-конвертация «Разбор по шагам» в плеер).
---
## Глава 1 — Натуральные числа
| § | Тема | Визуал | Статус |
|---|------|--------|--------|
| 1 | Как решать задачу | `stepPlayer` (схема: условие→план→решение→проверка) | ✅ |
| 2 | Чтение и запись, разряды | 🆕 `placeValue` — разрядная таблица (классы/разряды), число рассыпается на разряды | 🆕 |
| 3 | Сравнение | `numberLine` + подсветка >/< ; тренажёр | ✅ |
| 4 | Точка, прямая, луч, отрезок, плоскость | 🆕 `linePrimitives` — SVG-галерея + интерактив «проведи через 2 точки» | 🆕 |
| 5 | Измерение отрезков, длина | 🆕 `rulerMeasure` — линейка над отрезком, тащишь — читаешь длину | 🆕 |
| 6 | Координатный луч | `numberLine` (ray) + `coordGame` («поставь число») | ✅ |
| 7 | Округление | `numberLine` со «снэпом» к разряду (стрелка к ближайшему) | ♻️ |
| 8 | Сложение и вычитание | `numberLineWalk` + столбик (inline, как 6 кл.) | ✅ |
| 9 | Умножение и деление | `areaModel` (a·b) + `numberLineJumps` (прыжки) | ✅ |
| 10 | Степень | 🆕 `powerBlocks` — 2² как квадрат, 2³ как кубик (изометрия), рост основания/показателя | 🆕 |
| 11 | Деление с остатком | 🆕 `remainderGroups` — раскладка точек по группам, остаток подсвечен (a=b·q+r) | 🆕 |
| 12 | Делители, НОД, НОК | 🆕 `divisorsLadder` — лесенки кратных (НОК) + `venn` делителей (НОД) | 🆕 (venn ✅) |
| 13 | Признаки делимости | 🆕 `divisibilityChecker` — вводишь число, флажки 2/3/4/5/9/10 загораются с объяснением | 🆕 |
| 14 | Простые/составные, разложение | 🆕 `sieve` (решето Эратосфена — анимация вычёркивания) + 🆕 `factorTree` (дерево множителей) | 🆕 |
| 15 | Математика вокруг нас | прикладные карточки + любой подходящий демо | ✅ |
| 16 | Движение/взвешивание/переливание | `carGraph` (движение) + интерактив-головоломка «переливание» (state-машина) | ✅/🆕 |
| 17 | Исторические сведения | карточки «А знаешь ли ты?» (системы счисления: майя/Египет/Рим) | ✅ |
## Глава 2 — Выражения. Уравнения
| § | Тема | Визуал | Статус |
|---|------|--------|--------|
| 1 | Числовые выражения | 🆕 `exprTree` — дерево порядка действий, подсветка шага | 🆕 |
| 2 | Выражения с переменными | `exprTree` + подстановка значения (слайдер x → значение) | ♻️ |
| 3 | Уравнение | 🆕 `equationScale` — весы: x+a = b, снимаем гири поровну (наследует `balanceScale`) | 🆕 |
| 4 | Формулы | `constAreaRect` / прямоугольник P=(a+b)·2, S=a·b со слайдерами | ✅ |
| 5 | Решение задач уравнениями | `stepPlayer` | ✅ |
| 6 | Угол. Измерение и построение | 🆕 **`protractor`** — транспортир: тащишь луч, читаешь градусы, классификация (остр/прям/туп/развёрн) | 🆕 ★ключевой |
| 7 | Математика вокруг нас | прикладные карточки | ✅ |
| 8 | Занимательные задачи | головоломки/квизы | ✅ |
| 9 | Исторические сведения | карточки-факты | ✅ |
## Глава 3 — Обыкновенные дроби
| § | Тема | Визуал | Статус |
|---|------|--------|--------|
| 1 | Дробные числа, обыкн. дроби | 🆕 `fractionBar` (полоса m из n) + `pie` (доля круга) | 🆕 (pie ✅) |
| 2 | Деление и дроби, осн. свойство | 🆕 `equivFractions` — дроблю каждую долю → площадь та же (2/3 = 4/6) | 🆕 |
| 3 | Правильные/неправильные, смешанные | 🆕 `improperMixed` — полосы складываются в целые + остаток (7/3 = 2⅓) | 🆕 |
| 4 | Сравнение дробных | `fractionBar` ×2 на общей шкале / `numberLine` дробей | ♻️ |
| 5 | Сложение/вычитание обыкн. дробей | 🆕 `fractionAdd` — приведение к общему знаменателю на полосах | 🆕 |
| 6 | Сложение/вычитание смешанных | `fractionAdd` + целые части | ♻️ |
| 7 | Умножение дробных | 🆕 `fractionMulArea` — площадная модель a/b · c/d (наложение сеток) | 🆕 |
| 8 | Деление дробных | 🆕 `fractionDiv` — «сколько раз c/d помещается» (мерная модель) | 🆕 |
| 9 | Задачи на все действия | `stepPlayer` | ✅ |
| 10 | Задачи на применение дробей | `fractionBar` + сюжетные тренажёры | ♻️ |
| 11 | Параллельные/перпендикулярные | 🆕 `linesRelation` — две прямые, угол между ними, ∥ и ⟂ | 🆕 |
| 12 | Ломаная, многоугольник, периметр | 🆕 `polygonPerimeter` — строишь вершины, стороны суммируются | 🆕 |
| 13 | Площадь, единицы | 🆕 `areaGrid` — заполнение единичными квадратами, конвертер единиц | 🆕 |
| 14 | Площадь прям. треугольника | 🆕 `triangleArea` — треугольник = половина прямоугольника (анимация отражения) | 🆕 |
| 15 | Среднее арифметическое | 🆕 `averageBars` — столбики выравниваются к среднему уровню | 🆕 |
| 16 | Линейные/столбчатые диаграммы | 🆕 `barChart` + `lineChart` (plane уже умеет polyline) | 🆕 (line ♻️) |
| 17 | Параллелепипед, куб | 🆕 `box3d` — изометрический чертёж с подписанными a,b,c (НЕ интерактивный 3D) | 🆕 |
| 18 | Объём | 🆕 `volumeCubes` — заполнение коробки единичными кубиками (изометрия, анимация) | 🆕 |
---
## Сводка новых компонентов (≈22)
**SVG-статичные / интерактивные (в `math6_svg.js` или как SVG-демо):** `linePrimitives`, `rulerMeasure`,
`placeValue`, `fractionBar`, `equivFractions`, `improperMixed`, `linesRelation`, `polygonPerimeter`,
`areaGrid`, `triangleArea`, `box3d`, `factorTree`, `exprTree`.
**Canvas/анимированные (в `math6_anim.js`):** `powerBlocks`, `remainderGroups`, `divisorsLadder`,
`divisibilityChecker`, `sieve`, `protractor`, `equationScale`, `fractionAdd`, `fractionMulArea`,
`fractionDiv`, `averageBars`, `barChart`, `volumeCubes`.
Приоритет (даёт максимум «вау» при минимуме кода): `protractor`, `fractionBar`+`fractionMulArea`,
`sieve`, `box3d`+`volumeCubes`, `equationScale`. Все — headless-safe (canvas-guard / чистый SVG).