feat(math6): canvas-анимации — движок math6_anim.js + 3 флагмана

Новый headless-safe движок window.Math6Anim (по канве chem7_anim:
RAF-цикл с паузой вне экрана через IntersectionObserver, prefers-reduced-motion,
в jsdom/HeadlessChrome getContext НЕ вызывается → тесты не падают).
Демо: rollingCircle (колесо катится → путь = C=2πr=πd), sweepArea
(радиус заметает круг → S=πr²), areaModel (площадная модель умножения a·b
на сетке 0,1). Вшито: Гл.6 §2 (колесо + заметание), Гл.1 §6 (умножение).
Тесты math6: 19/19 (+canvas-демо монтируются headless-safe).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-06-02 21:24:37 +03:00
parent 85c516e811
commit 6b734957e9
4 changed files with 212 additions and 3 deletions
+5 -3
View File
@@ -17,6 +17,7 @@
<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>
@@ -532,7 +533,7 @@ function buildP6(){
+'<div class="wg-help">Двигай множители — смотри, как число знаков после запятой определяет ответ.</div>'
+'<div class="sliders"><label>Первый = <b id="p6-av">1,2</b><input type="range" id="p6-asl" min="0" max="5" value="1"></label>'
+'<label>Второй = <b id="p6-bv">0,3</b><input type="range" id="p6-bsl" min="0" max="5" value="2"></label></div>'
+'<div id="p6-out" class="qbox"></div></div>';
+'<div id="p6-out" class="qbox"></div><div id="p6-area" style="margin-top:10px"></div></div>';
h+='<div class="wg" id="p6-iv2"><div class="wg-header"><span class="wg-badge">Интерактив 2</span><div class="wg-title">Тренажёр умножения</div></div>'
+'<div class="wg-help">Перемножь десятичные дроби и введи ответ.</div>'
+'<div class="score-display"><span>Пример <b id="p6-i">1</b> / 6</span><span>Очки: <b id="p6-s">0</b> / 6</span></div>'
@@ -544,11 +545,12 @@ function buildP6(){
(function(){
var AS=[0.4,1.2,0.25,3.5,0.06,2.5], BS=[0.3,4,0.2,1.5,0.7,0.08];
var asl=document.getElementById('p6-asl'), bsl=document.getElementById('p6-bsl'), out=document.getElementById('p6-out');
var asl=document.getElementById('p6-asl'), bsl=document.getElementById('p6-bsl'), out=document.getElementById('p6-out'), area=null;
function render(){ var a=AS[+asl.value], b=BS[+bsl.value]; document.getElementById('p6-av').textContent=_kf(a).replace('{,}',','); document.getElementById('p6-bv').textContent=_kf(b).replace('{,}',',');
var da=_dec(a),db=_dec(b), ma=_mant(a,da),mb=_mant(b,db), p=ma*mb, r=p/Math.pow(10,da+db);
out.innerHTML='<div style="font-size:.95rem;color:var(--muted)">$'+ma+'\\cdot '+mb+' = '+p+'$, знаков после запятой: $'+da+'+'+db+'='+(da+db)+'$</div>'
+'<div style="font-size:1.4rem;font-weight:800;color:var(--pri2);margin-top:6px">$'+_kf(a)+'\\cdot '+_kf(b)+' = '+_kf(r)+'$</div>'; renderMath(out); }
+'<div style="font-size:1.4rem;font-weight:800;color:var(--pri2);margin-top:6px">$'+_kf(a)+'\\cdot '+_kf(b)+' = '+_kf(r)+'$</div>'; renderMath(out);
if(window.Math6Anim){ if(area)area.stop(); area=Math6Anim.areaModel(document.getElementById('p6-area'),{a:a,b:b}); } }
asl.oninput=render; bsl.oninput=render; render();
})();