| 2026-09-11 |
Кубы поворачиваются вместе с моделью: rotY на инстансах
...
Character.yaw раньше вращал только позиции вокселей — кубы оставались
осями-выровненными и на диагональном ходе «пилили» силуэт углами.
Теперь PosedVoxel.rotY (опциональный поворот самого куба): visual()
ставит rotY = yaw на каждый воксель, рендер строит матрицу инстанса
makeRotationY(rotY) + setPosition — жёсткое вращение модели целиком.
Олень без изменений (четверти оборота держат сетку на осях). Проба
tools/probe-diag.mjs: герой на мировой диагонали, силуэт чистый.
6 гейтов игры + 11 демок зелёные, 301 тест.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
20 hours ago
|
| 2026-09-10 |
Текстурный слой моделей + манекен 10×16×4: деталь на текстурах, не геометрией
...
Формат: тайли пиксель-арта на грани вокселя (VoxelTile, тексель = слот
палитры — перекраска красит и текстуры) + tex (id тайля на воксель);
encodeModel(g, palette, texture?), texIdAt/texBytes/resolveTiles,
числовая валидация слоя. Рендер: addVoxelCloud(voxels, tiles) — атлас
(ячейка = 6 суб-граней тайля, 0 белая), aTileId + шейдерная инъция
(грань куба из нормали). Манекен: 14×24×8 (498 вокс) → 10×16×4 (164);
лицо — арт 8×8 текселей (бахрома/глаза/рот) на фасаде головы, волосы —
макушка и затылок. Игра: BODY_SIZE [5,16,5], stride 9.6, облака с
resolveTiles. Порог маха anim-гейта 1.0→0.8 (ноги вдвое короче).
6 гейтов игры + 11 демок зелёные, 300 тестов.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Дизайн персонажей v3: детализированный манекен 14×24×8 с лицом
...
Манекен движка 9×16×4 → 14×24×8 «путник» (~2.4 тайла, 498 вокс):
торс силуэтом (юбка плаща, пояс, грудь, плечи), рукава с кистями
кожи, сапоги с мысками, шея, голова с глазами, носом и волосами.
Палитра 8 слотов: MannequinPalette {skin?, hair?, torso?, legs?,
arms?, boots?, belt?, eyes?} — глаза отдельным тёмным слотом
(не от ремня). Череп ступенькой: фасад лица до y21, шапка волос
назад до z4 — иначе с игрового ракурса (~55° сверху) шапка прячет
глаза (луч к фасаду проходит через воксель уровнем выше).
Игра: палитры героя и NPC под новую модель (Ирвину тёплая кожа —
кожа в тон седине читалась как череп), BODY_SIZE [5,24,5],
stride 12.8 (каденция 1.64 цикла/с). Аним-лист под манекен 14
шириной (PITCH 18, подставки 14×14); combat-гейт — кучка для
визуального кадра спавнится в стороне от тела героя.
Все 6 гейтов игры + 11 демок зелёные, 297 тестов. Тулза
probe-hero.mjs — проба позиции героя через мост.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Дизайн персонажей и объектов, персонажи мельче (трек 24)
...
- Манекен движка 11×21×4 → 9×16×4; новое API mannequin(palette?):
MannequinPalette {torso/legs/head/arms} красит слоты, форма не зависит
- Палитры героя и NPC (NpcDef.colors); олень мельче (~10 вокс)
- Дом: двускатная крыша коньком вдоль X, деревянная дверь на видимом
фасаде, труба; дерево: крона с профилем (низ вздут, ель ярусами)
- Гейты anim.mjs под мелкий манекен (diff фаз 40, подъём стопы 0.7);
тулза crop-zoom.mjs — зум-кроп снимка для визуальной проверки
6 гейтов игры + 11 демок зелёные, 296 тестов.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|

Масштаб UNIT 5→10, детализация манекена 11×21×4, частицы из мира
...
Фидбек: «частицы летают вместе с персонажем, как приклеенные»;
«персонажи низкодетализированные, не читаются; объекты всё ещё
сильно меньше — масштаб поднимать кардинально».
- Частицы (пепел, мотыльки) отвязаны от камеры: мировой якорь +
дрейф, окно камеры заворачивает (wrap) — при движении героя
частицы стоят на месте в мире.
- 1 тайл v1 = 10×10 вокселей: генераторы областей и пропы подросли
(дерево ~30–38 со стволом 2×2, дом 24×30–40×18 — вдвое выше героя,
башня 47, Машина 24×34×18), высота мира 52, стены интерьера 13.
- Манекен движка 5×11×3 → 11×21×4 (голова-куб, торс, руки/ноги 2×2 —
силуэт читается; 220 вокселей; тест связности — BFS по
6-связности). Герой 2.1 юнита/с (stride 12.8 — темп v1), камера
viewSize 80 (охват 8 тайлов), радиусы интеракта 15, олень ~13 вокс.
- Гейты переведены на новую геометрию: все 6 игры + 11 демок
зелёные, 295 тестов.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Масштаб мира UNIT 3→5: герой ≈ 2 тайла, скорость 2.1 юнита/с
...
Фидбек «персонажи крупнее деревьев и соразмерны домам»: 1 тайл v1 =
5×5 вокселей. Генераторы областей и пропы подросли под тайл 5×5
(дерево 17–23 вокс ~2× героя, дом 12×14–18×9, башня 21, Машина
12×17×9, стены интерьера 8); олень ~9 вокс. Герой 2.1 юнита/с
(stride 6.4 — темп v1), олени 0.45/1.0 юнита/с. Камера viewSize 40 —
тот же охват 8 тайлов; тени/дистанция масштабируются от viewSize сами.
Гейты переведены на новую геометрию (центр тайла tile*5+2.5,
spotVoxel tile*5+2, подходы ±5); 6 гейтов игры + 295 тестов зелёные.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Трек 21 «сборка» закрыт: полный прогон и сравнительные скриншоты с v1
...
- Полный прогон: 11 гейтов демки + 6 гейтов игры зелёные, 295 тестов.
- Зеркальные тулзы v1/v2 compare-shot.mjs: 5 общих участков, герой в
одном тайле (карты v2 конвертированы 1:1), день 10:00, пары v1|v2.
- Итог сверки: раскладка/объекты/переходы совпадают 1:1; допустимые
расхождения — камера v2 крупнее (~2x), тёмные области светлее, вода
бледнее, интерьер беднее деталями.
- Доки: plan.md (итоги трека 21), v2/CLAUDE.md (полный прогон разом).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Трек 20: катсцены как данные — CutsceneRunner в движке
...
- Движок: core/cutscene.ts — жанронезависимый рантайм (стек шагов
{dur, fn?, cam?}, глайд камеры по инъекции CutsceneCamera, действие
шага может перезапустить сцену) + validateCutscenes; 8 юнит-тестов
- Игра: data/cutscenes.ts — метки точек камеры тайлами v1, именованные
действия, реестр 3 сцен; resolveCutscenes валидирует при старте;
main.ts — runner вместо inline-катсцен, мост playCutscene(id)
- Гейт cutscenes.mjs: dry-run каждой сцены до конца, камера к герою
- Все 6 гейтов игры зелёные, 295 тестов
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
1 day ago
|
Полировка игры: меню/автосейв, виньетка наката, мотыльки/дымка, шиммер воды
...
- Меню (Esc) + автосейв/«Продолжить» (движковый SaveManager): GameSave —
полный снапшот сюжета (область/тайл, флаги+вары, сумка, часы, правки
цветков до setArea); страница стартует в меню — гейтам startGame(false)
- Виньетка опасности + пелена наката (screenFx, DOM-слои)
- Атмосферные частицы v1 Atmosphere: мотыльки лугов, дымка прудов
(клочья на якорях клеток воды); шиммер — редкие блики на прудах
- Мост: ambientInfo, menuInfo, startGame(load); shot.mjs — startGame
- Грабли: castShadow после пересоздания облака, z-fighting копланарных
кубов над world-мешем (EPS 0.03), зомби-vite по PID, encodePng Buffer
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
| 2026-09-09 |
Фидбек: канвас под окно, плавная камера, поворот оленей, пропорции мира
...
- Канвас тянется под окно (CSS 16:9), бэкинг-стор 960×540 (pixelated).
- Камера следует за героем по float-цели без округления — дёрганье ушло;
глайд катсцен тоже без квантования.
- Олень поворачивается мордой по ходу движения (rotXZ, 4 четверти).
- Пропорции: деревья/дома/башня/Машина выше юнитов (герой 10 вокселей);
высота чанка мира 16 → 20 (дерево до 15 + GROUND_Y).
- Мост setFauna(false) для кадр-равенств (олени бродят в реальном
времени до setManual — флейк детерминизма areas); гейту areas нужен
stepTicks(1) после setFollow(false) — ручной режим не перерисовывает.
- Меню зафиксировано в треке 21 плана (замечание пользователя).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

Трек 19: акт 2 — катсцены резонатора и Машины, фауна, shot.mjs
...
Игра (apps/game): катсцена настройки резонатора (камера к резонатору →
звон → роща отвечает → тост) и усыпления Машины (камера к устью),
custom-эффекты диалогов через pending в onFinish; FaunaSystem v2 —
воксельные олени (src/deer.ts, src/fauna.ts): брожение по соседним
тайлам, подход на громкий звон, спавны в AreaDef.fauna v1 1:1
(луга ×2, пруды ×1). Мост: faunaInfo/startleFauna/setCam (камера на
участок без телепорта героя)/cutsceneInfo/tileCenter.
Тулза tools/shot.mjs — оперативный скриншот участка карты агентом:
область/флаги/вары/время суток + камера + снимок одной командой.
Гейт tools/checks/act2.mjs — 27 проверок (Клинт по флагу, тоны 3/3,
катсцены по шагам и глайду камеры, олени: спавны/брожение/подход к
звону); interact.mjs ждёт тост финала после катсцены, npc.mjs доигрывает
катсцену перед снимком. Регресс: 281 юнит-тест; гейты areas 16, npc 27,
interact 27, atmosphere 18, render 13 — зелёные.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

Трек 18: время суток, освещение и музыка — атмосфера v1 в игре v2
...
Движок: экспорт daynight (dayNightFactor/dayNightAmbient/flickerFactor),
новые API VoxelRenderer — setNight(k, tint) (hemisphere → тон ночи, фон
сцены, гашение солнца) и setDayAmbient(color) (дневная база области:
тёмные интерьеры гасят hemisphere и солнце по яркости), addPointLight.
Игра (apps/game): GameClock (1 сек = 1 игровая минута, старт 8:00),
данные освещения 8 областей v1 1:1 (bells, окна, очаги, отсвет башни;
whenFlag/notFlag/whenNight), GameLighting (diff источников, мерцание,
лампа героя HERO_LAMP), AshParticles (пепел лугов), GameAudio (темы
областей с кроссфейдом — только луга, как в v1). Мост: clockInfo/
setClock/lightingInfo/audioInfo/setAsh. Гейт tools/checks/atmosphere.mjs
— 18 проверок; areas.mjs научен отключать пепел для кадр-равенств.
Вне скоупа (отложено): туман прудов, ауры наката, виньетка, амбиент-слои.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Трек 17: интерактив, пикапы, квест «Три цветка» в игре v2
...
Контент v1 1:1: интерактивные объекты областей (столбы, моты, тон-деревья,
сундук, записка, очаг, прилавок, верёвка колокола, резонатор, Машина),
зоны наката (полотно — маска), воксельные пропы строго в тайл 3×3,
FlowerQuest (сбор у прудов → посадка поляны с пересевом; правки — журнал
по областям, переживает пересборку мира).
В main.ts: приоритет целей «E» v1 (npc → переход → интерактив → цветок),
накат замедляет вдвое без полотна + тост при входе, мини-катсцены (стек
шагов с глайдом камеры), plant_flowers отложен до конца диалога (v1
pendingCustom). Мост: interactInfo/voxAt/flowerTiles.
Гейт tools/checks/interact.mjs — 27 проверок (реакции и ветки объектов,
накат ×2 с полотном, сбор цветка, Машина: заперто → усыплена → спит,
катсцена сдачи с посадкой поляны). Регресс: npc 29, areas 16, 261 тест.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

Трек 16: NPC и квестовый каркас — диалоги/квесты v1 в игре на v2
...
Контент «Пепельных луга» 1:1 из v1: реестры FLAGS/VARS, 7 предметов,
NPC (Ирвин/Мила в Звенце, Клинт в роще по флагу act2_hook), 9 диалоговых
графов (JSON + validateDialogue при старте), квесты как стадии с
doneFlag/ready/progressKey, GameState (DialogueState движка).
Сцена: NPC-манекены с точками взаимодействия (E — Поговорить), выбор
графа — квест-стадия → repeat → dialogueFirst; в диалоге мир замер;
эффекты графов исполняет игра (сумка, тосты); HUD — трекер квеста,
сумка, тосты. Мост: npcInfo/talkTo/dialogueInfo/dialoguePick/
dialogueAdvance/dialogueAbort/setState/stateInfo.
Движок: экспортирован evalConditions (ready-условия стадий — те же
предикаты, что в графах диалогов).
Гейт tools/checks/npc.mjs — 27 проверок (раскладка NPC v1, появление
Клинта по флагу, выбор графа по стадиям включая сдачи, выбор ответа,
сумка, флаги, трекер, motes_note, мир замер, панель диалога).
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

Трек 15: карты и области — игра «Пепельные луга» на v2 (apps/game)
...
Новое приложение v2/apps/game (демка не тронута — её 11 гейтов завязаны
на сценку): воспроизведение демо-среза v1 по референсу.
- tools/convertMaps.mjs — конвертация карт v1 (RLE) → src/data/maps.json;
раскладка тайлов v1 переносится данными (позиции NPC/переходов сходятся)
- src/areas.ts — генератор мира области: 1 тайл v1 = 3×3 вокселя,
земля y0-1, вода слоем y=2 (непроходима, как v1 blocked), штампы
объектов — компактные генераторы строго в тайл 3×3 (mapTree/mapBush/
mapBoulder — крона не вылезает на соседей) + дома/колодец/башня/
машина/рельсы/стены/декор; всё детерминировано
- src/data/areas.ts — 8 областей с переходами v1 1:1: step (вход на
тайл-триггер), click («E» у двери/колодца), 'return' — стек возврата
- src/main.ts — мир области пересоздаётся на переходе, герой-манекен,
фейд out→swap→in (#fade), подсказка «E — …» (#hint), камера follow
- мост: setManual/stepTicks/heroInfo/heroTeleport/setInput/setFollow/
setSun/areaInfo/gotoArea/solidAt/interact/interactInfo
- гейт tools/checks/areas.mjs — 16 проверок: детерминизм пересборки,
blocked (3×3 под-колонки), зажим у грани воды, step-переходы
луга⇄Звенец/луга⇄пруды, люк→зал→return по стеку, click «E», интерьер
- доки: v2/CLAUDE.md (game-блок, грабли: экранная ось (1,0) — диагональ
мира и срез триггера; штампы шире тайла), plan.md (трек 15 закрыт)
check:fast: 261 тест, typecheck engine+demo+game.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|

Трек 14: аудио — перенос аудио-подсистемы v1 на воксельный движок
...
Движок (@rpg/engine): src/audio/ — types (4 шины master/music/sfx/ambience,
хендлы, опции), decode (BufferCache с in-flight дедупом декода), Voices
(полифония sfx: вор самого тихого, restart по ключу, панорама в полёте),
Loops (слоты музыки/амбиента с кроссфейдом), SoundSpec/Music (спек-синтез,
детерминированный), synth (примитивы v1 tools/synth.mjs в TS — в v2 нет
WAV-пайплайна, всё синтезируется в рантайме), AudioManager (фасад:
prepare() заводит контекст синхронно, unlock, playSpec с кэшем буфера,
шпион onPlayed). 44 юнит-теста (261 всего), тесты v1 перенесены 1:1.
Демка: src/audio.ts (спеки боя/урона/шагов — формулы v1 sfxSpecs;
DemoAudio — позиционный звук: затухание (1-d/r)^1.5 + изо-панорама,
дедуп 0.08 с; StepVariants — 3 варианта шага), обвязка в main.ts —
хуки боя (cone→bell_hit, resonance→bell_low, spit, awake→ash_hiss,
kill→ash_die, playerHit→hurt), шаг на границе половины walk-цикла,
unlock на первом жесте; мост audioUnlock/audioInfo (кольцевой буфер 24).
Гейт audio.mjs (8 проверок, DEV-шпион): тишина на старте, шаги играют,
атака→bell_hit, плевок→spit, резонанс→bell_low, лог ограничен 24.
Все 11 гейтов демки зелёные. Урок: кулдаун конуса не сбрасывается
телепортом — между боевыми секциями гейта ждать >= 30 тиков.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Eugene Sukhodolskiy
committed
2 days ago
|
Трек 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 трек 4: turntable-листы — визуальный гейт генераторов моделей
...
- apps/demo/turntable.html + src/turntable.ts: 6 моделей (деревья/валуны
x варианты) x 4 ракурса (0/45/90/135) на подставках 8x8x2; мост
sheetInfo() + setModels(on) для референсного кадра гейта
- tools/checks/turntable.mjs: центры ячеек той же проекцией, что камера;
эллипс 48x42 в ромбе подставки; 5 проверок (ячейки непустые,
варианты попарно различаются); скриншоты /tmp/v2_turntable*.png
- agent-lib: launchBrowser({viewport}) — страница листа 960x720 выше
дефолтного вьюпорта
- грабли: дробные координаты VoxelGrid.set — молчу no-op; скриншот =
вьюпорт браузера (канвас без центрирования); выборка эллипсом вместо
малых боксов у края ромба ячейки
- гейты: render 12/12, turntable 5/5; 50 юнит-тестов зелёные
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: демка на мире 6×6 чанков (96×96), замер производительности мешинга в мосте
...
- CHUNKS=6: мир 36 чанков, 80к вершин / 40к треугольников, постройка+мешинг
~0.4-0.5 с (гейт-лимит 2 с); контент разнесён по площадке, дом у центра
- мост __agent: chunkStats/perf; правка setVoxel атомарна с ремешингом
- гейт 9/9: мир из 36 чанков, перф-лимит, столбик на шве x=48 меняет кадр
- грабля теста: правка занятого вокселя не меняет геометрию — столбик
«исчезал» дважды (вне кадра, затем внутри дома)
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
|