| 2026-09-09 |
Трек 13: бой — перенос боевой системы v1 на воксельный движок
...
Движок: combat/ — shapes/los/stats/enemies/playerCombat/brain + world.ts
(CombatWorld: хуки вместо EventBus v1, мир — deps-предикаты solid/opaque,
снаряды, трупы, толкучка-сепарация с откатом в стены), StateMachine +
Cooldown, 16 юнит-тестов (217 всего). Боевой юнит = 3 вокселя демки,
конвертация только на границе.
Демка: сгустки-кучки на лугу (спящий — «блин», hurt-вспышка), атака на
Space (конус/резонанс), HUD сердец #hp (скрыт вне игровой сцены), шум
шагов, мост combatSpawn/combatClear/combatInfo/combatStats/attackInput.
Гейт combat.mjs 14 проверок; все 10 гейтов демки зелёные.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
v2 трек 12: сцены — SceneManager (стек, фейд out→in), меню поверх игры в демке
...
core/scene.ts — перенос схемы v1 без привязки к бэкенду: стек
push/pop/replace, переход фазами затухание → смена → проявление
(полный переход 2×duration), FadeOverlay {setAlpha} инъекцией;
параллельные переходы глотаются, enter новой сцены не ожидается,
render рисует весь стек. 10 юнит-тестов.
Демка: gameScene (tick+рендер) внизу стека, menuScene (DOM-панель,
мир под ней) сверху — старт в меню; Esc/мост gotoMenu — автосейв
в слот auto + меню, «Продолжить» грузит auto; мост sceneInfo/
gotoMenu/startGame. Гейт scenes.mjs — 11 проверок (фейд чёрный в
конце out, глотание параллельного перехода, продолжение с сейва).
Гейты демки входят в игру через startGame(false)+60 тиков (полный
переход). Уроки: CSS display:flex перебивает атрибут hidden
(#menu[hidden]{display:none}); полный переход = 48 тиков, не 24.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Сохранение: SaveManager + сериализация состояния демки (v2 трек 11)
...
save/saveManager.ts — перенос SaveManager v1 1:1: JSON-слоты, хранилище
StorageLike инъекцией (localStorage в демке, Map в тестах), мета слота
в параллельном ключе meta:<slot> (старые сейвы читаемы). Демка: DemoSave
version 1 (герой/флаги/переменные/сумка), applySave прерывает активный
диалог и обновляет HUD сразу; мост saveTo/loadFrom/saveList/saveDelete.
Гейт save.mjs — 9 проверок: восстановление состояния попиксельно
(кадр после загрузки = кадр сохранения, diff 0). 154 юнит-теста.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Инвентарь: контейнер предметов + эффекты диалогов (v2 трек 10)
...
inventory/inventory.ts — перенос Inventory v1 1:1: счётчики по id,
лимиты слотов/стака (возвращают факт, не бросают), onChange с деталями
изменения, serialize/load для сейвов. Демка: сумка героя (maxSlots 8),
DialogueWorld.hasItem связывает условия диалогов с сумкой (выбор
«Отдать цветок» виден только с цветком), onEffect исполняет
giveItem/takeItem (движок эмитит — исполнение игрой), HUD сумки
перерисовывается по событию контейнера. Гейт inventory.mjs — 8 проверок.
147 юнит-тестов.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Диалоги как данные + интерактивные точки (v2 трек 9)
...
Перенос диалоговой архитектуры v1 в ядро v2: граф — данные (узлы/
выборы/условия/эффекты, validateDialogue для агентной валидации),
рантайм DialogueRunner — семантика v1 (текстовый узел ждёт игрока,
узел-действие проваливается сам, do[] только эмитится), отрисовка —
игра (DialogueView). Точки взаимодействия — чистые данные + nearest.
Демка: страж у дома и табличка, клавиша E, HTML-оверлей диалога,
2 графа с эффектами setFlags/setVars и тостами; мост interact/
interactInfo/dialogueOpen/dialogueInfo/dialoguePick/dialogueAdvance.
Гейт dialogue.mjs — 15 проверок (подсказка, панель по зонам кадра,
выборы, эффекты, закрытие). 136 юнит-тестов.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

v2 трек 8: каркас ядра + герой (управление, камера следит)
...
- core/loop.ts: GameLoop — фиксированный шаг 60 Гц, аккумулятор с
maxStepsPerFrame, ручной режим setManual+stepTick (детерминизм гейтов),
now/schedule инъектируются для Node-тестов
- core/ecs.ts: EntityWorld — перенос проверенной минимальной ECS v1
(открытый вопрос «каркас ядра» решён)
- core/controls.ts: ввод как данные; screenMoveToWorld — экранные оси
в мировую горизонталь по yaw камеры (проекция на границе, урок №1)
- physics/character.ts: Character — тело физики + walk от скорости
(фаза = путь/stride, стопы не скользят; покой замирает); spawnY для
спавна в воздухе; мост тела физики переехал на Character (один путь)
- render: setTarget/currentTarget — камера (и солнце) следит за целью
- Демка: герой на WASD/стрелках + виртуальный стик агента; мост
setInput/heroInfo/heroTeleport/stepTicks/setManual/setFollow
- Гейт hero.mjs 9 проверок: ввод агента двигает героя, фаза 1.25
цикла/с, стена по грани, покой замирает, камера следует
115 юнит-тестов; гейты: render 13, turntable 5, anim 8, physics 7,
hero 9 — зелёные.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

v2 трек 7: физика тела — AABB против вокселей + гравитация
...
- physics/body.ts: SolidWorld (точечная выборка get), makeBody/stepBody
(полунеявный Эйлер), collides (AABB по воксельным диапазонам, касание
грани — не столкновение), ось-раздельное разрешение X→Z→Y с зажимом
к граням вокселей, сабстепы против туннелирования
- 10 юнит-тестов: падение на грань, покой, сход с уступа, стена,
туннелирование (50 вокс/с при dt=0.1), угол, потолок, число гравитации
- Демка: тело-манекен с walk-анимацией и поворотом по движению; мост
bodySpawn/bodyStep/bodyInfo/bodyRemove (фиксированный dt — детерминизм)
- Гейт physics.mjs 7 проверок: падение на землю, стена останавливает
по грани, фаза ходьбы растёт, кадр меняется, манекен рисуется
- Грабли в v2/CLAUDE.md: VoxelWorld(n) — высота чанка, не число чанков
(set вне границ молча false); Vec3 readonly — физика на обычных
кортежах; спавн тела проверять на пересечение AABB с миром
101 юнит-тест; гейты: render 13, turntable 5, anim 8, physics 7 — зелёные.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

v2 трек 6: рига/анимация — «анимация = данные» + walk-цикл манекена
...
- animation/mat.ts: аффинная математика без three (Affine, порядок
Эйлера X→Y→Z, rotateAround) — чистая, тестируется без рендера.
- animation/rig.ts: рига (кости: имя/родитель/pivot в связочном
пространстве), привязка вокселей — явная у генератора или bindNearest;
validateRig (родители раньше детей, согласованность привязки);
poseVoxels — жёсткая деформация по цепочкам костей.
- animation/clip.ts: клипы — ключи {t, кость: rot/pos}, линейный
семплинг с заворотом t, validateClip (монотонность, замкнутость
цикла «первый = последний»), footMinY (контакт стопы).
- animation/locomotion.ts: walkClip(params) — ноги в противофазе, руки
против одноимённой ноги, корень приседает дважды за цикл и качается.
- models/mannequin.ts: эталонный манекен 5×11×3 с ригой (5 костей,
явная привязка — Voronoi по pivot отнёс бы торс к рукам).
- render: addVoxelCloud — InstancedMesh для деформированных вокселей,
обновление позы без пересборки геометрии.
- Демка: anim.html/anim.ts — аним-лист 8 кадров цикла (4×2); мост
poseStats(i)/clipCheck()/setModels. Гейт anim.mjs: 8 проверок —
картинка (ячейки видны, фазы различаются) + числа через мост
(клип замкнут, противофазы, контакт стоп, качание корня).
- Попутно: turntable sheetInfo отдавал viewSize 30 при камере 32 —
исправлено на реальное значение (гейт проходил за счёт запаса).
- 91 юнит-тест; гейты: render 13/13, turntable 5/5, anim 8/8.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

v2 трек 5: .vox импорт/экспорт (MagicaVoxel) + перекладка палитры
...
- models/vox.ts: parseVox/exportVox — чанки MAIN/SIZE/XYZI/RGBA, PACK>1 —
ошибка, неизвестные чанки пропускаются с детьми; обрыв файла (в теле и
в заголовке чанка) — понятная ошибка, не RangeError. Оси: у .vox z —
вверх, у движка y — вверх: (x,y,z)_engine = (x,z,y)_vox. RGBA ровно
256 записей; при экспорте слоты модели сжимаются в подряд 1..N.
- models/paletteMap.ts: remapSlots — перекладка слотов модели на палитру
сцены (точный hex или ближайший RGB, при равенстве — меньший слот);
решает «слоты модели ≠ слоты сцены» после импорта .vox.
- Демка: мост stampVoxB64(b64,x,z) — парсинг → перекладка → штамп +
ремешинг dirty-чанков.
- Гейты: render 13 проверок (+ .vox-штамп меняет кадр, фиксстура — base64
от exportVox), turntable 5 проверок зелёные.
- Уроки в план/CLAUDE: Node не импортирует @rpg/engine — фиксстуры гейтов
вкладываются готовыми; точка правки для «кадр изменился» обязана быть
в кадре камеры; заголовок .vox-чанка — 12 байт.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
v2 трек 3: генераторы воксельных моделей (rng, формат JSON, деревья/валуны, штамповка)
...
- math/rng.ts — mulberry32: next/int/range/chance/pick, детерминизм по сиду
- models/format.ts — VoxelModel (size + плотный base64 + слоты-палитра),
encode/decode + числовая валидация (validateModel) для агентного пути
- models/generators.ts — treeModel (круглая/колонна/ель), boulderModel
(union сфер, свет на верхних гранях); (вид, сид) -> модель, чисто
- models/stamp.ts — stampModel в мир с клиппингом (half-open границы)
- демка: 12 деревьев + 3 валуна из генераторов; ручные tree/boulder удалены
- гейт рендера: 12 проверок (+ модельная статистика, детерминизм и
различие вариантов через мост stampTree)
- 50 юнит-тестов зелёные; доки plan.md/CLAUDE.md обновлены
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
v2: чанковый мир — Chunk/VoxelWorld с dirty-трекингом, meshRegion, демка 3×3 чанков
...
- world/chunk.ts (16×H×16) + world/world.ts: мир-словарь, get/set через
границы (в т.ч. отрицательные), правка боковой кромки помечает соседний
чанк dirty
- мешер обобщён: meshRegion(at, bounds, palette) — область по функции
доступа; world/worldMesher.ts мешает чанк через world.get — culled и AO
на швах бесшовны; тест: меш 4 чанков ≡ меш одной сеткой (позиции+AO)
- демка на мире 3×3 чанков с ремешингом dirty-чанков; мост __agent:
setVoxel (атомарен с ремешингом), chunkStats; гейт 8/8 — столбик на шве
чанков меняет кадр, dirty схлынулись
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Спайк v2: воксельный рендер — сетка/мешер/AO, three.js-бэкенд, демка и скриншот-гейт
...
- движок: voxel/grid.ts (Uint8-сетка, палитра по индексам), voxel/mesher.ts
(culled-грани + классический AO 0..3 с флипом диагонали, 12 тестов),
render/voxelRenderer.ts (ортокамера диметрии 2:1, dirLight + shadow map,
низкое разрешение 480×270)
- тулзы: tools/agent-lib.mjs — браузерный каркас проверок v2 (swiftshader),
tools/png.mjs — PNG-кодек (в т.ч. RGB-скриншоты headless Chromium)
- демка: apps/demo — воксельный пепельный луг в палитре арт-библии,
мост window.__agent (setSun/stats), чек checks/render.mjs: pageerror,
меш, тени ползут утро/вечер, апскейл кратен 2×2, многокрасочность
- грабли в v2/CLAUDE.md: камера под землёй при минус-Y (ловится только
скриншот-гейтом — урок №2 подтверждён в первый же день)
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Скелет v2: workspace, @rpg/engine 2.0.0-alpha (three.js), маниалы CLAUDE.md
...
v2/packages/engine — ядро-заглушка: зависимость three ^0.186, src/index.ts
с принципами v2 (рендер за интерфейсом, единое мировое пространство, сим/вью
разделение, мост — часть ядра), смоук-тест, tsconfig. v2/package.json —
workspaces + check:fast. v2/CLAUDE.md — краткий маниал: решения беседы,
уроки v1 к соблюдению, команды. Корневой CLAUDE.md — карта версий v1/v2
(корень остался без маниала после переезда). plan.md — задача 21 о
перепаковке. v2: npm install + тест + typecheck зелёные.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|