feat(labs): новая симуляция «Гонка с задачами» — кинематика 1D с геймификацией

race.js (1357 строк):
- 8 сценариев: встречи (поезд+машина, 2 лодки), догон (мотоциклист, поезда), кто первый (авто vs поезд, 3 спортсмена), свободное падение vs парашют, обгон с разгоном
- Иконки movers inline SVG: car, train, bike, moto, runner, ball, boat
- Аналитический поиск точки встречи: линейный + квадратный + численный (если задержка)
- Стробоскоп положений каждые 0.5-1 с
- Canvas-графики x(t) и v(t) с маркером встречи (красная точка + бейдж)
- Проверка ответа с tolerance ±5%, verdict зелёный/красный
- Слайдеры x₀/v₀/a для каждого мовера + кнопка 'Сброс к сценарию'
- Stats bar 5 ячеек: Время, t_встречи, x_встречи, Лидер, Расстояние между

UI (lab.html):
- Sticky quick-bar: Старт/Пауза/Сброс
- Карточка вопроса вверху + answer-bar внизу с input + verdict
- Collapsible-секции (race-acc): Параметры мовера 1, 2, 3, Настройки

Интеграция:
- lab-init.js: 'sim-race' в ALL_SIM_BODIES + роутинг _openRace
- admin/sims.js: запись в ADMIN_SIMS (cat: Физика, title: 'Гонка с задачами')
- lab-glue.js: P_RACE preset с SVG-превью (дорожка + кривые x(t))
- lab.css: ~200 строк стилей .race-* по паттерну elec/geo/dyn-acc
This commit is contained in:
Maxim Dolgolyov
2026-05-26 19:49:08 +03:00
parent 218baef4ad
commit af46290ca3
6 changed files with 1688 additions and 0 deletions
+1
View File
@@ -27,6 +27,7 @@
{ id: 'waves', cat: 'Физика', title: 'Волны и звук' },
{ id: 'heatengine', cat: 'Физика', title: 'Тепловые двигатели' },
{ id: 'radioactive', cat: 'Физика', title: 'Радиоактивный распад' },
{ id: 'race', cat: 'Физика', title: 'Гонка с задачами' },
{ id: 'logic', cat: 'Физика', title: 'Логические схемы' },
{ id: 'molphys', cat: 'Химия', title: 'Молекулярная физика' },
{ id: 'chemistry', cat: 'Химия', title: 'Химические реакции' },
+16
View File
@@ -652,6 +652,18 @@
<text x="131" y="16" font-size="9" fill="rgba(255,255,255,0.5)" font-family="Manrope,sans-serif">C</text>`);
/* Race sim preview — two objects on a track, x(t) lines */
const P_RACE = _svg(`${_grid('rgba(255,255,255,0.05)')}
<line x1="20" y1="75" x2="250" y2="75" stroke="rgba(255,255,255,0.18)" stroke-width="8" stroke-linecap="round"/>
<line x1="20" y1="75" x2="250" y2="75" stroke="rgba(30,32,50,0.9)" stroke-width="6" stroke-linecap="round"/>
<circle cx="75" cy="75" r="9" fill="rgba(6,214,224,0.2)" stroke="#06D6E0" stroke-width="2"/>
<circle cx="185" cy="75" r="9" fill="rgba(239,71,111,0.2)" stroke="#EF476F" stroke-width="2"/>
<line x1="30" y1="110" x2="130" y2="30" stroke="#06D6E0" stroke-width="2" opacity="0.85"/>
<line x1="30" y1="30" x2="200" y2="110" stroke="#EF476F" stroke-width="2" opacity="0.85"/>
<circle cx="107" cy="60" r="5" fill="#FF6B6B" stroke="#fff" stroke-width="1.5"/>
<text x="115" y="57" font-size="9" fill="#FF6B6B" font-family="Manrope,sans-serif" font-weight="700">встреча</text>
<text x="135" y="130" font-size="8" fill="rgba(255,255,255,0.35)" text-anchor="middle" font-family="Manrope,sans-serif">x = x₀ + v₀t + at²/2</text>`);
/* Logic Circuits preview */
const P_LOGIC = _svg(`${_grid('rgba(255,255,255,0.04)')}
<rect x="20" y="38" width="60" height="30" fill="rgba(155,93,229,0.12)" stroke="#9B5DE5" stroke-width="1.5" rx="4"/>
@@ -824,6 +836,10 @@
title: 'Радиоактивный распад',
desc: 'Период полураспада, цепочки распадов, активность. Визуализация ядер + кривая N(t). Радиоуглеродное датирование.',
preview: P_RADIOACTIVE },
{ id: 'race', cat: 'phys',
title: 'Гонка с задачами',
desc: 'Кинематика 1D: встреча, догон, кто первый. Реши задачу — проверь анимацией и графиком x(t).',
preview: P_RACE },
{ id: 'heatengine', cat: 'phys',
title: 'Тепловые двигатели',
desc: 'Циклы Карно, Отто, Дизеля, Брайтона. PV-диаграмма, поршень, КПД.',
+2
View File
@@ -38,6 +38,7 @@
'sim-quadratic','sim-normaldist','sim-graphtransform',
'sim-pendulum','sim-equilibrium','sim-opticsbench','sim-titration',
'sim-isoprocess','sim-probability','sim-bohratom','sim-electrolysis',
'sim-race',
'sim-waves','sim-hydro','sim-radioactive','sim-geometry','sim-heatengine','sim-logic',
'sim-qualanalysis','sim-periodic','sim-organic','sim-solutions'];
var ALL_CTRL_BARS = ['ctrl-graph','ctrl-proj','ctrl-coll','ctrl-tri','ctrl-trigcircle','ctrl-emfield',
@@ -98,6 +99,7 @@
if (id === 'probability') _openProbability();
if (id === 'bohratom') _openBohrAtom();
if (id === 'electrolysis') _openElectrolysis();
if (id === 'race') _openRace();
if (id === 'waves') _openWaves();
if (id === 'hydrostatics') _openHydro();
if (id.startsWith('hydrostatics:')) _openHydro(id.split(':')[1]);
File diff suppressed because it is too large Load Diff