| 2026-09-07 |

perf(render): culling тайлов карты, пустые оверлеи света, setDepth без пересортировки
...
О-2 рендера. На лугах ~900+ спрайтов карты рисовались целиком при ~250
видимых; пустые fullscreen-оверлеи света (ambient/vignette/пульс) рисовались
каждый кадр даже днём; ходьба взводила sortDirty каждый тик.
- IsometricTileMap.cullToRect: тайловое окно из экранных углов (screenToIso),
margin ±1 по X и вверх на высоту самого высокого tall; пересчёт только при
сдвиге окна; isTileVisible — для тестов/отладки; вызов из сцены
(updateCameraFollow). null — вернуть всё.
- Lighting: ambient.visible=false при белом тинте, vignette/pulseAmb — при
нулевой альфе (днём минус 2-3 fullscreen-квада).
- IsoDepthLayer.setDepth/setDepthRect: ранний выход при неизменном zIndex
(пиксельная сортировка детей не перезапускается каждый тик ходьбы).
- agent.mjs perf: возврат 0 (объект отчёта ломал process.exit).
Perf (swiftshader headless, до → после): fps бой 3-6 → 7-8, покой 5-6 → 5-7
(rasterizer swiftshader глушит выигрыш — он раскроется на целевом iGPU);
heap в пределах шума (28-31 МБ). Скриншот смоука не изменился, тайлы у краёв
камеры на месте.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
perf: реальный fps в агентном мосту + чек perf (baseline О-0)
...
- Engine.get fps() через FpsMeter (было 1/fixedStep = 60 всегда); AgentHost.fps.
- checks/perf.mjs: старт (страница+ассеты, newGame→location), A* (scene:route),
walkTo через луга, fps/heap в покое и в бою; agent.mjs perf (не в check —
бенчмарк, не гейт); lib.mjs open() с сырыми опциями openGame.
- eslint: performance: readonly для node-тулз.
Baseline (swiftshader headless, 960x540):
- старт: ассеты→меню ~3.0 с (raw 4.5 с с фиксированными 1.5 с сна моста),
newGame→location ~150-175 мс;
- A* путь через луга: 2-4 мс (10 узлов), walkTo: ~0.5 с;
- fps: 5-6 в покое, 3-6 в бою; heap: 28-31 МБ.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|

fix: утечки жизненного цикла (сцена, ввод, карта) + read-only тест карт
...
Игра:
- LocationScene: подписки EventBus снимаются в exit() (off из on);
DialogueSystem.destroy(); worldAudio.setLayers([]) в exit (лупы
амбиент-слоёв раньше звучали поверх следующей сцены); guard гонки
roomtone (сцена вышла до резолва промиса — луп гасится); в exit
добавлены moteLabel и chargeRing (в worldRoot — не вычищался).
- SaveSlotsScene: имена областей из areaOf() (интерьеры показывались
как «луга»).
Движок:
- InputManager: contextmenu-слушатель снимается в dispose().
- IsometricTileMap: плейсхолдер-графика ячейки хранится в CellSprites
и уничтожается при перерисовке (раньше накапливалась на setTile).
Тесты карт: fresh/round-trip read-only в npm test; запись файлов —
только при RUN_MAPS_GEN=1 (npm run maps) — обычный прогон больше не
мутирует рабочее дерево. agent:check: дублирующая проба maps удалена,
invariants — через сценарий checks/agent-invariants.mjs (был инлайн-
дубль, разошедшийся с ним).
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
20 hours ago
|
feat(game): непрерывное время суток вместо флага evening
...
GameClock (1 с = 1 игровая минута, старт 8:00) на Game; GameLighting
смешивает day/night ambient по кривой dayNightFactor через деп timeHours,
ночные источники — whenNight, лампа по фактору ≥ 0.5. Сейв v4 (clock),
миграция state v3 удаляет evening; мост: s.time, scene:setTime,
инвариант time-bounded, сценарий checks/time.mjs.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
21 hours ago
|
feat(game): контент освещения + сценарий проверки lighting
...
- locations.ts: ambient областей (луга/пруды/Звенец/интерьеры), окна трёх
домов Звенца, очаг дома Ирвина (hearth_low -> hearth_high по флагу квеста),
лампа прилавка лавки, холодный отсвет башни после звонка
- LocationScene: вызов lightView.update(dt) — время/лерп ambient/кадры
к спрайтам (сценарий поймал замороженное мерцание)
- tools/checks/lighting.mjs: 6 шагов (ambient областей, окна, тёмный интерьер,
мерцание с допуском, лампа следует за героем, очаг ярче после сдачи),
регистрация в agent.mjs
- доки: demo.md (матрица), plan.md (задача 10 + точки расширения day/night),
art-style.md (свет — оверлей, цвет из гаммы жизни, интенсивность ≤ 1.1)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
22 hours ago
|
feat(game): агентный мост — pickChoiceByText, path/mood/tags в снапшоте, сценарий quest-bells
...
- DialogueSystem.pickChoiceByText(text) — выбор варианта по тексту реплики
(реплики героя в графе — выборы по библии мира; elder_first теперь ветвится)
- DialogueSnapshot += mood/tags/path — снапшот показывает настроение и путь
прохождения графа
- мост: команда сцены scene:pickChoiceByText, GameAgent.pickChoiceByText
(ждёт waitingForChoice, берёт по тексту), прокси AgentClient (+timeout
у runDialogue)
- новый checks/quest-bells.mjs — полный цикл квеста «Три цветка»: взятие
у Ирвина выбором по тексту -> сдача (кат-сцена посадки, цветы списаны)
-> Мила (полотно из do[] в сумке) -> эпилог trader_after; входит в agent:check
- доки: agent.md (снапшот диалога, команды, API), practices.md (typewriter
и выбор в сценариях; метод моста = 3 места), в том же коммите
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
23 hours ago
|
| 2026-09-06 |
Движок: секвенсор renderMusic + playLoopBuffer; игра — тема лугов (работа G)
...
Партитура MusicSpec (bpm, beats, партии-стемы: pluck/bell/pad) чисто
компилируется в луп; playLoopBuffer играет буфер памяти на любой шине.
Тема лугов — правило-базовый генератор в data/music.ts (сид, ля-минорная
пентатоника), компиляция в рантайме — WAV для музыки не нужен; у области
поле theme, у Game — playTheme с guard-ом и кроссфейдом. Проба
checks/music.mjs в agent:check. Секвенция тем (бой) — до боевой темы.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Мост: scene:synthesize — звук по спеку из агентных проверок (работа E2)
...
Агент без слуха описывает звук параметрами (SoundSpec), движок
компилирует его в буфер (playSpec), факт запуска наблюдаем в
__gameAudioLog. Проба checks/synth.mjs в agent:check: удар/звон/
скрип/гул по спекам, громкость доезжает до голоса, повторный синтез
играет, негодные спеки возвращают null, гул не глушит амбиент.
Формы спеков — в docs/engine/agent.md.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Игра: DEV-лог аудио, агентная проба audio, практики «Добавляю звук»
...
- DEV-шпион window.__gameAudioLog (кольцо 24): sfx через onPlayed, амбиент через playAmbience
- checks/audio.mjs: амбиент запущен один раз, шаги без боя, bell_hit, guard амбиента, кольцо;
зарегистрирована в agent.mjs (8 проб)
- Доки: practices.md — ситуация «добавляю звук»; assets-audio-save.md — шпион и проба
Co-Authored-By: Claude Code <noreply@anthropic.com>
|

Тела не проходят друг сквозь друга + карта коллизий агенту
...
Расталкивание через реестр сцены: герой выталкивает себя из NPC
(PlayerController), враг — из героя, NPC и своих (EnemySystem); каждый
актор двигает только себя (separateCircles). attackStop (0.85) больше
суммы радиусов — авто-атака не дрожит.
A* не ведёт героя сквозь тело: SceneObjects.walkGrid() считает тайлы
NPC занятыми (герой застревал «на носу» у Ирвина — звон в верёвку
не поднимал флаг). Проводка: клик по миру, авто-подход к цели,
scene:route моста.
Карта коллизий агенту: слой s.collision {width, height, blocked (0/1
с footprint пропов), props} + команды scene:walkable {x, y} и
scene:raycast {from, to} (прямая видимость, вода прозрачна). Новый
сценарий checks/collision.mjs: слой валиден, walkable/raycast на
конкретных тайлах, клик в дерево — герой в проходимом, телепорт в
тело спящего ползуна — враг выталкивает себя.
Доки: agent.md (слой + 2 команды), practices.md (ситуация «проверяю
коллизии/движение» + грабли телепорта на тайл перехода).
Co-Authored-By: Claude Code <noreply@anthropic.com>
|

Разграничение: жанронезависимые тулзы переехали в packages/engine/tools
...
Правило: тулза, знающая контент игры (палитру, тайлы, локации, сценарии
акта), живёт в apps/game/tools как «сценарий применения»; машинерия без
знаний об игре переезжает к движку.
- packages/engine/tools/: png.mjs (encode+decode), canvas.mjs (палитра —
параметр), imaging.mjs (кроп/квантизация/обзорный лист), wav.mjs
(WAV-энкодер и примитивы синтеза), agent-lib.mjs (маяк — параметр
openGame), boundary.mjs (правила гварда, корни/публичное API — опции)
+ юнит-тесты boundary.
- exports движка: "./tools/*" — игровые сценарии импортируют
@rpg/engine/tools/* вместо относительных путей; maps/gen.test.ts
больше не лезет в src движка (encodeMap/parseMap из @rpg/engine).
- Игра остаётся сценарным слоем: palette.mjs, gen.mjs (арт/звуки),
aiart (промпты/манифест/тонкий post.mjs), checks/, smoke*, agent.mjs,
новый lib.mjs (маяк загрузки игры поверх движкового каркаса).
- Артефакты генераторов (арт, карты, WAV, processed) бит-в-бит прежние.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
2 days ago
|
Архитектура: гвард границы движок/игра + перенос тулз в apps/game/tools
...
- Гвард границы (apps/game/tools/guards/boundary.mjs, npm run guard):
движок не импортирует игру и не выходит из пакета, игра импортирует
движок только через @rpg/engine и @rpg/engine/assets/*. Чистое ядро
покрыто тестами (8 кейсов); проба guard:boundary в agent check.
- tools/ -> apps/game/tools/ (git mv, история сохранена): правка
корне-относительных путей в генераторах и CLI, ROOT-константы
'../../..', npm-скрипты обновлены.
- Доки: CLAUDE.md, llms.txt, docs/engine/*, README — новые пути,
практика «меняю границу движок/игра» и грабля про ROOT тулз.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
2 days ago
|