Files
Learn_System/plans/quantik-game/CONTEXT.md
T
Maxim Dolgolyov c780b6fd96 @
feat(quantik-game): фаза 5 — авторинг игровых уровней в sim-builder + раздача

Учитель собирает игровой уровень без кода: новая (аддитивная, сворачиваемая)
панель в sim-builder задаёт блок goal (when/title/hint/hold/fail) + до 3
звёзд + game-мету (chapter/order/par_ms); выражения проверяются inline через
SimExpr.compile (без eval). buildSpec/loadFromSim — round-trip без потерь
(goal/game пишутся только при включённом слое; обычная sim не меняется).
Кнопка «Играть» монтирует черновик в SimEngine-модалке (HUD цели из Ф0).
QuantikLevels стал async: подмешивает custom_sims cat=game (свои+
published) в реестр (custom:<dbid>), offline-safe, строки без goal
отбрасываются; deep-link /quantik?level=custom:<id> с серверной проверкой
доступа (own|published → иначе 403/404), мимо геймплейного гейта unlockStars.
Раздача классу — реюз share Ф6 (game-aware ссылка + durable pushNotif).
Правки sim-builder строго аддитивны (параллельная сессия). npm test 259/8
baseline; quantik-authoring 6/6; lint:routes 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
2026-06-14 16:09:10 +03:00

16 KiB
Raw Blame History

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 + множество untracked tmp_*/мусорных файлов. НЕ трогать и НЕ коммитить этот WIP — стейджить только свои файлы поимённо.
  • Phase 0 реализован (pending review): слой целей в движке _sim_engine.js (блок goal, компиляция when/fail/stars через SimExpr, состояние результата, HUD-оверлей, API onGoal/getResult/resetResult) + серверный гейт validateSpec пропускает goal/game. Изменены: frontend/js/labs/_sim_engine.js, backend/src/controllers/customSimController.js. Аддитивно: спека без goal ведёт себя ровно как раньше (HUD не создаётся, побед не считается). Смоук 40/40; npm test 238 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, портал-цель, бонус-звезда. На победу onGoalLS.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 (icon rocket) виден всем. Новые: 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 test 251 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); скин тинтует героя+нарратора (localStorage quantik-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 test 259/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 уровней: луч/синус/парабола/модуль/экспонента, unlockStars 9..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 test 261 / 253 pass / 8 baseline fail (без новых); lint:routes 0; все node --check OK.
  • Phase 4 реализован (pending review): фирменные квантовые способности + SR-связка, ВСЁ через безопасную модель (движок _sim_engine.js НЕ тронут). Новый frontend/js/game/quantik-abilities.js: window.QuantikEnergy (клиентский ресурс энергии, localStorage quantik-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 (L12L16) + CHAPTERS.quantum в levels.js; карта рисует автоматически (map.js не тронут). js/api.js +2 врапера (fcStudySession, fcReview). quantik.html +script-тег +CSS .qa-*. Backend НЕ тронут. Все node --check OK (вкл. инлайн 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 test 261 / 253 pass / 8 baseline fail (без новых); lint:routes 0.
  • Phase 5 реализован (pending review): авторинг игровых уровней в sim-builder + раздача классу. ⚠️ ПАРАЛЛЕЛЬНАЯ СЕССИЯ активна на ветке (правит sim-builder + admin «games»), поэтому все правки sim-builder.js/.html — строго АДДИТИВНЫЕ (новые методы/панель/CSS-блок, существующие строки почти не тронуты). sim-builder: панель «Игровой уровень (цель/звёзды)» (sectionGame + wiring + playGame + helpers loadGame/buildGoal/buildGameMeta) — тумблер «Это игровой уровень» включает слой goal (when/title/hint/hold/fail) + до 3 звёзд (when+label) + метаданные (chapter/order/par_ms); выражения проверяются inline через SimExpr.compile. blankState/loadFromSim/buildSpec/validate расширены аддитивно (по 1 врезке каждый). Кнопка «Играть» монтирует SimEngine в модалке (HUD/победа активируются сами наличием goal — Ф0). Round-trip goal/game без потерь. Игра: QuantikLevels стал асинхронным — ensureCustom() грузит custom_sims cat='game' (свои+ published) и мёржит как записи custom:<dbid>; getAsync(id) резолвит deep-link (own draft через LS.customSimGet). Новая глава custom в CHAPTERS. quantik.html: Promise.all([loadProgress, ensureCustom]) до карты + deep-link ?level=custom:<id> (без гейта unlockStars). Backend: share() для cat='game' шлёт game_level_shared со ссылкой /quantik?level=custom:<id> (иначе /lab?sim=…), ответ +link. CATS уже содержал 'game' (Ф0/Ф3); goal/game уже в validateSpec. Изменены: frontend/js/sim-builder.js, frontend/sim-builder.html, frontend/js/game/levels.js, frontend/quantik.html, backend/src/controllers/customSimController.js. Новый тест: tests/quantik-authoring.test.js (6/6). Headless round-trip-смоук (vm + реальные _sim_expr+sim-builder +levels) 7/7 — удалён. Все node --check OK (вкл. инлайн обоих HTML). npm test 267 / 259 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_sims cat='game' остаётся целевым хранилищем для авторённых уровней (Ф5); реестр тогда станет асинхронным (загрузка опубликованных + слияние со встроенными той же формы записи).
  • Герой Квантик: в уровне = 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).