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> @
5.9 KiB
5.9 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.
Key Architecture Decisions
- «Атом» = блок
goalв спеке (булево SimExpr). Любой уровень = спека SimForge +goal. Движок вычисляетgoal.whenкаждый кадр; победа → result + callback. Нетgoal→ no-op. - Уровни хранятся в
custom_sims(cat='game'), а не в новой таблице. Реюз авторинга/шаринга/embed. Новые таблицы — только под ПРОГРЕСС игрока и лидерборд (мигр.). - Герой Квантик: в уровне = 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).