Files
Learn_System/plans/quantik-game/phase-1-shell-first-level.md
T
Maxim Dolgolyov 4b5c8077d3 @
feat(quantik-game): фаза 0 — слой целей в движке (goal/HUD/result)

Декларативный блок goal в спеке SimForge (булево SimExpr-условие победы),
вычисляемый каждый кадр: фиксация результата (победа/время/попытки/звёзды),
callback onGoal, HUD-оверлей (цель/звёзды/подсказка/баннер, inline SVG).
API инстанса: onGoal/getResult/resetResult. Серверный validateSpec
пропускает goal/game (длина выражений + escape текста, без исполнения).
Аддитивно: спека без goal ведёт себя как раньше. Смоук 40/40; npm test
238 pass/8 baseline; lint:routes 0. План фичи (7 фаз) + CONTEXT.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@
2026-06-13 15:13:02 +03:00

64 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1: Оболочка игры + 1 физ-уровень + прогресс (MVP)
**Status:** ⬜ Not Started
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** fullstack
## Objective
Сквозной играбельный срез: страница `/quantik` грузит уровень-спеку, монтирует движок в
«игровом режиме» (управление = слайдеры закона + кнопка «Запуск»), на победу шлёт результат
на сервер, показывает экран успеха со звёздами/временем. Прогресс сохраняется в БД.
Первый уровень — «Артиллерия Квантика»: угол+скорость, попасть в портал, собрать звезду.
## Tasks
- [ ] Task 1: Миграция (следующий свободный номер) `game_progress`: `id, user_id, level_id TEXT,
best_time_ms INTEGER, best_stars INTEGER, attempts INTEGER, completed_at`. Индекс по (user_id, level_id) UNIQUE.
- [ ] Task 2: Контроллер `gameController.js` + роутер `game.js`, смонтировать в `server.js`
(после `/api/custom-sims`). Эндпоинты: `GET /api/game/progress` (свой прогресс по всем
уровням), `POST /api/game/progress` `{level_id, time_ms, stars}` (upsert: пишем лучший
результат — min time / max stars; attempts++). auth-only; валидация входа.
- [ ] Task 3: Клиент `LS.gameProgressList()` / `LS.gameProgressSubmit(levelId, {time_ms, stars})` в js/api.js.
- [ ] Task 4: Уровень как ДАННЫЕ: модуль `frontend/js/game/levels.js` (или сид в `custom_sims`).
Для MVP — встроенная спека уровня `phys-artillery-1` (physics + goal + 1 star + portal/star объекты).
Решение источника уровней зафиксировать в CONTEXT.md (встроенные данные сейчас; custom_sims в Ф5).
- [ ] Task 5: Страница `frontend/quantik.html` + `frontend/js/game/quantik-game.js`:
доступ всем авторизованным (LS.initPage()); подключает `_sim_expr.js`+`_sim_engine.js`
тем же путём, что lab.html/sim-builder.html. Монтирует уровень, ставит `onGoal` → submit + экран успеха.
- [ ] Task 6: «Игровой режим» движка/обёртки: цель видна (HUD из Ф0), управление = существующие
слайдеры params; кнопки «Запуск»(play)/«Сброс»(reset). Без редакторских панелей.
- [ ] Task 7: Экран успеха (DOM-оверлей страницы): звёзды, время, попытки, кнопки «Ещё раз»/«Дальше»
(для MVP «Дальше» неактивна/возврат). Inline SVG, без эмодзи.
- [ ] Task 8: Пункт в сайдбаре `js/sidebar.js` — `/quantik` в группе practice (по примеру `/sim-builder`),
видимость по роли (доступно ученикам — это игра). `isActive('/quantik')` подсветка.
- [ ] Task 9: Тест бэкенда `backend/tests/game.test.js` (паттерн lab-links.test.js: свой app.use
нового роутера, getToken/inject): submit пишет лучший результат, не ухудшает, attempts++,
требует auth, валидирует вход. Headless-смоук страницы по возможности (vm + стаб), иначе ручная проверка логики.
## Files to Modify/Create
- `backend/src/db/migrations/0NN_game_progress.sql` — таблица прогресса.
- `backend/src/controllers/gameController.js`, `backend/src/routes/game.js` — API.
- `backend/src/server.js` — монтаж роутера.
- `frontend/quantik.html`, `frontend/js/game/quantik-game.js`, `frontend/js/game/levels.js` — клиент+уровень.
- `frontend/js/api.js` — `LS.gameProgress*`.
- `frontend/js/sidebar.js` — пункт меню.
- `backend/tests/game.test.js` — тест.
## Acceptance Criteria
- `/quantik` грузится, монтирует уровень, цель видна; «Запуск» проигрывает физику.
- Попадание в портал (+звезда) → экран успеха с временем/звёздами; результат записан в `game_progress`.
- Повторный худший результат не перезаписывает лучший; attempts растёт.
- `npm run migrate` применяет миграцию; `npm test` зелёный (+ новый тест); `lint:routes` baseline 0.
## Notes
- Маршрутизация `/js/game/*`: помнить гочу sim-builder — `/js` мапится на корневой `js/`, а файлы
лежат во `frontend/js/game/` → отдаются через `express.static(frontendDir)`. Не трогать server.js static.
- Роуты `:id` прикрыть `authMiddleware` на уровне роутера (lint:routes baseline 0).
- Время — из `getResult().timeMs` (Ф0).
## Review Checklist
- [ ] Все задачи; конвенции (ownership/auth как studentMaterials/customSim); без эмодзи/eval
- [ ] Миграция применяется; API безопасен; тест зелёный; lint baseline 0; existing тесты не сломаны
## Handoff to Next Phase
<!-- Заполняет агент-имплементер. -->