0b1925fd3b
feat(quantik-game): фаза 4 — квантовые способности + SR-комнаты Глава-созвездие quantum (L12–L16) и фирменные механики — всё через безопасную модель спеки, движок и бэкенд НЕ тронуты (engine touch = 0): - Суперпозиция: два тела ball+ball2, goal.when требует ОБА (зеркальный закон). Туннелирование: forbidden-зона wall + fail wall.hit && tunnel<1; способность тратит энергию → setParam(tunnel,1). Коллапс/прицел: пунктир- plot предсказанной траектории на паузе. - Энергия — клиентский ресурс (localStorage quantik-energy, QuantikEnergy). - SR-комната: мини-сессия повторения флешкарт в модалке (НЕ iframe), LS.fcStudySession/fcReview; «Знаю/Легко» дают энергию; текст карт экранируется, картинки — по regex-вайтлисту. Все 5 уровней проверены на реальном движке (2★ достижимы; суперпозиция требует оба тела; туннель-гейт блокирует без заряда). npm test 253/8 baseline; lint:routes 0; цепочка разблокировки проходима. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> @
14 KiB
14 KiB
Feature Context: Квантик — Законы Мира
Current State
- Ветка
feature/quantik-gameответвлена отfeature/sim-builder(движок P1–P3 там, не в master). - При ответвлении унаследован чужой uncommitted WIP sim-builder:
frontend/js/sim-builder.js,frontend/sim-builder.html,.claude/settings.json+ множество untrackedtmp_*/мусорных файлов. ⛔ НЕ трогать и НЕ коммитить этот WIP — стейджить только свои файлы поимённо. - Phase 0 реализован (pending review): слой целей в движке
_sim_engine.js(блокgoal, компиляция when/fail/stars через SimExpr, состояние результата, HUD-оверлей, APIonGoal/getResult/resetResult) + серверный гейтvalidateSpecпропускаетgoal/game. Изменены:frontend/js/labs/_sim_engine.js,backend/src/controllers/customSimController.js. Аддитивно: спека безgoalведёт себя ровно как раньше (HUD не создаётся, побед не считается). Смоук 40/40;npm test238 pass / 8 baseline fail; lint:routes 0. - Phase 1 реализован (pending review): сквозной играбельный срез. Страница
/quantik(frontend/quantik.html+frontend/js/game/quantik-game.js) монтирует уровень-спеку черезSimEngine.mount; «игровой режим» = HUD из Ф0 (сам по наличиюgoal) + слайдеры params + play/reset. Уровеньphys-artillery-1— данные вfrontend/js/game/levels.js(window.QuantikLevels): physics-гравитация + body-запуск под углом θ/скоростью v, портал-цель, бонус-звезда. На победуonGoal→LS.gameProgressSubmit+ DOM-оверлей успеха (звёзды/время/попытки). Прогресс: таблицаgame_progress(мигр.076), API/api/game/progress(GET/POST,gameController.js+routes/game.js, смонтировано вserver.jsпосле/api/custom-sims), клиентLS.gameProgressList/Submit. Сайдбар:/quantik(iconrocket) виден всем. Новые:076_game_progress.sql,gameController.js,routes/game.js,quantik.html,js/game/levels.js,js/game/quantik-game.js,tests/game.test.js. Изменены:server.js,js/api.js,js/sidebar.js.npm test251 pass / 8 baseline fail (game.test.js 13/13); lint:routes 0; миграция применяется чисто. - Phase 2 реализован (pending review): одиночный уровень превращён в играбельный мир.
Карта-созвездие (
frontend/js/game/map.js,window.QuantikMap) на звёздном фоне: 6 физ-уровней в 2 главах (Кинематика 1–3, Динамика 4–6), узлы-«звёзды» со статусом (locked/available/completed+ звёзды), линии-связи, поэтапное появление. Шапка: нарратор-Квантик (PetSprite), XP-бар + «уровень Квантика», всего звёзд, скин-пикер (8 скинов, часть за XP/звёзды). Контент уровней расширен вlevels.js(метаданныеchapter/order/par_ms/unlockStars, по 2 звезды: кристалл + норматив времени). Разблокировка/XP/группировка — ЧИСТЫЕ функции в новомfrontend/js/game/progress-logic.js(window.QuantikProgress), покрыты тестом. Навигация: карта→интро(нарратор)→уровень→успех (нарратор по звёздам)→карта; «Дальше» активирована (nextPlayable); скин тинтует героя+нарратора (localStoragequantik-skin). Backend НЕ тронут — XP клиентская агрегация изgame_progress. Новые:js/game/map.js,js/game/progress-logic.js. Изменены:quantik.html,js/game/levels.js,js/game/quantik-game.js.node --checkвсе OK; смоуки (логика 16/16, рендер 7/7, winnability 6/6 на реальном движке) зелёные и удалены;npm test259/251 pass / 8 baseline fail (без изменений); lint:routes 0. - Phase 3 реализован (pending review): новый ТИП уровня — Квантик едет по кривой
y=f(x), которую СОБИРАЕТ игрок (слайдеры коэффициентов). Движок (_sim_engine.js, аддитивно): (1) «бегунок по кривой» — наplotполеrunner:{duration,hold}кладёт в env<id>.runX/.runY/.runDone; герой = обычный point наcurve.runX/runY(f компилируется 1 раз, питает И кривую, И бегунок — нет само-ссылки); (2)type:'zone'(rect/circle, kind forbidden/target/collect, track) → булево env-поле<zoneId>.hit(1/0); goal/fail/stars ссылаются на него. ⛔ Предикаты в грамматику SimExpr НЕ добавлялись. Новая глава-созвездиеfunctionsвlevels.js(5 уровней: луч/синус/парабола/модуль/экспонента,unlockStars9..17 ≤ 18 макс физ-звёзд → нет дедлока); map.js НЕ тронут (рисует по метаданным). СерверvalidateSpecпринимаетzone+runner(OBJECT_TYPES + поля). Изменены:_sim_engine.js,levels.js,customSimController.js,quantik.html(per-level бейдж темы). Новые тесты: custom-sims.test.js +2 (приём zone+runner, отказ unknown type) — 26/26. Headless vm-смоук (per-level solvability + logic 29/29) зелёный и удалён.npm test261 / 253 pass / 8 baseline fail (без новых); lint:routes 0; всеnode --checkOK. - Phase 4 реализован (pending review): фирменные квантовые способности + SR-связка, ВСЁ через
безопасную модель (движок
_sim_engine.jsНЕ тронут). Новыйfrontend/js/game/quantik-abilities.js:window.QuantikEnergy(клиентский ресурс энергии, localStoragequantik-energy, 0..99; grant/spend/canSpend/rewardForQuality; TUNNEL_COST=3, GOOD=1/EASY=2) +window.QuantikAbilities(mountBar— HUD энергии + кнопки «Повторение/Туннель/Прицел» оверлеем на сцене;openRestRoom— мини-сессия повторения флешкарт в модалке, реюзLS.fcListDecks/fcStudySession/fcReview, НЕ iframe). Туннель = тратит энергию →inst.setParam('tunnel',1); барьер =forbidden-зонаwall,fail:'wall.hit && tunnel<1'(tunnel — не слайдер, отсутствует в env → 0 → стена сплошная). Прицел = пауза-тоггл над пунктир-plot предсказанной траектории. Суперпозиция = чистый контент: 2 телаball+ball2,goal.whenс обоими. Главаquantum(L12–L16) +CHAPTERS.quantumвlevels.js; карта рисует автоматически (map.js не тронут).js/api.js+2 врапера (fcStudySession,fcReview).quantik.html+script-тег +CSS.qa-*. Backend НЕ тронут. Всеnode --checkOK (вкл. инлайн quantik.html); headless vm-смоук (РЕАЛЬНЫЕ движки): энергия + суперпозиция-оба-тела + tunnel-flips-fail + per-level solvability sweep (5/5 выигрываемы, full-star достижим, L15/L16 без tunnel = 0 win) + регресс 11 существующих уровней — 48/48, удалён. Контент-фикс: монета L16 (5,6)r0.7 → (5,6.9)r0.85 (была несовместима со 2-й звездой k≥6.8).npm test261 / 253 pass / 8 baseline fail (без новых); lint:routes 0.
Key Architecture Decisions
- «Атом» = блок
goalв спеке (булево SimExpr). Любой уровень = спека SimForge +goal. Движок вычисляетgoal.whenкаждый кадр; победа → result + callback. Нетgoal→ no-op. - Уровни хранятся в
custom_sims(cat='game'), а не в новой таблице. Реюз авторинга/шаринга/embed. Новые таблицы — только под ПРОГРЕСС игрока и лидерборд (мигр.).- Уточнение Ф1: для MVP уровни — ВСТРОЕННЫЕ ДАННЫЕ в
frontend/js/game/levels.js(window.QuantikLevels, форма{ id, title, subject?, hint?, spec }), а не записиcustom_sims.custom_simscat='game' остаётся целевым хранилищем для авторённых уровней (Ф5); реестр тогда станет асинхронным (загрузка опубликованных + слияние со встроенными той же формы записи).
- Уточнение Ф1: для MVP уровни — ВСТРОЕННЫЕ ДАННЫЕ в
- Герой Квантик: в уровне = engine point с
body+ glow + trail (визуал P2). На карте/в диалогах =PetSprite.render(level, mood, accessories, colorKey, streak, pattern)(DOM SVG). - Управление = чинить закон, а не WASD: игрок крутит
params-слайдеры движка (угол/скорость/ гравитация) или собираетf(x); затем «Запуск» — симуляция проигрывается к цели. - Безопасность: цвета — только в canvas-стоки; текст спеки — escape (
& < >); выражения — только длина на сервере, исполняет безопасный SimExpr на клиенте.
Engine touch-points (Phase 0)
- Спека v1 формат — в шапке
_sim_engine.js. Добавитьgoal/gameСЮДА (документировать). - rAF-цикл
_renderFrame(вычисляет env). Добавить_evalGoal()после построения env. mount()возвращает инстанс — добавитьonGoal,getResult,resetResult.- HUD — DOM-оверлей
_labelLayer/новый слой (как readout-бейджи). Без эмодзи, inline SVG. - Серверный гейт
customSimController.validateSpec(:93) — разрешитьgoal/stars/hint/game.
Cross-Phase Dependencies
- Phase 1+ зависят от
goal/getResult/onGoalиз Phase 0. - Phase 2 (XP/скины) зависит от прогресса Phase 1.
- Phase 4 (туннелирование) зависит от флешкарт-SR API.
- Phase 5 (авторинг) трогает sim-builder — к этому моменту чужой P4-WIP должен быть смержен в sim-builder; свериться перед стартом фазы (возможен мерж base-ветки).
- Phase 6 (живая гонка) зависит от моста
sim_state(Ф7 sim-builder) — он на base-ветке.
Temporary Workarounds
(пока нет)
Phase 0 — API/гочи (для следующих фаз)
- Движковое API цели:
inst.onGoal(cb)(1 раз при победе, cb получаетgetResult()),inst.getResult()→{won,failed,timeMs,attempts,stars:{got,total}}(без goal →null),inst.resetResult()(сброс результата, НЕ считается попыткой).inst.reset()= полный перезапуск уровня +attempts++(пользовательская попытка; первый авто-reset при mount НЕ считается). - HUD появляется автоматически при наличии
goalв спеке (отдельного флага «game mode» нет). timeMs= мировое времяtот старта (max(1, round(t*1000))), детерминизм; не wallclock.- Env цели = весь env кадра + единственный доп.идентификатор
tries(= attempts). Других не вводить. - Серверный
validateSpecпринимаетgoal{when,title,hint,hold,fail,stars≤3}иgame{...}(резерв Ф1/5); выражения не исполняются (только длина ≤500), текст escape+обрезка. - Победа делает
pause()в кадре; следующий queued-rAF выходит рано →onGoalне задвоится.
Open Questions / Notes
- Категория
cat='game'— проверить списокCATSв customSimController.js, расширить при необходимости. - Ассеты: разрешены CC0/открытые из интернета (выбор пользователя) — фиксировать источник+лицензию в коммите/доке; визуальная база остаётся in-house (PetSprite/canvas/FLUX).
- Маршрут страницы игры: clean URL
/quantik(паттерн/sim-builder,/lab).