| 2026-09-07 |
UX-пачка: подсказки, клик-зоны, моты, коллизия домов, сундук, тихая вода
...
- Тосты держатся по длине текста (до 6 с) + подсказка сбора колокольчиков
при первом входе в пруды (флаг hint_bells).
- Клик по «телу» объекта: RouterDeps.pixelTile как фолбэк на голом клике —
bbox тел NPC/интерактивов (без подписей) + ремап на высокий тайл (дома).
- Моты: заметная насыпь с пульсирующей искрой, HUD-счётчик, вьюха
растворяется с искрами при поднятии (InteractSink.onConsumed).
- Движок: TallSpec.shadow — тайл (tx-1,ty-1) за домом блокируется
(shadowTilesOf в collision.ts + isWalkable карты, тесты).
- Интерьеры: бронзовый контур проёма + подпись «выход».
- Спрайт сундука (tiles/chest.png) вместо ящика-плейсхолдера.
- Вода прудов: radius 2.5, volume 0.22 — только вплотную и тихо.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
15 hours ago
|
Фикс десинка вью героя (SpriteMotion не двигает blink-view) + звук: ветер, шорохи, тише вода
...
- Движок: SpriteMotion перезаписывает позицию/поворот только при bob/sway —
view с чистым blink/pulse можно двигать извне (герой прибивало к точке
спавна, ходьба выглядела камерным скроллом, по прибытии спрайт
«возвращался»); detach симметричен; тесты SpriteMotion
- PlayerController: syncView на точном прибытии в waypoint (кадр не отстаёт)
- Звук: ambience/wind — глобальный слой (AmbienceLayerDef.radius опционален,
нет at/tiles — константная громкость) на лугах и прудах; вода прудов
тише (0.6→0.35, радиус 6→5); sfx/rustle — редкие дальние шорохи пепла
из тика сцены (rng сцены, случайные pan/rate). Птиц в мире нет по лору
- Доки: anim.md (правило позиционирования), practices.md (глобальные
слои, шорохи, «птицы молчат»)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
16 hours ago
|
Аудио: стерео-музыка, динамические темы (бой/настороженность), room tone интерьеров
...
- Движок: renderMusicStereo (interleaved L,R, equal-power pan треков,
нормализация по общему пику каналов), createBuffer(channels 1|2);
моно renderMusic бит-в-бит прежним сэмплам
- Игра: темы боя и tension-стем в data/music.ts; threat-тик
LocationScene.updateMusic — chase → тема боя, wary → тихий стем
(setVolume с флагом stemPending против шторма перезапусков)
- Room tone интерьеров: ROOM_TONES (hum-спеки, шина ambience),
запуск в enter, стоп в exit, validate-тест ключей
- checks/music.mjs: инвариант «тема лугов не перезапускается»
(динамические темы/стем — легитимная реакция на врага)
- Доки: assets-audio-save.md (стерео), practices.md (динамическая
музыка, pending-флаг), plan.md (Работа G — сделано)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
16 hours ago
|
| 2026-09-06 |
audio: палитра спеков (tone/wobble/sweep/layers) — все sfx на спек-синтезе (E4)
...
- SoundSpec: kind 'tone' (чистый тон + свип freqTo), параметры w/attack/
fadeTo/wobbleHz|Depth|Base|Phase, доп. голоса layers (SpecVoice с delay);
без модификаторов бит-в-бит прежним формулам
- data/sfxSpecs.ts: 16 спеков — все бывшие файловые sfx, включая шаги
(StepVariants: варианты renderSpec с сидами base+i·10, fallback — базовый
спек); ui_click во всех сценах через playSfx
- gen.mjs остался только амбиенту; assets/audio/sfx/ удалён; формулы
бывших sfx экспортированы для парити-теста (bit-в-бит / eps 1e-5)
- мост: scene:synthesize принимает kind tone; доки: agent.md,
assets-audio-save.md, practices.md, plan.md (E4 ✅)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
16 hours ago
|
audio: миграция bell_hit/whoosh на спек-синтез (E3), мёртвый door.wav удалён
...
- SoundSpec: флаг swell (огибающая «0 → 1 → 0» у hit/scrape), у chime 4-й
партиал и константная амплитуда клика — формулы совпали с gen.mjs дословно
- data/sfxSpecs.ts: реестр SPEC_SFX + playSfx — единая точка проигрывания
sfx (AudioSystem, useTransition, collectFlower); ключи в AUDIO_KEYS
- gen.mjs: CLI-гвард (WAV при импорте не пишутся), формулы bellHit/whoosh
экспортированы для парити-теста sfxSpecs.test.ts (бит-в-бит равенство)
- доки: plan.md (E1–E3 ✅, F/G ✅), practices.md, assets-audio-save.md
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
16 hours ago
|
Движок: секвенсор 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>
root
committed
16 hours ago
|
Движок: auto-mute по visibilitychange, bus в PlayOptions, exponential-фейд
...
Свернул таб — ctx.suspend, вернулся — resume (опция pauseOnHide, без
DOM listener не ставится). Разовый sfx можно направить в любую шину
(bus, по умолчанию sfx). Затухания лупов — экспоненциальные (линейный
спад слышен ступенькой); нарастание осталось линейным — экспонента не
определена от нуля. Доки и план (работа F ✅) в том же коммите.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
Движок: playSpec — спек-синтез звука по описанию (работа E1)
...
SoundSpec (kind hit/chime/scrape/hum + параметры) детерминированно
компилируется renderSpec в сэмплы; AudioManager.playSpec кэширует
буфер по ключу. Путь «звук по запросу» для ИИ-агента без слуха.
Типы synth.mjs — декларацией рядом (synth.d.mts): TS резолвит
specifier к реальному файлу и игнорирует ambient declare module.
План работ E/F/G (спек-синтез, хвосты аудио-инфраструктуры, музыка)
— в docs/plan.md; доки движка обновлены в том же коммите.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
Движок: лок кадров (maxFps) и FPS-счётчик по F3
...
GameLoop: опция maxFps — срезанные rAF-кадры не делают ни шагов, ни рендера,
но время копится в аккумулятор (шаги идут пачкой на отрисованном кадре).
Engine: опция maxFps, FpsMeter — дебаг-плашка FPS в углу (среднее за ~0.5 с),
скрыта по умолчанию, переключается по F3 (движок слушает сам, preventDefault
против поиска Firefox; в игре F3 уже занята дебаг-оверлеем сцены — toggl'ятся
вместе). Игра: maxFps 30. Доки core.md/getting-started.md обновлены.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
Движок: playBuffer/createBuffer (sfx из памяти); игра — вариативные шаги
...
D2 работы D. AudioManager: общий запуск голоса вынесен в startSfx,
playBuffer(key, buffer, opts) играет буфер из памяти в шину sfx,
createBuffer(Float32Array, rate=22050) строит AudioBuffer (null до unlock).
Чистые примитивы синтеза вынесены в @rpg/engine/tools/synth.mjs (без
node-импортов — wav.mjs тянет node:fs и в браузере не соберётся); wav.mjs
реэкспортирует их для тулз, WAV-файлы побайтно не изменились.
Игра: systems/StepVariants.ts — 3 процедурных варианта шага на поверхность
(сиды 253–256, полосы как в gen.mjs), AudioSystem.playStep(surface) вместо
ключа+джиттера rate, LocationScene отдаёт поверхность. До unlock — файловый
шаг. Гвард: @rpg/engine/tools/* — публичное API. Доки и план обновлены.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
Движок: onPlayed для лупов, onEnded, duration(key); игра без ручного лога амбиента
...
- onPlayed зовётся и на стартах лупов (нормализованные опции) — DEV-лог игры
собирается целиком шпионом, ручной push в Game.playAmbience удалён
- onEnded(key): естественный конец sfx; заглушенные голосом (stop/вор/restart)
событие не поднимают
- duration(key): длительность декодированного буфера (null до preload)
- Тесты: +5 в AudioManager.test.ts (440 всего); доки в том же коммите
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
Движок: SfxHandle из play(), опция restart, лимит полифонии maxVoices
...
- play() возвращает SfxHandle | null: setVolume/setPan/setRate в полёте + stop;
после stop и естественного конца хендл no-op (учёт голосов через onended)
- restart: true — прежние экземпляры ключа глушатся коротким фейдом
- maxVoices (3-й аргумент конструктора, дефолт 24): при переполнении
воруется самый тихий играющий голос
- Тесты: 6 новых в AudioManager.test.ts (436 всего); доки assets-audio-save.md,
practices.md — в том же коммите
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
17 hours ago
|
Игра: AudioSystem — позиционный звук мира, бой на событийной шине
...
- systems/AudioSystem.ts: playAt (затухание 1.5 степени + pan по экранному
смещению от слушателя), playStep (джиттер rate), attach (подписки combat:*),
setLayer (локальный амбиент, тик-фейд через новый MusicHandle.setVolume)
- CombatWorld освобождён от deps.audio: 5 play-вызовов -> события
(новое combat:spit {pos}, combat:awake дополнен pos) — симуляция снова чистая
- combat:playerHit -> sfx/hurt подпиской; sink интерактивов через playAt
- MusicHandle.setVolume в движке (cancel+setValueAtTime — без борьбы с ramp)
- 11 тестов AudioSystem; agent:check зелёный
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
18 hours ago
|
Движок: AudioManager v2 — шина ambience, playLoop, опции pan/rate
...
- 4-я шина ambience → master (лупы областей и локальные слои отдельно от музыки)
- PlayOptions {volume, rate, pan}: rate 0.5..2, |pan|<0.01 — без StereoPanner;
число в play() — сахар для {volume} (30+ старых вызовов не мигрируем)
- playLoop — луп без слота (база локальных амбиент-слоёв); playMusic/playAmbience —
независимые слоты с кроссфейдом, негодный ключ не глушит текущий трек
- ctxFactory инъекцией (фейк в тестах), шпионский хук onPlayed
- Settings.ambience (дефолт 1, старые настройки накрываются спредом)
- 10 тестов на фейковом AudioContext; доки assets-audio-save.md + README
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
18 hours ago
|
Батч 7: декор-слой (микро-кусты, камни, проплешины)
...
- engine: DecorData + TileMapData.decor; decorLayer между землёй и объектами;
addDecor (возвращает спрайт, один на тайл, повторный заменяет) / clearDecor;
setTile декор не трогает
- engine: MapFileV1.decor + validateDecor (границы, целые, dx/dy — числа)
- game: DECOR-реестр (tuft/stone/bald, id 15-17), buildDecor на createRng(seed+7919)
(~10% наземных тайлов, только GRASS/ASH, смещение не по сетке);
mulberry32 заменён на движковый createRng
- art: decor_tuft/stone/bald 16×16 (рисунок в ромб 16×8, палитра G/P)
- фикс fresh-теста: Math.round -> -0 теряется в JSON, нормализация +0
- тесты: порядок слоёв, addDecor/clearDecor, границы, round-trip + валидация decor
- доки: maps.md (раздел «Декор»), art-style.md, practices.md (ситуация
«меняю генераторы арта или карт», грабля -0)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
18 hours ago
|
Батч 6: варианты текстур тайлов (микс по хэшу координат)
...
- engine: hashTile(x,y,seed) — чистый хэш координат (math/rng.ts)
- engine: TileMapData.variants + setTileVariants + публичный variantOf;
анимация сильнее вариантов (setTileAnimation снимает их)
- engine: MapFileV1.variants (строковые ключи) + validateVariants в parseMap
- game: GRASS_V1/V2, ASH_V1, PATH_V1 (id 11-14), GROUND_VARIANTS в трёх
генераторах карт, новые текстуры в ASSET_KEYS и tileTextures()
- art: grass_2/grass_3/path_2/ash_2 (32×16, та же палитра, другой seed)
- тесты: hashTile (детерминизм/разброс), выбор варианта стабилен при setTile,
анимация vs варианты, round-trip + валидация variants
- доки: maps.md (раздел «Варианты текстур»), art-style.md, art-pipeline.md
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
19 hours ago
|

Движковые коллизии: круг поверх сетки + LOS по пропам
...
Новый чистый модуль map/collision.ts в движке: gridOf (Grid из
TileMapData с footprint пропов), точная проверка круга circleFits
(ближайшая точка квадрата Blocked-тайла — ловит угловой прокол по
диагонали), moveCircle со скольжением по осям, pushOutOfWalls для
телепортов, separateCircles для будущего расталкивания тел.
Дедупликация четырёх копий worldToTile+isWalkable: движение героя
(moveFree), шаги врагов, фауна и валидатор контента теперь на одних
функциях. IsometricTileMap.isPropBlocked публичен.
Бой против стен: конус удара требует прямой видимости (hasLineOfSight
по tall + пропам), снаряды гасятся о стены и дома (вода прозрачна —
плевок летит над прудом). Отброс героя — только если тело помещается
(circleFits): прищёлкивание к центру тайла после отброса меняло
динамику погонь у прудов и валило пробу interact-world.
14 юнит-тестов на коллизии (скольжение, угловой прокол, совместимость
с A*-маршрутом, push-out, separateCircles). Доки: maps.md (раздел
«Коллизии»), README.md, llms.txt.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
19 hours ago
|
SceneRegistry: реестр объектов сцены с индексом по тайлам
...
Жанронезависимый примитив «что-то стоит на карте»: позиция в юнитах,
радиус тела, footprint в тайлах, непрозрачная ссылка на контент игры.
Запросы at/atWorld/near/byKind без перебора сцены; дубликат id — throw.
Фундамент для унификации NPC/интерактивов/врагов и телесных коллизий.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
20 hours ago
|
Реестр размеров спрайтов: sizes.mjs + AssetLoader.frameSize
...
Единый источник номиналов для тулз (gen.mjs, lint-art.mjs), рантайм
читает размер кадра из атласного JSON. Захардкоженные 16×24/16×16
заменены ссылками на реестр; VIRTUAL-дубли 480/270 в сценах — на
Game.VIRTUAL_W/H; маркер NPC считается от реальной высоты кадра.
- tools/pixelart/sizes.mjs: SIZES (tile/tall/prop/char/fauna/clump/decor)
+ SLOTS для линтера; тест sizes.test.ts
- gen.mjs, lint-art.mjs: импорт из реестра вместо локальных констант
- AssetLoader.frameSize(key, frameName?) — sourceSize из атласного JSON
- IsoLayout как параметр игры — отложено (docs/plan.md)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
20 hours ago
|

Анимация 4/4: шоукейс в игре — все акторы на SpriteAnimator, статика оживает
...
Унификация акторов на движковые аниматоры (три ручных таймера кадров больше не дублируются):
- PlayerController: SpriteAnimator с клипами walk_*/idle_* — ушёл «застыл на произвольном кадре ходьбы»;
- CombatViews: SpriteAnimator (спящим pause), hit/death-бёрсты — oneShot через engine.fx
(закрыт баг «частицы стоят на месте»), новые опции drag/spin/scaleOverLife/colors;
- FaunaSystem: SpriteAnimator (на ходу walk, в покое стоп-кадр).
Оживление статики в LocationScene (всё тикается engine.fx, без ручного update):
- вода — setTileAnimation (2 кадра, один таймлайн на все клетки);
- мигание героя — SpriteMotion blink с живым duty (вместо ручного alpha);
- NPC idle — кадры npcs_sheet (randomPhase по тайлу), атлас добавлен в BootScene,
отдельные PNG NPC из списка ассетов убраны;
- искры pickup-объектов — SpriteMotion pulse;
- тёплые мотыльки — эмиттер blend:'add' + wobble + fadeIn;
- кадры героя/фауны — через assets.animation() (анимации атласов из батча 3).
Ограничение: sway для цветов/башни не вводился — это тайлы карты (спрайты
внутри IsometricTileMap), SpriteMotion на них неприменим.
Движок, попутные фиксы:
- Updatables: разрушенные записи не тикаются (Pixi обнуляет transform —
тик разрушенного SpriteMotion ронял весь тик и молча убивал игру после
перехода между локациями) + тесты;
- Engine.stepTicks: setManual(false)/resetTiming в finally — исключение в шаге
больше не оставляет цикл в ручном режиме навсегда;
- EmitterOptions.velocity опционален (в oneShot с radialSpeed не нужен);
- SpriteAnimator/SpriteMotion: геттер destroyed — самозачистка из engine.fx.
Доки: core.md (fx), anim.md (самозачистка), render.md (velocity), agent.md +
practices.md (грабля «мост глотает throw шага» и приём диагностики).
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
20 hours ago
|

feat(engine): батч 2 — оживители статики + партиклы v2 + тайл-анимации
...
- anim/motion.ts: чистая sampleMotion — bob/sway/pulse/blink, композиция,
округление bob до целого px; anim/SpriteMotion.ts — Pixi-адаптер
(база снимается в конструкторе, живые params, detach, seed→фаза)
- render/particleSim.ts (breaking): stepParticle → ParticleVisual
(alpha/scale/rotation/tint); drag, wobble, fadeIn/fadeOut-хвост,
scaleOverLife, colorOverLife; mergeEmitterOptions — чистое слияние
(burst больше не мутирует опции); fix: rng.int инклюзивен — выход
за границы colors
- render/Particles.ts: текстурные частицы, colors/colorOverLife, spin,
size-диапазон, max-лимит + пул спрайтов, blend 'add', setOptions,
onFinish у oneShot
- IsoDepthLayer.addFx(view, tx, ty, bias=0.5) — эффекты поверх актёра
- IsometricTileMap.setTileAnimation(id, frames, fps) + update(dt) —
один общий таймлайн на все клетки id (вода)
- engine.fx (батч 1) — рецепт авто-тика в доке вместо ручного update
- доки: render.md (частицы, addFx), anim.md (SpriteMotion, тайлы),
recipes.md (ходьба/атмосфера/статика/вода/удар), maps.md
- тесты: motion (9), particleSim переписан под v2 (итого 360)
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
21 hours ago
|
engine: ядро анимации — SpriteAnimator, клипы, реестр тика engine.fx
...
- anim/clip.ts: чистый степпер клипов (loop/once/pingpong, время в
шагах, speedScale, dt>периода проматывает).
- anim/SpriteAnimator.ts: именованные клипы, play/pause/showStep,
onFrame/onFinish, randomPhase (seed), текстура только при смене шага.
- anim/FrameAnimation.ts → @deprecated-обёртка, API байт-в-байт.
- core/Updatables.ts + Engine.fx: движок тикает эффекты сам (между
tween-ами и сценами), самозачистка по destroyed; clear() в stop().
- Тесты: clip (7), Updatables (5), FrameAnimation (4) — пробел покрытия
закрыт (было 0). Доки: новый docs/engine/anim.md, core.md, README.
Co-Authored-By: Claude Code <noreply@anthropic.com>
root
committed
21 hours ago
|

Крупные объекты: props с footprint в движке, слоты арта, проба дома кодом
...
Работа C из docs/plan.md — подготовка к зданиям акта 2.
Движок:
- TileMapData.props: крупный объект с footprint w×h от СЗ-угла — коллизия
по всему прямоугольнику, земля под ним (ground), спрайт якорем низ-центр
footprint'а; без текстуры — колонна-плейсхолдер (общий с tall хелпер).
- IsoDepthLayer.addRect: глубина по диагонали юго-восточного угла
footprint'а — герой у южной стены перекрывается домом, перед южным
углом рисуется поверх.
- mapFormat: props в файловом формате + валидация (целые w/h ≥ 1,
footprint внутри карты, высота в юнитах).
- LocationScene вставляет map.propViews в общий depth-слой.
- Доки движка: maps.md (секция props), render.md (addRect).
Арт (проба C2):
- Арт-библия: слоты крупных спрайтов (дом 2×2 — 64×80, 3×3 — 96×96,
4×4 — 128×112); плотность пикселя как у тайлов.
- gen.mjs: tiles/house_big.png (64×80) — композит: модули щитов + крыша
из шпал + козырёк + окна. Сравнение с AI-апскейлом 24→48 —
tools/aiart/probe-c2.png: код-композит заметно чище, апскейл — мыло с
чужой плотностью пикселя. Вывод: крупные объекты — код-композит;
апскейл только как болванка (см. docs/plan.md, работа C).
Тесты: 318 (+9: footprint, depth-rect, валидация пропов).
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Фабрика тестовых фикстур + fail-fast предикатов waitFor
...
- testing/ (только для *.test.ts, в бандл не попадает):
combatWorld.ts (fakeMap/fakeWorld/run/far), gameState.ts (fakeState),
maps.ts (mapWithWall). EnemyAI/los/Interactables тесты переведены —
бойлерплейт фейковых карт/стейтов выведен из трёх файлов.
- GameAgent.waitFor: top-level обращения s.<ключ> сверяются с
AGENT_SNAPSHOT_KEYS до компиляции предиката; неизвестный ключ ->
{ ok: false, error: 'неизвестный ключ s.X', ticks: 0 } — опечатка
больше не тихий false на весь таймаут. predKeys — чистая функция,
тестируется в snapshot.test.ts.
- Список ключей: ENGINE_SNAPSHOT_KEYS (движок) + сценические + слой игры;
анти-дрейф тесты держат список согласованным со слоями снапшота.
Проверки: typecheck, 307 тестов (+6), agent check 45/45 (ни один чек
валидация не отторгла), smoke-act1. Доки: agent.md (поведение waitFor),
practices.md (проверка сценариев).
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
| 2026-09-05 |

Батч 0: агентный набор инструментов (мост, валидация, CLI, доки)
...
Движок (packages/engine/src/agent/):
- types.ts: SceneAgent/AgentHost/Invariant/SnapshotLayer — каркас жанронезависим
- EngineAgent: снапшот+инварианты, step/waitFor, атомарные tapVirtual/press/key
- invariants.ts: checkFinite/checkRange/checkBounds/checkWalkable
- Engine.stepTick/stepTicks/tickCount; GameLoop.setManual/resetTiming
- InputManager.inject*: инъекция через те же структуры ввода
- DialogueRunner: nodeId/choices/waitingForChoice раскрыты для снапшота
Игра (apps/game):
- agent/GameAgent.ts: window.__agent (DEV): snapshot/step/waitFor/walkTo/runDialogue
- agent/snapshot.ts: чистые слои hero/enemies/npcs/dialogue/game
- data/validate.ts: runtime-валидация контента → Invariant[] (нашла 4 врага на воде)
- сцены реализуют SceneAgent: whitelist-команды, lastToast в снапшоте
Инструменты и доки:
- tools/agent-lib.mjs (openGame/AgentClient/Checks), tools/agent.mjs (CLI check/run/snapshot/screenshot/dev)
- tools/checks/agent-invariants.mjs; смоуки переписаны на мост; maps:fresh в gen.test.ts
- docs/llms.txt, docs/engine/agent.md, docs/engine/practices.md (живой документ)
- CLAUDE.md, docs/engine/README.md, docs/demo.md обновлены
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Батч 6: CutsceneRunner + кат-сцена сдачи квеста
...
- Движок: packages/engine/src/cutscene/CutsceneRunner.ts — view-агностичный
раннер шагов (call/cameraMove/burst/wait/setFlag); шаг с seconds: 0 —
параллельный; 5 тестов.
- Демо: кат-сцена сдачи «Трёх цветков» — посадка → камера к башне →
удар колокола (звон, shake, кольцо) → зелень → финальный тост.
- Смоук tools/smoke-act1.mjs: полный прогон акта 1 от «Новой игры»
до кат-сцены (сцелиться в тайл триггера, диалог через Space).
- Доки: docs/engine/cutscene.md, README (карта + структура),
docs/demo.md (матрица, дорожная карта — следующий срез: телепортация,
интерьеры, взаимодействие, ИИ врагов), CLAUDE.md (грабля клика вне экрана).
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
сейвы v2 + предметы + инвентарь
...
- движок: Inventory — контейнер Map<id, count> (add/remove/count/has/all,
onChange), inventoryFromData; тесты;
- Game.inventory: сумка героя, сброс в новой игре;
- SaveData v2: поле version + items, normalizeSave дополняет сейвы v1;
- data/items.ts: реестр предметов (cloth, bellflower, salt, water_flask);
- сбор цветка кладёт bellflower в сумку; полотно выдаётся предметом
после диалога Милы (флаг got_cloth остаётся меткой);
- InventoryScene: строки сумки из инвентаря (имя + ×N);
- тесты: 192/192.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
Фаза 4: TallSpec.height в мировых юнитах
...
- плейсхолдер-колонна: h = tall.height * iso.tileW (вместо px);
- удалён устаревший map.screenSize (остался worldBounds в юнитах);
- data/map.ts: высота дерева 1.5 юнита (те же 48 px на экране);
- .map-файлы перегенерированы (diff — только height: 48 -> 1.5);
- parseMap отвергает tall.height > 16 как высоту в px (защита от
протухших карт-файлов);
- тесты: 186/186.
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
камера: позиция и границы в мировых юнитах
...
- Camera.x/y и bounds в юнитах (1 юнит = 1 тайл); клэмп по экранному
bbox мирового прямоугольника; deadZone -> deadZonePx (окно на экране)
- IsometricTileMap.worldBounds; LocationScene использует его
- camera.test.ts переписан в юнитах (проверка проекций)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
движок: мост мировых юнитов (worldToScreen, unitsToPx, метрика проекции)
...
- math/iso.ts: проекция мир↔экран (float, без округления), линейка
скаляров (tileW px на юнит), метрика проекции (worldLen/worldNorm/
worldDist/moveTowardsW), тайлы (tileToWorld/worldToTile), bbox
прямоугольника (worldRectToScreen)
- shapes.ts: inCircleW/inConeW — метризованные варианты
- тесты: world.test.ts (18) + эквивалентность W-вариантов
Co-Authored-By: Claude Code <noreply@anthropic.com>
|