# Russiano2D: инженерная спецификация производственной готовности

Версия документа: 1.1. Дата: 15 октября 2026 года.

## 1. Цель и границы

Развить Russiano2D до общего 2D game engine/SDK, на котором можно выпускать насыщенные action-platformer и roguelite игры: большие многоуровневые карты, управляемый персонаж, ближний бой и снаряды, противники с фазами поведения, динамическое освещение, выразительные эффекты, сюжетные последовательности, сохранения и полноценное управление с клавиатуры и геймпада.

Основная работа — довести взаимодействие существующих подсистем до надёжного контракта. Наличие метода или отдельной демонстрации не означает готовности целого игрового сценария. Новая возможность должна появляться как расширение существующего `$` API и открытого формата данных, с проверяемыми границами и примером использования.

### 1.1. Архитектурные обязательства

1. **Сохранить `$`-скриптинг.** `$` — единственная публичная точка входа игры в движок. Создание тегами, выборка селекторами, цепочки wrapper-методов, события и работа с данными остаются основой SDK. Новые возможности доступны через `$`; обход через публичный `engine.*` не допускается.
2. **Сохранить node/tag/wrapper.** Существующий узел — единица идентичности, жизненного цикла, иерархии, тегов, классов и событий. Дополнительные данные узла не превращаются в ECS, компоненты или второй реестр игровых объектов.
3. **Игра — код и данные.** Текстовые форматы и скрипты являются источником истины. Канонический визуальный редактор сцен не создаётся. Инструменты SDK редактируют отдельные данные и проверяют их настоящим runtime.
4. **Весь новый UI — RmlUi.** HUD, меню, настройки, инструменты и debug-панели используют `.rml`/`.rcss` и существующий `$.ui`. Специализированная графика допустима внутри RmlUi custom-elements.
5. **Нативное ядро и QuickJS сохраняют свои роли.** Массовая физика, запросы, сборка батчей и другие измеренно горячие проходы выполняются нативно. QuickJS обеспечивает `$` API, сценарии, правила и оркестрацию. Игровая логика не переносится в C ради самого переноса.
6. **Re2D Baker/import — только authoring.** При наличии такого конвейера в выбранной поставке его выход остаётся обычным 2D-ассетом. Он не становится основанием для универсальных 3D runtime, scene graph, материалов или физики. Возвращать удалённые инструменты ради выполнения этого документа не требуется.
7. **Совместимость — обязательство.** Текущие игры и форматы продолжают работать. Расширения форматов версионируются; изменение старого поведения имеет явный режим совместимости и тест.

### 1.2. Приоритеты

- **P0 — основа надёжного выпуска:** жизненный цикл, время, контроллер, столкновения, боевые контакты, восстановление, ввод, диагностика и поставка. Блокирует production-ready статус базового профиля.
- **P1 — сложный production-профиль:** управляемые свет и материалы, расширенные атласы, комнаты, процедурная проверка, музыкальные слои, специализированные инструменты. Обязателен, если соответствующая возможность заявлена поддерживаемой.
- **P2 — расширения:** дополнительные художественные режимы, сложные оптимизации и инструменты, полезность которых подтверждается проектами и измерениями. Не блокируют базовый выпуск.

Функциональный минимум выделен в §2.2 и §39–49; таблица §2.3 отделяет готовые API и игровую логику от пробелов. P0 не означает переписать все перечисленные модули. Сначала фиксируется текущий контракт, затем закрывается конкретный пробел.

## 2. Основание и достоверность инвентаризации

Точный репозиторий движка подтверждён через GitHub: [Nikide/russiano2d](https://github.com/Nikide/russiano2d). Опорный commit на момент проверки: `da2d27390d2dc0e1f38a3a83e8ed6a0c08976f06`.

Дополнительно изучено рабочее дерево пользователя от 15.10.2026. Оно содержит значительные незакоммиченные изменения. В частности, свежие controller helpers, изменения камеры, времени, tilemap и `hits.js` нельзя автоматически считать частью опубликованной версии. Ниже это обозначено как **локальное расширение**. Указанные пути относятся к этому рабочему дереву; ссылки GitHub на commit подтверждают только опубликованную основу.

В уточнённой редакции полностью разобраны 26 собственных игровых скриптов, включая общий state, управление сценами, все три варианта генерации, персонажа, противников, снаряды, ловушки, меню и сюжетные последовательности. Для трёх близких генераторов изучен общий текст и все различия. Проверены наборы используемых свойств 26 игровых сцен, их подключения событий и дорожки анимаций: 124 value tracks, 20 audio tracks и 8 method tracks. Код сторонних расширений не считается кодом игровых механик. Это статический инженерный аудит кода, описаний сцен, связей ресурсов, параметров ассетов и тестовых контрактов. В рамках подготовки документа движок и игры не запускались, новые тесты и замеры не выполнялись. Наличие тестового файла означает наличие проверки в репозитории, а не её успешный запуск в этом аудите. Качество изображения и звука здесь не объявляется проверенным.

Открытые вопросы обозначаются как требования к проверке, а не как доказанное отсутствие реализации. Особенно важно не наследовать устаревшие ограничения из документации, если код уже изменён.

### 2.1. Наблюдаемые производственные сценарии

Требования ориентированы на реальные сочетания систем:

- Вертикальное движение по платформам, прыжки, столкновения со стенами, ограничения камеры и многослойный параллакс.
- Атака с отдельным оружейным pivot, зеркалированием, временно активной областью поражения, частицами и звуком.
- Снаряд, который меняет направление после удара и затем поражает другую категорию целей.
- Противник, который патрулирует край платформы, просыпается при активации области и получает отбрасывание.
- Фазовый противник: подготовка, движение, столкновения с границами, восстановление, серия выстрелов и смерть.
- Временные ловушки, включаемые анимацией и триггером; переход между комнатами с блокировкой управления.
- Генерация сетки, выделение платформ по длине, поиск свободных областей и размещение объектов с проверкой пригодности карты.
- Сюжетные последовательности, совмещающие камеры, текст, музыку, изменение видимости, трансформы и завершение сцены.
- Смерть, повторная попытка, состояние текущего прохождения, постоянные настройки, HUD таймера и прогресса.
- Атласные спрайты, отдельные фоны, многослойные изображения, частицы, точечный свет, экранные эффекты и пространственные звуки.

Эти сочетания обосновывают требования к примитивам. Они не означают, что движок должен содержать конкретных персонажей, типы оружия, правила прохождения или алгоритм определённой игры.

### 2.2. Что действительно нужно реализовать в первую очередь

Этот список отделяет необходимое выразительное покрытие игровых сценариев от общей программы развития. **Для воспроизведения перечисленных механик не требуется сначала выполнить весь P1/P2.**

1. **P0: иерархические 2D-трансформы** для weapon pivot → sword → sensor, emitter и muzzle marker. Сейчас parent relation не равнозначна композиции position/rotation/scale. Подробный совместимый контракт — §39.
2. **P0: independent/compound sensors и безопасное включение форм.** Нужны отдельные movement/attack/contact/interaction shapes, независимые offsets/masks/enabled и отслеживание физического владельца. Подробности — §40.
3. **P0: многоцелевые animation tracks** существующего плеера: bool/enum properties, nested target, audio cues/volume, управляемые events и начальное/reset состояние. Подробности — §41.
4. **P0: тайловые collider descriptors** с неполным прямоугольником внутри клетки, разделением visual atlas address и collision shape, согласованием запросов. Подробности — §42.
5. **P0 для шумового профиля генерации: seeded simplex noise.** Имеющегося value noise недостаточно для эквивалентной пороговой геометрии. Остальные алгоритмы размещения остаются обычным `$`-скриптингом. Подробности — §43.
6. **P0: управляемая активация обработки и формы отдельно от visibility и sleep**, плюс событие входа в видимую область/activation region. Подробности — §44.
7. **P0: загрузка ресурсов с фактическим progress/failure/cancel** и чистая замена поддерева сцены. `loadAsync` и порционная JS-работа сами по себе не дают неблокирующее чтение/декодирование. Подробности — §45.
8. **P1, обязательный для соответствующего visual-профиля: экранный effect pass** с sampling предыдущего изображения, noise texture и параметрами времени. Имеющиеся sprite shader и built-in post presets не доказывают эквивалентность сложному screen distortion. Подробности — §46.
9. **P1 для точного particle-профиля:** emission timing/randomness/explosiveness, radial/tangential acceleration относительно эмиттера, hue variation и speed scale. Большинство остальных параметров частиц уже есть. Подробности — §47.

Остальное в §5–37 — укрепление интеграции и развитие SDK. Controller edge cases, scope/cleanup, корректность audio routing, marker semantics и input lock обязательны для надёжности; новый boss framework, диалоговый плагин, normal maps, music stems и расширенный save не являются предварительным условием реализации базовых игровых механик.

### 2.3. Матрица покрытия игровых операций существующим `$`

Статусы: **A — уже выражается**, **B — есть основа, нужен совместимый контракт/доработка**, **C — не найдено эквивалентного публичного примитива**, **D — игровая логика, не задача ядра**. Статусы статические; runtime-приёмка перечислена отдельно.

| Операция | Статус | Куда ложится в Russiano2D / конкретная работа |
|---|---|---|
| Создать объект по шаблону, добавить/удалить поддерево | A/B | `$.prefab`, wrappers, hierarchy; добавить scope-cleanup, не новый prefab runtime |
| Глобальные retry/run counters, флаги, статистика и debug mode | A/D | `$.store` и обычный JS; конкретные правила остаются в игре |
| Глобальные сигналы смены сцены/старта таймера | A | `$.signal`, `$.scene`, `$.time` |
| Перезапуск комнаты после смерти | B | `$.scene.restart` есть; cleanup, cancellation и reset policy — §5/14 |
| Preload и загрузка сцены с полосой progress | B | Resource registry и loading UI есть; фактический native async pipeline — §45 |
| Рекурсивный список файлов для диагностического вывода | A/D | Существующий `$.fs.list` + рекурсивный JS-обход; не новая игровая подсистема |
| Клавиши, mouse attack, axis, held jump | A | `$.input.bind/down/pressed/axis`; управление остаётся `$`-кодом |
| Кнопка атаки на touch UI | A/B | RmlUi button вызывает то же action/команду; input context исключает двойную доставку |
| Скорость, gravity, jump, проверка пола/стены | B | Box2D и wrapper helpers есть; controller semantics/footprint — §8 |
| Disable slide-on-ceiling и остановка персонажа | B | Явная controller policy; не предполагать совпадение поведения разных solvers |
| Патруль и проверка обрыва перед ногами | A/B | Raycast есть; local mirrored probe и self-filter — §39/40 |
| Преследование по direction/distance | A/D | Простая JS-математика + `.velocity`; отдельная AI-система не нужна |
| Переворот спрайта и отдельный оружейный pivot | A/C | Собственный flip есть; наследуемый signed transform и child world point — §39 |
| Вращающаяся ловушка с дочерней областью урона | C | Нужна та же композиция visual/sensor transform, не новый тип ловушки |
| Выстрел из дочернего marker после отражения pivot | C | Stable local/world marker API — §39 |
| Несколько независимых collision areas у одного объекта | B | Sensors есть; compound/attached shapes и enabled policy — §40 |
| Включить attack collider по ключу анимации | B/C | Events могут вызвать код; data-driven bool track + безопасная physics-команда — §41 |
| Contact damage, scalar HP, смерть | A/B | `.health/.damage`, filters/events; не обязательная зональная модель `$.combat` |
| Отбрасывание и delayed cleanup после смерти | A/B | Velocity/impulse, timers и локальный hit feedback; согласовать с controls |
| Отражение снаряда и разрешение урона только после отражения | A/D | Поля узла, masks/queries, velocity; правила отражения — обычный JS |
| Уязвимость только в выбранной фазе | A/D | FSM + условие damage; не отдельная boss subsystem |
| Подготовка, движение, стеновые развороты, burst shots | A/B/D | `$.state`, `$.flow`, animation events; scoped cancellation и timing |
| Обработка каждого N-го physics tick | B | `$.time.frame` не объявлять physics tick; simulation-step counter/event — §44 |
| Отключить frame/physics scripts до первого появления | B/C | Visibility не выключает logic; per-node processing policy — §44 |
| Синхронно менять sprite/weapon/particles/UI по одному клипу | C | Существующий player одноцелевой; multi-target binding — §41 |
| Анимация visibility/shape enabled/animation name | B/C | Не считать числовой `value` track готовым bool/enum setter; §41 |
| Audio clip в заданном времени и volume envelope | B | Event callbacks + sound есть; serialized audio track и handle — §41 |
| Повторный play того же активного клипа без сброса | A | Защита уже есть в `playClipOn` и animation player; сохранять |
| Reset/initial state клипа и цепочка по completion | A/B | Completion/events есть; явный reset/stop/interrupt policy — §41 |
| Tile read/write, world↔cell, tile existence | A/B | `$.tilemap`, `$.grid`; logical origin и negative boundary mapping — §42 |
| Несколько atlas sources в одной карте | B | Каноническая таблица tile descriptors; raw foreign scene format не нужен |
| Тонкий collider в нижней части tile | C | Tilemap collision builder строит полные solid rectangles; §42 |
| Noise threshold layout | C/D | Добавить simplex к `$.random`; пороги и построение карты — JS, §43 |
| Выделить платформы по длине, найти свободный квадрат | A/D | Arrays/grid уже достаточны; reusable helper желателен, не engine blocker |
| Weighted spawn на краю/в центре платформы | A/D | `$.random`, `$.grid`, prefab; правила размещения — JS |
| Проверка карты, ограниченный retry, loading steps | A/B/D | `$.task`/flow есть; failed report и retry policy интегрировать |
| Camera limits/zoom/deadzone и текущая камера | A/B | `$.camera` есть; snapshot/lease и completion integration |
| Параллакс, коэффициенты, бесшовная полоса | A | `$.layers` и существующий `$.layers.repeat`; не создавать заново |
| Самостоятельный scroll фона | A/D | Изменение layer offset через `$`/игровой шаг; frame-rate policy явная |
| Colored point lights и global darkness | A/B | Lightmap/ambient уже есть; проверить texture falloff и соответствие visuals |
| Частицы: shape, gravity, life, size, angle, angular velocity | A | `$.particles` уже покрывает; units и preset data |
| Частицы: local/global space, burst/one-shot, ramps, fields | A/B | Уже есть; world-space attachment и clocks проверить |
| Частицы: gradual explosiveness/radial/tangent/hue | C/B | Конкретное расширение параметров/симуляции — §47 |
| Экранное искажение с screen/noise sampling | B/C | Общие shader/post есть; проверяемый screen effect contract — §46 |
| Простые цветные mesh-заглушки и fade rectangles | A | Обычные 2D rect/ellipse/sprite; generic 3D mesh runtime не нужен |
| SFX, spatial attenuation, Master volume | A/B | `$.sound`/`$.audio` есть; routing и dB conversion policy проверить |
| Reverb и именованные audio buses | A/B | DSP/buses есть; изолированный bus-send — отдельный gap, §48 |
| Реплики, два портрета, typing, input advance/skip, звуки | A/B | Существующие `$.dialog/$.timeline`; только binding/lifecycle интеграция |
| Cue на выбранной реплике и продолжение после dialogue end | A/B | Timeline events + existing signals; не новый dialogue engine |
| Retry-dependent выбор реплик | A/D | Store + RNG + existing dialogue data |
| Progress bars, timer text, меню, volume slider, exit | A/B | RmlUi + `$`; завершение приложения через существующий `$.quit()` |

### 2.4. Что не следует выдавать за обязательный недостающий функционал

Normal maps, synchronized music stems, advanced checkpoints, сложный replay seek, дополнительные moving-platform abilities и универсальная navigation генератора — развитие общего движка. Они описаны по первоначальному охвату спецификации, но их отсутствие само по себе не блокирует перечисленные базовые сценарии. В изученных игровых скриптах нет основания требовать ECS, новый язык, самостоятельный boss framework, отдельную диалоговую систему, skeletal IK или generic 3D renderer.

Пустая функция, закомментированная механика и ошибка сравнения/счётчика в игровом коде не превращаются в задачу движка. Такие правила переписываются обычным `$`-кодом с выбранным корректным поведением.

## 3. Инвентаризация: что уже существует

Обозначения: **есть** — найдена реализация; **локально** — существенная часть находится среди текущих изменений; **расширить** — довести контракт, интеграцию или устойчивость. Ни один статус не означает автоматическую приёмку runtime.

| Область | Найденная основа | Решение спецификации |
|---|---|---|
| Иерархические 2D-трансформы | Дерево узлов и наследование visibility/alpha есть; обычный batch берёт собственные x/y/angle/scale узла | P0: явная local→world композиция для дочерних visuals, sensors и markers; старые координаты сохранить |
| Публичный scripting | `core.js`, `api.js`, `bootstrap.js`, `native.js`: `$`, узлы, wrappers, селекторы, скрытый native bridge | Сохранить и расширять; отдельный scripting API не нужен |
| Renderer | `render.c`, `highlevel/render.js`: общий 2D batch, blend modes, offscreen viewport, post-processing | Проверить порядок проходов, ресурсы и ограничения; новый renderer с нуля не нужен |
| Camera | `camera.js`: follow, bounds, deadzone, lookahead, zoom, shake, coordinate transforms, snapshot | Довести room/cutscene arbitration и поведение времени; часть исправлений локальная |
| Слои и параллакс | `layers.js`, `viewports.js`, `viewport.js` | Единый контракт координат и нескольких видов |
| Свет и тени | `render.js`, `render.c`: light nodes, occluder segments, lightmap, мягкость теней | Свет существует; оптимизировать и расширить маски/материалы |
| Normal maps | В изученном обычном 2D sprite-пути не подтверждён законченный публичный material/normal-map контракт | P1-расширение с совместимым fallback |
| Particles/VFX | `particles.js`, `fx.js`: trails/ribbons, поля сил, local/global particles; `tween.js`, `curve.js`, `pool.js`; локальный `hits.js` | Связать часы, владение, бюджет и события; не создавать второй VFX runtime |
| Physics | Box2D v3, `physics.c`, `world.js`, `collision.js`: тела, сенсоры, маски, контакты, rays, shape casts, CCD | Довести устойчивый controller/contact contract |
| Character foundations | `api.js`: velocity, jump, ground/wall helpers; локально coyote, jump buffer, air jumps, drop-through | Не заявлять отсутствующими; проверить крайние случаи и геометрическую корректность |
| Animation | `anim.js`, `animplayer.js`: клипы, tracks, events, state machine, seek, blending; `state.js` — общая FSM | Дополнить событиями игровых окон и едиными часами; новый animation graph с нуля не нужен |
| Atlases | `atlas.js`: JSON import, frame tags, slicing metadata | Довести trim/pivot, длительности, страницы, reload и диагностику |
| Tilemaps | `tilemap.js`: слои, autotile, terrain helpers, animation, Y-sort, merged collision, sampling | Доработать транзакционные изменения, геометрию тайлов и комнаты |
| Процедурные данные | `grid.js`, `random.js`, `nav.js`, `task.js`; `proc.js` — прежде всего процедурная графика | Расширять grid/nav/random/task; не путать `$.proc` с готовым генератором комнат |
| Areas/triggers | `triggers.js`, сенсоры Box2D, node events | Довести жизненный цикл пересечений и предсказуемую активацию |
| Combat | `.health/.hp/.damage` в node API, `combat.js`, `weapons.js`; локальный `hits.js` | Общие hit/hurt contracts поверх существующего здоровья; специализированные модели необязательны |
| FSM/сценарии | `state.js`, `flow.js`, `steps.js`, `time.js` | Примитивы boss patterns уже есть; нужны scope/cancel/debug и примеры |
| Signals/events | `signal.js`, `.on/.off`, ожидания, once, приоритеты | Расширить владение и трассировку, не писать второй event bus |
| Звук | `sound.js`, `audiobus.js`, `soundbank.js`, native audio/DSP | Довести общие маршруты и точность запуска музыкальных слоёв |
| Save/state | `save.js`, `store.js`, `prefab.js`, `state.js`: JSON slots, metadata, autosave, snapshots | Надёжный restore protocol и запись; новая save-система не нужна |
| Dialogue/timeline | `dialog.js`, `timeline.js`, `story.js`, `cutscene.js`, `i18n.js` | Существуют; только интеграция с игровым lifecycle, вводом и save |
| Input | `input.js`: actions, bind/rebind, сохранение bindings, gamepad slots, rumble, touch | Контексты, capture workflow, reconnect и фокус UI |
| UI/HUD | `ui.js`, `gui.cpp`, RmlUi, DevTools; legacy widgets сохраняются | Новый UI — RmlUi; проверить пути документов, focus и data binding |
| Localization | `i18n.js`: словари, параметры, plurals, fallback | Связать с RmlUi, authoring validation и шрифтами |
| Replay/testing | `replay.js`, `agent.js`, fixed-dt/seed, virtual input, query/inspect/profile | Расширить записи, checkpoints и divergence reports |
| Resources/reload | `resource.js`, runtime reload, asset cache | Транзакционная замена и согласованность зависимых ассетов |
| SDK | `sdk_tools.json`, RmlUi studios, native backend: sprite, animation, tilemap, particles, collisions, parallax, font, audio, input, RmlUi, automation | Расширять существующие инструменты; не создавать обязательный scene editor |
| Поставка | Действующие упаковка, SDK CLI, platform bundles и автоматические проверки | Требуется проверка установленного пакета, а не новый packager |

### 3.1. Конкретные ограничения, влияющие на проектирование

1. В изученном `api.js` `.moveAndSlide()` задаёт скорость тела; самостоятельного полноценного sweep/slide character solver это имя не доказывает. Ground/wall helpers используют лучи; это не равнозначно проверке полного footprint.
2. В `scene.js` смена сцены отложена, но сцена не является автоматическим владельцем созданных узлов. `exit()` обязан чистить их. `$.world.all()` включает UI; очищать им игровой забег опасно.
3. `animplayer.js` имеет собственное продвижение времени. Документация отмечает сырой `dt` и отдельную pause; единая семантика pause/hit-stop ещё требует проверки с локальными изменениями.
4. Дорожка позиции анимации пишет трансформ узла; автоматическое согласование с телом Box2D не следует считать готовым.
5. В атласах документированы ограничения rotated frames, нескольких страниц и reload; trim/pivot частично поддержаны через slices. Повторную реализацию slices не планировать.
6. `$.random` уже предоставляет seeded generators, выбор с весами и value noise. Сериализация внутреннего состояния генератора не подтверждена существующим контрактом.
7. `$.save` хранит prefab-данные и скорости по порядку обхода. Функции и подписки не сериализуются; `scene` — справочная метка, а не автоматическое переключение сцены.
8. В save-path запись проходит через обычный файловый API. Транзакционное восстановление мира и гарантии при обрыве записи требуют отдельной приёмки.
9. Световые тени обычного 2D-пути включают JS-расчёты по отрезкам. Наличие GPU lightmap composite не означает полностью нативную или GPU-симуляцию теней.
10. Звуковые шины, DSP и spatial helpers существуют. Музыкальный трек и звуки, запущенные разными API, имеют разные пути маршрутизации. Синхронный запуск нескольких stems не подтверждён.
11. `$.task` уже режет работу по бюджету времени. Такой бюджет не должен менять результат процедурной генерации при разной скорости машины.
12. Документированный tilemap limit при патологической геометрии допускает неполную коллизию после предупреждения. Production-профиль должен предотвращать публикацию такой карты либо безопасно отклонять её создание.

## 4. Общие инженерные контракты

### 4.1. Узлы, wrappers и API

Каждое расширение сначала проверяется на конфликт с существующим именем метода. Не вводить одноимённый метод с другой семантикой. Мутации wrapper возвращают wrapper, чтение имеет однозначный результат для пустой выборки, массивов и одного узла. Правило для нескольких найденных целей у команды должно быть описано.

Игровой код не получает внутренние Box2D handles, GPU pointers или нестабильные индексы массивов. Для событий и сохранений используются устойчивые логические идентификаторы. Native handles остаются техническими подробностями с проверкой поколения.

Краткие примеры существующего стиля:

```js
$('<player>', { id: 'hero' }).at(100, 200).appendTo($.world);
$('#hero').on('hit', onHit);
$.camera.follow('#hero', { deadzone: [40, 24], lookahead: 64 });
```

Все новые сигнатуры ниже — **проектные предложения**, а не обещание, что такие вызовы уже работают. Финальные имена согласуются с текущим API; предпочтительнее новые опции существующих методов.

### 4.2. Данные

Расширять имеющиеся JSON-форматы. Для нового типа данных обязательны версия схемы, стабильные идентификаторы, единицы измерения, defaults, валидатор и правила совместимости. Пути ресурсов разрешаются относительно файла-владельца, а не случайного working directory.

В документации и SDK должны совпадать значения по умолчанию, диапазоны и ошибки. JS и native validators либо используют общий источник схем, либо проходят одинаковый набор positive/negative fixtures.

Обязательные различия: ID ресурса, ID prefab, ID экземпляра и ID узла. Нельзя подменять их временным числовым handle.

### 4.3. Фазы кадра

Нужен документированный контракт фаз: фиксация ввода → команды логики/FSM → продвижение игровых анимаций и окон → физический шаг → контакты/боевое разрешение → отложенные изменения → синхронизация render state → камера/VFX/UI → сборка кадра. Конкретное размещение animation events фиксируется интеграционным тестом.

Порядок не следует менять вслепую ради этой схемы: сначала описать текущий, затем устранить случаи, где контакт получает окно прошлого кадра или удалённый узел продолжает получать callbacks. Изменение порядка является изменением поведения API.

## 5. P0-01. Владение и жизненный цикл сцен

**Основа:** `$.scene`, node hierarchy, `$.flow`, `$.signal`, `$.resource`, `$.time`.

**Задача:** добавить необязательную область владения сцены/комнаты/последовательности. Она связывает уже существующие узлы, подписки, таймеры, flows, задачи и удерживаемые ресурсы. Это lifecycle-объект, а не новая сущность scene graph.

Область имеет состояния active, closing, closed. При закрытии запрещает новые задачи, отменяет ожидания и удаляет принадлежащие ей узлы в безопасной фазе. Persistent UI и глобальные настройки имеют явного другого владельца. Реестр не очищается целиком.

Предложение API: опция `scope` в существующих create/subscribe/schedule-вызовах и scoped-контекст `$.scene`. Новая сцена сначала проходит prepare, затем commit; ошибка подготовки сохраняет предыдущую сцену пригодной к работе.

**Приёмка:** 100 последовательных restart/load не увеличивают число живых узлов, тел, подписок и таймеров относительно ожидаемого состояния; persistent HUD сохраняется. Переход из contact callback безопасен. Отменённая генерация и завершившийся старый loader не публикуют мир после нового перехода.

## 6. P0-02. Часы, pause, slow motion и hit-stop

**Основа:** `$.time`, physics timeScale, camera, particles, animation player, timeline, flows; локальные freeze/hit helpers.

Нужно согласовать домены времени без создания второй time-системы:

| Домен | Назначение | Пауза игры | Hit-stop |
|---|---|---|---|
| Simulation | gameplay, физика, боевые окна, игровые FSM | Стоит | Стоит |
| Presentation | выбранные эффекты и камера | По политике | Может продолжаться |
| UI | меню, focus, загрузка | Работает | Работает |
| Audio transport | sample clock и музыка | Явная политика | Явная политика |

Пользователь не обязан вручную разбирать raw/scaled `dt` в каждом обработчике. Новым задачам и плеерам задаётся опция clock, старые defaults сохраняются до явно объявленного изменения. Несколько источников freeze/slow используют независимые tokens и детерминированное правило композиции; снятие одного не снимает другой.

Лимит догоняющих physics steps и поведение после долгого suspend должны быть явными. Fixed-dt не использует wall-clock для исходов боя.

**Приёмка:** pause во время атаки замораживает движение, damage windows и gameplay timers; UI отвечает. Hit-stop не порождает повторный урон и не блокирует завершающий flash. Снятие cutscene-lock не снимает pause меню. Прогон при 30/60/144 render FPS даёт одинаковую последовательность simulation events при одинаковом fixed step.

## 7. P0-03. Physics и устойчивые контакты

**Основа:** Box2D v3, `$.world`, named collision layers, sensors, shape casts и CCD.

Требуется формальный контракт размеров в пикселях, перевода в физические единицы, центра/пивота и масштабирования. Полигональные и capsule shapes валидируются до создания тела. Некорректный контур не должен тихо превращаться в другое тело.

Контакты сообщают устойчивые self/other IDs, shape role, фазу begin/stay/end, normal и точку там, где backend действительно предоставляет их. Отсутствующие данные обозначаются явно. Для sensors не выдумывать контактную нормаль.

Изменение masks, отключение формы и уничтожение тела выполняются через безопасную очередь. Повторный end, устаревший handle и callback после destroy не допускаются. Shape queries имеют фильтр owner/self, collision mask и понятный порядок результатов. Overlap и sweep различаются по смыслу.

CCD обязателен для заявленного профиля быстрых физических снарядов; визуальное ручное перемещение без тела не получает гарантий CCD автоматически.

**Приёмка:** быстрый снаряд не проходит тонкую стену в заявленном диапазоне скоростей и fixed step; начальный overlap корректно диагностируется. Удаление цели внутри callback безопасно. Включение/выключение формы даёт документированную пару событий. Ошибка лимита тел не оставляет визуально проходимую карту без обязательной коллизии.

## 8. P0-04. Character controller foundations

**Основа:** существующие `.controls`, `.velocity`, `.jump`, `.moveAndSlide`, ground/wall helpers и локальные controller additions.

Не создавать готового героя с обязательными способностями. Нужен повторно используемый контракт управляемого тела: движение по земле, ускорение/торможение, скорость в воздухе, gravity policy, допустимый угол поверхности, устойчивое определение опоры, стен и потолка.

Grounded определяется контактами и/или shape sweep с учётом ширины тела, нормали, tolerance и направления движения. Центрального ray недостаточно для гарантии устойчивости на краю. Ground info включает опору и её скорость; moving platforms передают смещение без двойного интегрирования.

Coyote time, jump buffer, variable jump height, air-jump count и drop-through расширяют существующие controls. Все длительности имеют одни единицы. Отдельно описать приоритет knockback, input, external velocity и платформы; скрипт управления не должен стирать импульс урона в следующем тике.

One-way поверхность пропускает снизу, держит сверху и имеет ограниченный по времени/опоре drop-through. Глобальное отключение всей маски платформ для этого неприемлемо.

Dash, wall-jump, ladder и ledge-grab — P1-примеры на этих примитивах; обязательные способности персонажа в ядро не встраиваются.

**Приёмка:** набор сцен включает край платформы, ступень/стык, низкий потолок, наклон, подъёмную и горизонтальную платформы, one-way stack, касание угла и смерть во время drop-through. Повтор входа из replay совпадает. Тело не застревает и не проваливается в заявленных условиях. Наличие нового helper без этих проверок не закрывает пункт.

## 9. P0-05. Hitboxes, hurtboxes и общий damage contract

**Основа:** sensor shapes, node health/damage, `$.combat`, `$.weapons`, animation events и локальный `$.hits`.

Нужны роли collision shapes: movement collider, hitbox, hurtbox, interaction area. Это метаданные и формы существующего узла/поддерева, а не компоненты. Они могут иметь локальное смещение и трансформ относительно оружейного pivot.

Обязательные поля атаки: attack instance ID, source ID, owner ID, team/filter, активный интервал, policy повторного попадания и набор игровых данных. Hitbox и hurtbox не обязаны иметь собственное здоровье. Несколько hurtboxes одной цели сводятся к одному gameplay-hit, если правило атаки не требует иного.

Общий damage request содержит amount, damageType, source/target, attackId, направление/импульс и произвольные данные игры. Ответ содержит accepted/rejected, фактически применённое значение и результат death/stagger, если это известно. Причины отказа фактические: inactive window, immunity, team, duplicate, destroyed target.

Поддержать простой scalar HP через существующий node API. Специализированная зональная модель `$.combat` остаётся опциональной. Общий ближний бой не требует модели конечностей, брони или конкретной формулы damage.

Порядок: собрать кандидатов → фильтровать и дедуплицировать → применить gameplay → выпустить событие результата → presentation feedback. `$.hitFx` не является источником урона. Физическое отбрасывание нельзя заменять косметическим сдвигом сквозь стены.

**Приёмка:** активная атака наносит один удар цели с несколькими формами; новая атака поражает её снова. Invulnerability не отключает movement collider. При отражении projectile owner/team/attack identity меняются по описанной политике. Смерть случается ровно один раз; атака умершего владельца отменяется либо продолжает работу по явно заданному правилу.

## 10. P0-06. Animation graphs и gameplay windows

**Основа:** `$.anim.define`, `$.anim.clip`, `$.anim.player`, node state machine и общая `$.state` FSM.

Не проектировать параллельный graph runtime. Расширить текущий формат transitions: приоритет, условие/событие, допустимое окно перехода, restart policy, завершение once-клипа. Требуется определить, где живёт состояние поведения, а где — визуальный выбор клипа; обе машины не должны рекурсивно переключать друг друга.

Animation markers открывают/закрывают attack windows, спавнят VFX и проигрывают audio cues. Маркер имеет ID и policy при seek, loop, skip и restore. В обычном ходе он срабатывает ровно один раз при пересечении. Seek предпросмотра по умолчанию не наносит урон.

Для многодетального спрайта разрешаются именованные targets внутри существующего поддерева, socket/pivot metadata и дискретные frame tracks. Смена sprite frames, flip и trim не должна смещать оружейный pivot.

Трансформ visual-child отделяется от physics-root. Physics-affecting motion идёт через controller/physics command с явной политикой, а не через неявную запись позиции из animation track.

**Приёмка:** прерывание атаки закрывает окно поражения; смерть отменяет шаги, которые больше не должны исполняться. Клип с коротким active-window не теряет его при переходе через границу fixed step. Повтор loop и seek не дублируют события. Все случаи проверяются совместно с P0-02 и P0-05.

## 11. P0-07. Areas, triggers и активация

**Основа:** `$.triggers`, Box2D sensors и node events.

Единый контракт enter/stay/exit, фильтр по tag/class/collision category, once/cooldown и владелец подписки. Поведение при создании внутри области, отключении формы и уничтожении участника документируется.

Отделить видимость от симуляционной активности. Offscreen не означает автоматически остановить физику, таймеры или снаряды. Можно задать activation region и hysteresis; policy выбирается игрой. Противник, который впервые появился на экране, не обязан навсегда оставаться активным без явного правила.

Room transition, interaction и timed hazard используют эти примитивы. Триггер не содержит встроенного знания о типе уровня или персонажа.

**Приёмка:** пересекающиеся зоны не создают дребезг, once-trigger не срабатывает дважды при повторной подписке, destroy внутри enter безопасен. Телепорт между комнатами завершает старые overlaps. Во время pause поведение stay соответствует выбранным часам.

## 12. P0-08. FSM, patterns и отменяемые сценарии

**Основа:** `$.state`, `$.flow`, `$.time`, `$.signal`, `$.pool`.

Для сложных противников нужны общие state transitions, последовательности, параллельные шаги, повторы, timeouts, ожидание animation marker и отмена по scope. Не создавать универсальный «boss engine» с жёстко заданными фазами и способностями.

Pattern — именованная data-driven последовательность с параметрами; действия разрешаются через зарегистрированные игровые функции. В JSON нельзя исполнять произвольный текст как JS. Выбор следующего pattern использует выделенный RNG stream.

Существующая отмена flows сохраняется; дополнительно согласовать её с lifecycle сцены, animation player, emitters и waiting signals. После отмены не должны оставаться deferred shots.

**Приёмка:** последовательность preparation → movement → recovery → burst → phase change воспроизводится с seed. Death в каждой фазе отменяет последующие выстрелы. Debug показывает current state, elapsed time, ожидаемое событие и pending tasks. Ошибка action выдаёт структурированную диагностику и определённое terminal state.

## 13. P0-09. Signals, события и cleanup

**Основа:** существующие node events и `$.signal`, включая once, priority и wait.

Добавить общий lifecycle scope для подписок и ожиданий, сохраняя нынешний bus. Описать синхронную/отложенную доставку, reentrancy, изменение подписок во время dispatch и порядок одинаковых priority. Node events и глобальные signals не должны незаметно пересылать друг друга.

Событие production-сценария может иметь event ID, simulation tick, source/target IDs и data. Эти поля нужны трассировке; вводить тяжёлую оболочку для каждого простого вызова не требуется. Payload не хранит опасную ссылку на удалённый native объект.

**Приёмка:** повторный вход в сцену не умножает callbacks; once остаётся once при вложенном emit. Ожидание события закрытого scope завершается отменой. Журнал показывает фактическую цепочку attack → contact → damage → death → transition.

## 14. P0-10. Save, state persistence и checkpoints

**Основа:** `$.save`, `$.store`, `$.prefab`, текущие JSON slots и autosave.

Разделить данные профиля, прохождения, комнаты и presentation. Это namespace/schema policy существующего сохранения, а не четыре новых системы. Настройки input/audio и язык не сбрасываются при restart run.

Нужны стабильные instance/node IDs. Скорости, FSM state, оставшиеся таймеры, RNG state и логические статусы сопоставляются по ID, не только по позиции в обходе дерева. Сериализуются данные, а поведение восстанавливается зарегистрированными фабриками/скриптами.

Restore protocol: прочитать → проверить schema/content versions → обновить поддерживаемые версии данных → подготовить ресурсы и мир во временной области → восстановить связи и behavior → проверить инварианты → commit → освободить старую область. Ошибка до commit не уничтожает рабочее состояние.

Сохранение на диск: temporary file, проверка записи, atomic replace там, где платформа это обеспечивает, backup последней корректной версии и восстановление после сбоя. Не обещать crash-safety без проверки конкретного filesystem backend. Слот будущей неподдерживаемой версии отклоняется без перезаписи.

Checkpoint — снимок логического состояния и точки восстановления с policy сброса комнаты. Не обещать сериализацию внутренних contact caches Box2D. Для точного replay отдельно определить допустимое расхождение после восстановления физики.

**Приёмка:** загрузка во время прыжка, активного снаряда, cooldown и фазового противника восстанавливает ожидаемое поведение. Испорченный JSON, недостающий ассет, неизвестная версия и прерванная запись не уничтожают последний корректный слот. Восстановленные подписки и таймеры устанавливаются один раз. Death/retry не увеличивает статистику дважды.

## 15. P0-11. Input, rebinding и gamepad

**Основа:** `$.input`, action bindings, rebind, persistence, pad slots, rumble и touch.

Расширить существующий action API контекстами gameplay/menu/dialogue/loading и приоритетами потребления ввода. Один confirm не должен одновременно закрывать реплику и выполнять атаку. UI focus, keyboard capture и gameplay lock согласуются через tokens/scopes.

Rebinding workflow: ожидание следующего подходящего ввода, cancel, timeout, conflict report, reset defaults, сохранение. Различать physical key и текстовый ввод. Аналоговые оси имеют deadzone, threshold и hysteresis, чтобы capture не ловил шум стика.

Gamepad reconnect восстанавливает назначение игрока по явной политике. Отключение при удержании кнопки сбрасывает её состояние. UI показывает актуальные glyphs и доступность rumble. Нельзя молча менять игрокам устройства из-за перестановки слотов.

**Приёмка:** меню полностью проходится геймпадом; горячее подключение, отключение во время jump и смена устройства не оставляют stuck action. Rebind сохраняется между запусками и не срабатывает через активное поле ввода RmlUi. Virtual input/replay используют тот же action resolution. Touch-контролы, если заявлены, не подменяются мышью и поддерживают одновременные действия.

## 16. P0-12. UI/HUD, localization и существующий timeline

**Основа:** RmlUi, `$.ui`, `$.i18n`, `$.dialog`, `$.timeline`, `$.cutscene`.

Новые экраны используют RmlUi. Требуются проверяемые data bindings здоровья, cooldown, таймера, прогресса загрузки и выбранного устройства. Пути `.rml`, `.rcss`, шрифтов и изображений одинаково работают при прямом запуске проекта, из SDK и из пакета.

UI lifecycle связан со scope. Persistent HUD отделён от временных окон. Focus stack возвращает фокус после закрытия диалога/паузы. Масштабирование поддерживает логический viewport, HiDPI и выбранную политику aspect ratio; безопасные поля проверяются на узком/широком окне.

Локализация уже существует. Дополнить извлечение и validation ключей, перевод RmlUi-текста, обновление открытых документов при смене языка, fallback fonts, переполнение и параметры plural. Наличие Unicode-строки не доказывает корректную форму всех письменностей; поддерживаемые языки должны иметь явную матрицу приёмки.

**Не создавать новую диалоговую систему или отдельный диалоговый плагин.** Существующий timeline дополняется только интеграционными возможностями: scope, ownership управления/камеры, pause policy, восстановление логической позиции и cleanup после stop/scene exit. Skip должен привести к определённому итоговому состоянию без повторного выполнения необратимых gameplay effects.

**Приёмка:** HUD переживает restart комнаты; каждый обязательный RmlUi ID доступен через существующий API. Смена языка обновляет меню и активный dialogue view. Escape/back закрывает верхний контекст и возвращает фокус. Нормальное завершение, skip и принудительный stop timeline возвращают управление, камеру и audio state по явному контракту.

## 17. P0-13. Ошибки и диагностика

**Основа:** текущие логи, agent protocol, SDK validators, DevTools.

Критические операции возвращают структурированный результат: code, subsystem, operation, assetPath/nodeId, message и recoverability. Имена полей — проектный контракт; формат согласуется с существующими ответами. Ошибка включает файл, строку/JSON path там, где они известны.

Не продолжать обязательную загрузку после критической ошибки так, будто подготовка завершилась успешно. В частности, общий loader должен отличать optional asset failure от невозможности создать обязательную коллизию/сцену. Log-only ошибка не заменяет failed result.

QuickJS exception получает stack trace и source path; promise rejection и callback error не исчезают в stderr без machine-readable записи. Ошибка удалённого узла сообщает stale ID. Повторные одинаковые сообщения ограничиваются по частоте, но счётчик потерь виден.

**Приёмка:** отсутствующий atlas, неверный collision polygon, исключение в frame callback, failed save и неподдерживаемый shader backend диагностируются воспроизводимо. Loader не выдаёт success при неполном обязательном мире. DevTools и автоматический тест получают одинаковый code.

## 18. P1-01. 2D renderer, слои и presentation contract

**Основа:** существующий SDL_GPU renderer, sprites/triangles batch, blend, offscreen и post FX.

Довести стабильный порядок layer/Z/Y-sort/creation order. Прозрачные элементы нельзя произвольно пересортировать ради batching. Разделить world, world-lighting, overlay и UI проходы, описать влияние post-processing на каждый. Локальные render targets должны иметь явную семантику current/previous frame, resize и запрета feedback loop.

Pixel-art профиль: nearest filtering, масштабирование, pixel snapping только presentation, согласованность камеры и параллакса. Снаппинг не должен квантизовать физическую позицию. При дробном zoom должно быть понятно, какой артефакт является ожидаемым и как выбрать integer-scale режим.

Material keys входят в batch key; постоянная смена материала не должна порождать неограниченные pipeline variants. Установить порядок освобождения texture/target и deferred GPU resources.

**Приёмка:** эталонные сцены с alpha/add/multiply, Y-sort, UI, parallax и offscreen сохраняют правильный порядок при перемещении камеры и resize. Смена сцены не показывает освобождённую текстуру. Frame capture и счётчики batch breaks объясняют число draw calls. Профиль RE2D=OFF сохраняет полный обычный 2D-путь.

## 19. P1-02. Camera и комнаты

**Основа:** существующие follow/deadzone/lookahead/bounds/snapshot/restore и multiple views.

Не добавлять ещё одну камеру ради платформера. Нужны reusable camera zones с bounds, follow policy, zoom и transition. Несколько запросов камеры имеют явные priority и owner; временная последовательность получает lease, затем возвращает прежнюю конфигурацию.

Smoothing задаётся независимо от render FPS; исключить lerp с постоянным коэффициентом на кадр как единственный контракт. Lookahead фильтруется и не дёргается при краткой смене направления. Shake накладывается на базовый transform, имеет seed/clock и ограничение доступности по настройкам пользователя.

Bounds вычисляются с viewport, zoom и rotation. Room меньше viewport требует явной политики центрирования/letterbox. Несколько views используют правильные transform для input picking и culling.

**Приёмка:** переход между вертикальными и горизонтальными комнатами не показывает пустой край вопреки выбранной policy. Cutscene-stop и death восстанавливают follow. Pause/hit-stop не меняют базовую позицию неожиданно. World↔screen roundtrip и mouse picking проходят при zoom, rotation и resize.

## 20. P1-03. Lighting, shadows и normal maps

**Основа:** уже работающие light nodes, occluder segments и lightmap composite. Создавать освещение заново не нужно.

### 20.1. Доведение существующего света

Разделить light receiver mask, occluder mask и render layer. UI не попадает под world lighting. Динамический occluder имеет invalidation только затронутой области; изменение тайла не пересобирает весь мир без необходимости.

Лимиты lights, shadow rays/segments и разрешение lightmap входят в quality profile. При превышении выбирается документированная деградация: убрать тень/уменьшить качество, а не случайно отключить значимый свет. Профилирование показывает число активных и culled lights, occluders, CPU shadow work и GPU composite.

Перенос JS shadow calculations в native рассматривается после измерения; публичный `$` API не меняется. CPU/reference вариант может оставаться для проверки.

### 20.2. Материалы спрайтов

Ввести минимальное расширение sprite material: albedo, optional normal, optional emissive, tint, lighting enabled и параметры ответа на свет. Отсутствие normal map даёт нейтральную нормаль; обычный спрайт сохраняет прежний путь.

Normal map — данные, а не sRGB color. Зафиксировать tangent-space convention, направление зелёного канала, преобразование при flip/rotation, соответствие atlas trim/pivot и extrusion. У normal/albedo pages одинаковая раскладка или явное отображение UV. Высота света — художественный параметр 2D-освещения, не 3D transform узла.

Предложение данных: material metadata в существующем asset manifest с полями `albedo`, `normal`, `emissive`, `normalConvention`, `lit`. Не вводить generic PBR graph.

**Приёмка:** тестовый выпуклый спрайт корректно освещается слева/справа, после flip и поворота; flat normal совпадает с ожидаемым базовым материалом. Trimmed atlas не смещает свет. Тень следует за moving occluder. Shader backend без расширенного режима использует объявленный fallback. Качество проверяется изображениями, производительность — отдельным измерением.

## 21. P1-04. Particles и VFX

**Основа:** `$.particles`, ramps/curves, blend, pool, screen FX, tweens и локальный `$.hits`.

Завершить reusable effect presets: burst/loop, локальная или мировая система координат, attachment к node/socket, clock, seed, scope и completion event. После удаления родителя эффект либо завершается самостоятельно, либо отменяется по policy.

Trails/ribbons уже существуют: `$.fx.trail` и `$.fx.ribbon`. Использовать их для melee, довести привязку к world-space socket, часы, cleanup и ограниченный буфер; новый ribbon renderer не нужен. Не требовать Box2D body на каждую частицу. Collision particles — P2 optional mode с отдельным бюджетом.

Ввести global/per-emitter caps и стабильное правило overflow. Presentation RNG не потребляет gameplay stream. Параметры эффектов редактируются существующей Particle Studio, включая кривые, без второго renderer.

**Приёмка:** сотни последовательных ударов не создают неограниченное число узлов/эмиттеров. Pause/hit-stop соответствуют выбранным часам. Перезапуск эффекта не сохраняет мусор предыдущего. При ограничении бюджета бой и результаты генерации не меняются. Настройки reduced flash/shake уменьшают presentation, сохраняя gameplay events.

## 22. P1-05. Sprite atlases и import pipeline

**Основа:** `$.atlas`, существующий Sprite/Animation Studio и native asset tools.

Сначала закрыть корректность: source size, trim rect, pivot, frame duration, tags/directions, sockets и collision metadata. Длительности кадров должны доходить до playback, а не теряться при превращении тега в массив sprite IDs. Логический pivot остаётся неподвижным при разных trimmed frames.

Rotated frames: либо поддержать на import с канонизацией, либо жёстко отклонять весь обязательный asset с точной диагностикой; молчаливо пропускать часть кадров production-клипа нельзя. Multipage — P1 для больших наборов, с явным page ID и ограничениями GPU.

Import manifest хранит content hash, importer version, settings и зависимости. Повторная обработка одних исходников даёт одинаковые metadata и раскладку при фиксированной версии. Кэш можно удалить без потери авторских данных. Packing, padding и extrusion одинаковы для albedo/normal/emissive.

SDK допускает ручную нарезку и редактирование открытого JSON. Preview использует runtime playback. Реимпорт не теряет именованные пивоты и ручные данные: автоматические и авторские поля разделены.

**Приёмка:** unequal frame durations, reverse/pingpong tags, trimmed sprites, sockets, page switch и отсутствие текстуры проверены fixtures. Кадры не дрожат при idle/run/attack. Paths с пробелами и разным регистром выявляют переносимые ошибки до упаковки.

## 23. P1-06. Tilemaps, комнаты и prefab data

**Основа:** `$.tilemap`, `$.prefab`, `$.scene`, grid и named layers.

Tilemap остаётся node data. Для тайла отделить visual ID, collision descriptor, terrain tags и gameplay metadata. Поддержать нужные reusable формы: solid, one-way, hazard/area и polygon/slope через существующую физику. Не связывать «картинка непрозрачная» с «тайл непроходим».

Изменение карты — пакет: изменить cells → пересчитать затронутые visual/collision/occlusion chunks → опубликовать согласованное состояние. Между фазами не существует невидимой старой стены или новой видимой платформы без коллизии. Превышение лимита имеет failed result.

Room description — открытые данные поверх prefab/scene: bounds, node instances, tilemap references, spawn markers, exits и connections. Не дублировать дерево prefab. Именованные children и override paths имеют stable IDs; повторное создание комнаты не порождает новые случайные ID.

Для больших уровней P1 — chunk activation и ресурсное владение; P2 — фоновый streaming. Не обещать полный streaming только из-за наличия loadAsync.

**Приёмка:** room load/unload не ломает HUD и глобальные настройки. Дверь/тайл меняет картинку, коллизию и occlusion согласованно. Сохранение сохраняет room ID и её изменения. Collision-merge не меняет геометрию и query semantics. Пример с несколькими комнатами работает без канонического scene editor.

## 24. P1-07. Procedural generation и проверка пригодности

**Основа:** `$.grid`, `$.random`, `$.nav`, `$.task`, `$.tilemap`, `$.prefab`. `$.proc` не следует переименовывать или перегружать генерацией уровней без нужды.

Добавить reusable операции над данными: выделение связных областей, поиск горизонтальных опор/платформ, free-space queries заданного размера, distance/clearance map, weighted placement с exclusion radius и проверка связности room graph.

Для платформера обычная связность свободных клеток не доказывает проходимость. Нужен optional reachability helper с параметрами controller: footprint, jump envelope, допустимые landing spans, one-way policy. Это консервативная модель; runtime verification на выбранных маршрутах остаётся отдельным тестом.

Generation pipeline: seed → layout → collision/clearance → placement → validation → publish. Ошибка приводит к ограниченному retry с записанным derived seed или fallback. Бесконечный restart всей игры не является штатным алгоритмом генерации.

Работа через существующий `$.task`: фиксированный порядок операций и RNG calls независимо от budget. Время влияет на продолжительность загрузки, но не на результат карты. Предварительные данные не появляются в активном мире до commit.

**Приёмка:** 1 000 фиксированных seeds проходят connectivity/clearance invariants; failed seeds сохраняют отчёт. Нет spawn внутри стены и недоступного обязательного выхода в пределах принятой модели. Одинаковый seed при разных task budgets даёт одинаковый hash данных. Отмена не оставляет половину карты в мире.

## 25. P1-08. Audio и music layers

**Основа:** `$.sound`, `$.audio`, soundbank, spatial attenuation, существующий DSP и reverb.

Согласовать маршрутизацию sound/music, bus volume, pause, mute, pitch, ownership и lifecycle handles. Старые вызовы продолжают работать; новое приложение может выбрать единый managed path.

Для music stems нужен native transport: общий sample-clock start, loop region, seek, fade envelopes и квантование переключения к beat/bar при наличии соответствующих metadata. JS вызывает команду группы; запуск каждого слоя отдельным callback одного render frame не даёт sample-accurate гарантии.

Минимальные данные: stem IDs/paths, sample rate compatibility, loop points, BPM/time signature при необходимости, gain и transition policy. Авторское содержание и правила «боевой/спокойный слой» остаются в игре.

Для SFX — voice limit, priority, stealing policy, небольшие pitch/gain variations через presentation RNG. Отдельная per-bus reverb/send — P2, если текущего общего эффекта недостаточно; не предлагать замену всей звуковой библиотеки.

**Приёмка:** stems стартуют и повторяются без нарастающего рассинхрона, что подтверждено PCM/transport timestamps. Crossfade не создаёт щелчков и не удваивает громкость непредсказуемо. Pause/resume, device loss и scene exit освобождают handles. Громкость/настройки сохраняются между запусками. Headless success не заменяет проверку реального вывода звука.

## 26. P0/P1-14. RNG, replay и тестовые hooks

**Основа:** `$.random`, независимые generators, `$.replay`, fixed-dt/seed и agent protocol.

**P0:** добавить экспорт/восстановление состояния RNG с version/algorithm ID. Начальный seed недостаточен для продолжения середины сессии. Именованные streams gameplay, generation и presentation изолируют потребление случайности. Старый default stream не меняет последовательность без явной версии.

Replay header содержит engine/build ID, content hashes, schema, seed/streams, fixed step и input mapping version. Input записывается на уровне разрешённых actions; raw input может храниться дополнительно для диагностики. Existing sampler/apply API сохраняется.

Проверки state hashes выполняются в определённых simulation ticks. Divergence report показывает первый расходящийся tick, поля/IDs и версии данных. Hash исключает wall-clock timestamps, GPU handles и presentation-only значения.

**P1:** checkpoints ускоряют replay seek и запуск регрессии. Поддержка должна различать snapshot логики и exact physics continuation. Межплатформенная битовая идентичность Box2D не объявляется без доказательств; replay compatibility задаётся матрицей build/platform и tolerance там, где это оправдано.

**Приёмка:** один и тот же сценарий дважды даёт одинаковую цепочку gameplay events и hashes в заявленной конфигурации. Добавление косметического эффекта не меняет генерацию и урон. Restore RNG продолжает последовательность с нужной точки. Повреждённая/несовместимая запись отклоняется понятной ошибкой.

## 27. P1-09. Asset hot reload

**Основа:** текущие reload hooks, resource cache, SDK preview.

Reload строит dependency graph: atlas → pages/materials → clips/sockets; tilemap → collision/occlusion; RmlUi → styles/fonts/images. Подготовка новой версии выполняется до замены. Некорректный ассет сохраняет last-known-good runtime state и выдаёт failed result.

Ссылки игры должны использовать стабильный resource identity или versioned indirection. Старые texture handles освобождаются после завершения использующего их кадра. Устаревшие clip/frame IDs не остаются привязаны к новым данным молча.

Различать reload asset data, reload behavior и restart scene. Сохранение произвольных JS closures после изменения кода не обещается. При невозможности безопасного behavior reload предлагается scoped restart с сохранением поддерживаемого логического состояния.

**Приёмка:** замена texture, atlas layout, collision data и RmlUi style во время preview либо применяется согласованно, либо отклоняется без повреждения. Серия reload не увеличивает GPU/CPU memory без ограничения. Ошибка JSON не завершает игру. Итоговый пакет не зависит от файлов кэша SDK.

## 28. P0/P1-15. Debug overlays и profiling

**Основа:** `$.devtools`, `$.agent`, query/inspect/profile, replay и RmlUi.

**P0:** добавить удобные фактические представления collider/hitbox/hurtbox, contact normals, ground support, active windows, FSM, timer/flow ownership и input contexts. Существующий agent protocol расширяется, параллельный протокол не создаётся.

**P1:** profiler разделяет simulation, physics, queries, scripts, animation, particles, shadows, batch building, UI и GPU passes. Отдельно показывает количество объектов, контактов, активных источников света, частиц, draw calls, texture switches, JS↔C calls и память ресурсов.

GPU time называется GPU time только при измерении GPU timestamps. CPU submit не используется как подмена. Отсутствующая метрика остаётся unavailable. Debug buffers ограничены, expensive tracing включается явно, release overhead измеряется.

**Приёмка:** по записанному hit ID можно найти источник, контакт, решение фильтра и damage result. Inspector не обращается к уничтоженному handle. Профиль с загруженным уровнем объясняет основные затраты и сохраняется в машиночитаемом виде. Overlay рисуется через RmlUi/custom content и не меняет исход симуляции.

## 29. P1-10. SDK и специализированные authoring tools

**Основа:** существующий launcher, tool registry, native CLI и RmlUi studios.

Расширять текущие панели:

| Инструмент | Нужное расширение |
|---|---|
| Sprite Studio | trim/source-size, sockets, multipage/material consistency, import report |
| Animation Studio | markers/windows, transition validation, clock preview, interruption cases |
| Collision Tools | shape roles, masks, one-way, footprint/support preview |
| Tilemap Studio | collision/occlusion layers, chunk budget, room connections, invalid geometry |
| Particle Studio | clock/scope, trails, budget counters, deterministic replay preview |
| Audio Tools | routes, stems/transport markers, voice usage и missing assets |
| Input Tools | capture/conflicts, contexts, gamepad disconnect tests |
| RmlUi Studio | document paths, focus navigation, localization overflow |
| DevTools/Automation | scoped lifecycle, validation reports, запуск acceptance fixtures |

SDK пишет открытые данные; любое сохранение можно просмотреть diff. Runtime preview использует тот же loader и симуляцию, что игра. Native backend и JS UI validators не расходятся по defaults и допустимым полям.

Undo/redo относится к редактируемому документу. Запись нескольких зависимых файлов имеет prepare/validate/commit policy и backup либо явно описанную границу атомарности. SDK backend поставляется готовым; конечному пользователю не нужен внешний scripting runtime для стандартных authoring/validation операций.

**Приёмка:** asset можно создать/исправить, проверить CLI, открыть в preview и использовать в игре без скрытых project database. Неверный marker/shape/reference выявляется до запуска. Предпросмотр в SDK и прямой запуск проекта дают одинаковые данные. Инструменты не вводят второй scene graph.

## 30. P0-16. Packaging, export и CI

**Основа:** существующая система сборки, упаковки и SDK CLI. Задача — приёмка поставки, а не перепроектирование инфраструктуры.

Пакет содержит runtime, необходимые библиотеки, SDK backend/UI, templates, документацию, license notices и manifest версий/checksums. Зависимости ассетов разрешаются рекурсивно; missing required resource — ошибка packaging. Debug assets и абсолютные пути машины разработчика не становятся обязательной частью игры.

Отдельно определить supported profiles: обычный 2D без дополнительного authoring/runtime семейства, расширенный 2D и SDK. Матрица платформ указывает build, runtime smoke, input, audio, GPU и installed-package evidence. Непроверенный backend не объявляется production-ready.

CI выполняет schema/API compatibility, native/JS tests и интеграционные сценарии; GPU/аудио/устройства проверяются отдельными подходящими заданиями или ручной подтверждённой процедурой. Публикация версии требует зелёных проверок **того же commit/tag** и проверки release assets. Успех другого checkout не переносится автоматически.

**Приёмка:** на чистой целевой системе без исходного checkout распаковать SDK, создать пример, запустить, собрать игру, перенести её в другой каталог и повторно запустить. Проверить Unicode/пробелы в путях, сохранение в writable user directory и отсутствие записи рядом с read-only executable. Для каждого заявленного target есть результат; Web/мобильные платформы не считаются готовыми из-за наличия build option.

## 31. P0-17. Документация и вертикальные примеры

У каждого расширения: страница текущего `$` API, схема данных, единицы, defaults, lifecycle/clock policy, ошибки, ограничения, тест и запускаемый пример. Документация не перечисляет реализованные методы как отсутствующие. Новые имена явно отделяются от проектных предложений.

Нужны небольшие, но законченные примеры:

1. **Platform foundations:** края, склоны, one-way, moving platforms, camera zones и gamepad.
2. **Melee/contact:** окна анимации, несколько hurtboxes, отражение projectile, knockback и feedback.
3. **Pattern arena:** отменяемые фазы, spawn pool, pause, death и restart.
4. **Generated rooms:** seeds, clearance/reachability report, task budgets и checkpoints.
5. **Lit sprites:** masks, occlusion, normal/flat fallback и atlas flips.
6. **Runtime integration:** RmlUi HUD, localization, existing timeline, music stems и scoped transition.
7. **Recovery:** save failure, corrupted asset, safe reload и replay divergence.

Это SDK/examples, а не обязательные игровые шаблоны с жёстко заданным жанром. Все они используют только `$`; внутренний native API не появляется в пользовательских инструкциях.

**Приёмка:** примеры работают из установленного пакета и имеют короткую автоматическую проверку. Документированные вызовы проверяются на совпадение с реализацией. Ограничения видимы рядом с API, а не только в истории обсуждений.

## 32. P2. Расширения после основных контрактов

- Дополнительные режимы существующих trails, particle collisions и GPU-симуляция после подтверждения bottleneck.
- Расширенные light quality modes, SDF/другая техника теней после сравнения с существующим segment path.
- Дополнительные animation layers/additive blending для 2D-частей, если реальным ассетам недостаточно текущего mixing.
- Platform-aware navigation links и построение маршрутов сложных противников поверх controller reachability.
- Фоновый room streaming с ограниченными memory budgets и cancellation.
- Per-bus reverb/send, дополнительные музыкальные transitions и transport tooling.
- Расширенные shader/material authoring tools с фиксированной 2D-границей.
- Более подробный trace/replay timeline в DevTools и инструменты сравнения профилей.

Каждый пункт требует отдельного запроса применения, измеримой пользы и проверки совместимости. Они не должны задерживать закрытие конкретного P0-дефекта.

## 33. Предлагаемые расширения форматов

Это состав данных, а не утверждение о готовой новой схеме. Поля добавляются в существующие форматы после проверки конфликтов.

| Данные | Минимальное расширение | Потребители |
|---|---|---|
| Atlas | sourceSize, trim, pivot/socket, frame duration, page, import settings/hash | Sprite/Animation Studio, `$.atlas`, playback |
| Animation | stable marker IDs, window intervals, named targets, clock, interruption policy | `$.anim`, node wrappers, combat |
| Collision | shape role, owner reference, masks, one-way policy, material tags | Existing physics loader, queries, tools |
| Room/prefab | stable instance/child IDs, bounds, exits, markers, references | `$.prefab`, `$.scene`, generation |
| Save | schema/content version, stable ID keyed state, RNG states, logical timers/FSM | `$.save` и restore hooks |
| Replay | build/content hashes, step, input schema, checkpoints/hashes | `$.replay`, agent tests |
| Material | albedo/normal/emissive refs, convention, lit flag | 2D import, sprite batch |
| Music | stems, loop points, gain, transport metadata | Existing sound/audio API, native transport |
| Input | action/context, bindings, device policy, capture settings | `$.input`, RmlUi settings |
| Validation report | code, severity, path, JSON pointer, related IDs | Native CLI, SDK UI, automation |

Не вводить единый гигантский формат проекта. Небольшие документы связываются обычными resource references; prefab остаётся источником описания узлов.

## 34. Порядок реализации и зависимости

| Этап | Содержание | Зависимости | Gate |
|---|---|---|---|
| A | Зафиксировать baseline API и локальные изменения, ошибки, clocks, ownership; спроектировать совместимые local/world transforms (§39) | Текущее дерево и существующие тесты | Понятно, что опубликовано, что локально; старые примеры сохранены |
| B | Local/world transforms, compound sensors, contact/controller contract, lifecycle и input contexts | A | Controller fixtures + repeated restart + pause |
| C | Multi-target/property/audio animation tracks, animation windows, hit/hurt resolution, flows/patterns | B | Бой воспроизводим, прерывания и death корректны |
| D | Stable IDs, RNG state, transactional save и replay hashes | A–C | Mid-session restore, corrupted save и deterministic replay |
| E | Atlas correctness, partial-tile collision, simplex noise, room data, tilemap transactions и generation validation | B, D; базовый atlas можно раньше | Seed corpus и room reload без неполного мира |
| F | Renderer integration, camera arbitration, lighting/materials и VFX budgets | A–C, atlas из E | Visual references + CPU/GPU measurements |
| G | Audio routing/stems, timeline integration, UI/localization | A, B, D | Real input/audio + stop/skip/restore сценарии |
| H | SDK panels, examples, installed packaging и release acceptance | Вертикальные срезы предыдущих этапов | Чистая установка и evidence каждого заявленного target |

Документация, validation и необходимые тесты выполняются в каждом этапе. SDK и упаковка получают минимальные обновления вместе с форматом, а не откладываются целиком на H. Gate H завершает поставку.

Сначала закрывать один полный сценарий, затем обобщать подтверждённую потребность. Например: attack marker → active sensor → one hit → knockback → feedback → death → restart. Это полезнее независимого расширения десятков API без интеграционного доказательства.

## 35. Общая программа приёмки

### 35.1. Корректность

- Unit: geometry, masks, clocks, RNG, schema validation, marker crossing, damage deduplication.
- Integration: fixed-step контроллер, attack interruption, reflected projectile, platform carry, trigger cleanup.
- Recovery: cancelled load, invalid asset, interrupted save, restore in mid-action, device reconnect.
- Lifecycle: restart/load/reload loops со счётчиками объектов и ресурсов.
- Visual: pixel stability, alpha order, light/normal orientation, shadows, UI scaling; эталоны с фиксированной конфигурацией.
- Audio: transport alignment, loop continuity, routing и fade; PCM/временные метки плюс прослушивание.
- Delivery: запуск установленного пакета вне checkout.

### 35.2. Производительность

Предварительный целевой профиль для обсуждения: 1920×1080, 60 FPS, fixed simulation 60 Hz. Это **цель**, а не измеренный результат текущего движка. Более высокая частота — отдельный профиль.

Набор сцен должен отдельно нагружать physics/contacts, tilemap, alpha/VFX, lights/shadows и UI. Начальные stress-fixtures: 200 активных противников, 500 снарядов, 5 000 частиц, 32 света, большая карта с видимой и невидимой частью. Эти числа — предложенные точки измерения; перед gate фиксируются реальные asset complexity, collision shapes и аппаратный target.

Для каждого target сохранить hardware/OS/backend, build flags, commit/content hash, разрешение, counts, warmup и длительность. Сообщать frame p50/p95/p99, simulation CPU, render CPU, GPU time если доступно, peak memory и loading time. Не складывать CPU/GPU времена как независимые части без учёта перекрытия.

Предлагаемый gate базового 60 FPS-профиля: p95 frame time ≤ 16,67 мс в согласованных игровых сценах; p99 и допустимые loading spikes фиксируются отдельно до оптимизации. Невыполнение gate приводит к явному ограничению профиля или работе с измеренным bottleneck, а не к общему заявлению «оптимизировано».

### 35.3. Доказательства

Каждый закрытый пункт имеет: revision, команду/сценарий, ожидаемое и фактическое поведение, машинный отчёт, ограничения. Изображение доказывает визуальное поведение выбранного кадра, тест — проверенные инварианты, benchmark — измеренную конфигурацию. Одно доказательство не подменяет другое.

## 36. Anti-goals

- Не менять `$` на другой язык, классовый framework, публичный native bridge или второй namespace движка.
- Не вводить ECS, components и параллельную модель игровых сущностей.
- Не создавать обязательный visual scene editor или скрытую project database.
- Не превращать SDK в отдельный runtime с собственными physics/render/animation реализациями.
- Не переписывать renderer, physics, input, audio, save, event bus и animation graph при наличии пригодной основы.
- Не создавать новую диалоговую систему и отдельный диалоговый плагин.
- Не превращать Re2D authoring/import в generic 3D runtime; не расширять ради этого scope движка.
- Не встраивать конкретные boss scripts, классы персонажей, формулы брони, лут-таблицы и правила прохождения в обязательное ядро.
- Не обещать arbitrary JS closure serialization, универсальный rollback или межплатформенный bit-exact physics без отдельного проекта и доказательств.
- Не делать наличие API, файла теста, успешной сборки или красивого кадра единственным основанием production-ready статуса.

## 37. Итоговый checklist production-ready

### Обязательная архитектура

- [ ] `$` остаётся единственной публичной точкой входа для всех новых возможностей.
- [ ] Node/tag/wrapper и текущие селекторы/цепочки сохранены; ECS/components не введены.
- [ ] Игра создаётся кодом и открытыми данными; SDK необязателен для её запуска.
- [ ] Новый UI/HUD/DevTools использует RmlUi.
- [ ] Существующий timeline интегрирован; параллельной диалоговой системы нет.
- [ ] Обычный 2D-профиль работает без зависимости от Re2D authoring.

### Базовая надёжность P0

- [ ] Иерархические local/world transforms согласованы для visuals, attached sensors и markers; старый world-space API сохранён.
- [ ] Multi-target tracks управляют bool/enum/physics/audio bindings без обхода публичного `$`.
- [ ] Частичные tile colliders и logical cell origins покрыты интеграционной проверкой.
- [ ] Для заявленного шумового профиля есть фиксированный seeded simplex и sample fixtures.
- [ ] Processing policy отделена от visibility/body sleep; physics ticks отделены от render frames.
- [ ] Ресурсная загрузка сообщает настоящий progress/failure/cancel и не блокирует UI сверх принятого бюджета.

- [ ] Сцены и последовательности имеют проверенный cleanup узлов, тел, подписок, timers/tasks и ресурсов.
- [ ] Pause, hit-stop, slow motion, UI и audio имеют согласованные часы.
- [ ] Controller проходит края, углы, потолки, one-way и moving platforms.
- [ ] Contacts и queries безопасны при отключении/удалении форм и смене сцены.
- [ ] Attack windows согласованы с animation и fixed step; повторный урон дедуплицируется.
- [ ] HP/death/knockback не конфликтуют с controls и presentation feedback.
- [ ] Фазовые сценарии отменяются без отложенных выстрелов и callbacks.
- [ ] Input contexts, rebinding, focus и gamepad reconnect проходят сквозной сценарий.
- [ ] Save использует устойчивые ID и защищает последнее корректное состояние.
- [ ] Restore восстанавливает behavior, RNG, таймеры и связи без повторных подписок.
- [ ] Replay обнаруживает divergence и проверяет версии build/content.
- [ ] Критические ошибки доступны машине и пользователю; incomplete load не выдаётся за success.

### Заявленный расширенный профиль P1

- [ ] Atlas trim/pivot/duration/socket проверены; неподдерживаемый импорт отклоняется явно.
- [ ] Room и tilemap изменения согласуют visuals, physics и occlusion.
- [ ] Generation имеет ограниченный retry, seed report, clearance и reachability checks.
- [ ] Camera bounds/transitions/leases работают при resize, pause и cutscene-stop.
- [ ] Light masks, динамические occluders и quality limits измерены.
- [ ] Если заявлены normal maps, проверены UV, flip/rotation, color space и fallback.
- [ ] VFX имеют ограниченные pools/budgets и независимый RNG.
- [ ] Если заявлены music stems, синхронизация подтверждена аудиоданными.
- [ ] Hot reload сохраняет last-known-good при ошибке и не протекает ресурсами.
- [ ] HUD/localization/timeline корректны на заявленных языках и устройствах.

### Поставка и сопровождение

- [ ] Установленный пакет создаёт, запускает и собирает пример без checkout.
- [ ] Каждый заявленный platform/backend имеет собственный результат приёмки.
- [ ] Release checks и assets соответствуют одному commit/tag.
- [ ] Согласованный performance profile выполнен; CPU/GPU и ограничения названы корректно.
- [ ] Примеры используют только `$` и поставляются вместе с актуальной документацией.
- [ ] Форматы, schemas и validators согласованы; данные открыты и пригодны для diff.
- [ ] Незакрытые P1/P2-возможности явно отсутствуют в обещаниях соответствующего профиля.

**Правило объявления готовности:** production-ready — это проверенный набор сценариев на конкретной версии, платформе и профиле возможностей. Базовый статус требует всех P0. Расширенная возможность включается в обещания только после собственного acceptance gate.

## 38. Навигация по исходникам движка

Пути приведены для инженера, который будет выполнять спецификацию; это не новые модули.

| Тема | Основные файлы |
|---|---|
| Философия и публичный API | `docs/PHILOSOPHY.md`, `docs/ARCHITECTURE.md`, `docs/AGENT_IMPLEMENTATION_RULES.md`, `docs/highlevel/_CONTRACT.md`, `src/highlevel/core.js`, `api.js`, `native.js` |
| Renderer/light | `src/render.c`, `src/render.h`, `src/highlevel/render.js`, `layers.js`, `fx.js` |
| Camera | `src/highlevel/camera.js`, `viewports.js`, `viewport.js` |
| Physics/controller | `src/physics.c`, `src/physics.h`, `src/highlevel/world.js`, `collision.js`, `api.js` |
| Animation/FSM | `src/highlevel/anim.js`, `animplayer.js`, `state.js`, `flow.js` |
| Combat/effects | `src/highlevel/combat.js`, `weapons.js`, `hits.js` — локальное расширение |
| Assets/maps | `src/highlevel/atlas.js`, `tilemap.js`, `prefab.js`, `resource.js` |
| Generation | `src/highlevel/grid.js`, `random.js`, `nav.js`, `task.js` |
| Events/time | `src/highlevel/signal.js`, `triggers.js`, `time.js`, `scene.js` |
| Save/replay | `src/highlevel/save.js`, `store.js`, `replay.js`, `agent.js` |
| Audio/input/UI | `src/highlevel/sound.js`, `audiobus.js`, `soundbank.js`, `input.js`, `ui.js`, `i18n.js`, `src/gui.cpp` |
| Dialogue integration | `src/highlevel/dialog.js`, `timeline.js`, `cutscene.js`, `story.js` |
| SDK | `sdk_tools.json`, `sdk/`, `docs/SDK.md`, `docs/SDK_IMPLEMENTATION_GAPS.md` |
| Проверки | `tests/js/`, `tests/agent/`, native tests, `docs/TESTING.md`, `docs/RECORD_REPLAY.md` |

Опубликованная основа: [дерево зафиксированного commit](https://github.com/Nikide/russiano2d/tree/da2d27390d2dc0e1f38a3a83e8ed6a0c08976f06). Локальные изменения следует повторно сверить перед реализацией каждого этапа: этот документ не является командой откатить или заменить текущую работу.


## 39. P0-18. Полноценные 2D local/world transforms

**Подтверждённый пробел:** `appendTo/append` связывают parent/children, но `.at/.angle/.scale` и обычный native `drawWorld` используют собственные координаты узла. Наследование visibility/alpha/depth существует; из него не следует наследование transform. `.globalPos()` сейчас возвращает camera-space позицию; `.toGlobal/.toLocal` также включают камеру и не являются полноценным преобразованием дочернего пространства через цепочку rotation/scale.

**Почему это необходимо:** оружие вращается и зеркалится относительно отдельной опоры; sensor и частицы следуют оружию; muzzle marker должен возвращать мировую точку после всех преобразований. Ручное копирование позиции героя в каждый ребёнок не покрывает отрицательный scale, поворот и nested offsets.

**Минимальная реализация:** добавить opt-in local transform существующего узла: translation, angle и signed scale; вычислять world transform композицией родителей. Старые `.at()` и `.pos()` не менять молча. Предложенные имена `localAt/localAngle/worldPoint/localPoint` сначала проверить на конфликт; можно использовать option transformSpace в текущем формате. Screen↔world остаётся зоной камеры с отдельными именами.

Нативный проход вычисляет dirty transforms пакетно с защитой от циклов. Reparent имеет keep-world/keep-local policy. Обычный physics root остаётся world-space; child sensor/visual получает вычисленный transform до физического шага/отрисовки. Не разрешать произвольный shear или изменение dynamic body's geometry без явной поддержки backend.

**Приёмка:** персонаж на `(100,200)`, pivot offset `(10,0)`, его child marker `(20,0)`: корректный world point до/после flip и поворота. Оружие, hitbox, emitter и marker совпадают. Camera zoom/rotation не меняет world point. Старый проект с world-space children сохраняет прежний вид. Это расширение существующего node tree, не новый scene graph.

## 40. P0-19. Независимые sensors и shape enable

**Подтверждённая основа:** box/circle/capsule/polygon, sensor, masks и contacts уже есть. Wrapper хранит форму тела узла; изменение формы/сенсора вызывает пересинхронизацию. Независимое включение нескольких привязанных shapes с собственной ролью и owner mapping не следует считать готовым из наличия `.sensor()`.

**Требование:** представить несколько областей либо существующими дочерними sensor nodes с attachment, либо native compound shapes за тем же `$` API. Выбор внутреннего представления не должен менять gameplay. В каждом случае есть logical owner, role, local offset/angle, layer/mask и enabled. Disabled shape исключена из overlap/physics без удаления игрового владельца.

Contact routing может вернуть sensor node и logical owner отдельно. Удаление или пересоздание native shape не должно обнулять attack deduplication. `.hide()`, body sleep, отсутствие обработки и отключение sensor — разные операции.

**Приёмка:** movement capsule, contact circle и weapon rectangle одного владельца работают независимо; выключение sword sensor не отключает движение. Flip/rotation следует §39. После открытия attack window уже находящаяся внутри цель обнаруживается по явно определённой overlap policy, без ожидания нового движения. Destroy/re-enable не даёт stale callbacks.

## 41. P0-20. Multi-target animation и property/audio tracks

**Подтверждённый пробел:** `animplayer.js` нормализует tracks типов position/scale/rotation/alpha/color/sprite/value/event и пишет их в одну target node. `value` с attr пишет в `node.attrs`; это не setter для visibility, physical shape enabled, выбора sprite clip или audio bus. Одна и та же игровая последовательность требует нескольких узлов одновременно.

**Расширение существующего плеера:** у track появляется target relative к корню плеера, стабильный target ID/path, typed binding и update mode. Поддержать continuous numeric tracks, discrete bool/enum tracks и event/audio cues. Binding разрешается до play, а не ищется селектором по всей сцене каждый кадр.

Минимальные bindings: visual transform, visible, tint/alpha, sprite animation/frame, emitter emitting/position, shape enabled, light intensity/radius, RmlUi element style/value и audio handle gain. Свойства применяются через зарегистрированные адаптеры существующих подсистем; произвольный JSON path не должен обходить physics safety.

Audio cue хранит resource, bus, gain, offset, optional stop/length и policy при seek/loop. Volume envelope привязан к созданному handle; он не меняет громкость всех чужих звуков. Method track вызывает зарегистрированное игровое действие или emit, без eval строки.

Reset/initial pose задаёт известные значения. Описать поведение play, play-same, restart, stop, completion и interruption. Уже существующий idempotent play-same сохранить. После seek/skip discrete state пересчитывается, а необратимые damage/spawn cues не выполняются повторно по умолчанию.

**Приёмка:** один клип управляет кадрами героя, поворотом/позицией/видимостью оружия, attack sensor, emitter и SFX; другой — несколькими персонажами, camera cue, UI fade и музыкой. Сериализованный JSON воспроизводится без ручного frame callback на каждую дорожку. Preview seek не наносит урон. Событие окончания каждой части продолжает flow ровно один раз.

## 42. P0-21. Частичная коллизия тайла и логические координаты

**Подтверждённый пробел:** collision builder тайлкарты объединяет solid cells в полные прямоугольники. Узловые polygon shapes есть, но это не per-tile collision descriptor. Требуются клетки с collider только в нижней полосе: например, visual 32×32 и physical rect `[-16,8]..[16,16]` в системе центра тайла.

**Требование:** в текущих tileset data добавить descriptor для visual region/source, local collision geometry, masks и occluder geometry. Для полной клетки оставить быстрый merge. Для частичной геометрии объединять только действительно эквивалентные соприкасающиеся формы; не расширять collider до размера изображения.

Queries `.fitsAt/.sample` и navigation clearance учитывают реальную форму там, где заявляют геометрическую точность. Клеточная занятость и реальная physics-геометрия различаются явно. Тайловые occluders уже имеют путь в существующее освещение; их соответствие partial shapes проверяется отдельно.

Генератору нужны отрицательные граничные клетки и верхняя/нижняя рамка за основной областью. Это можно выразить finite array с logical origin и padding; sparse infinite map не обязательна. World↔cell преобразования учитывают origin, размер тайла и transform карты. Несколько atlas sources канонизируются в таблицу visual IDs; сырой чужой resource ID не становится runtime API.

**Приёмка:** персонаж стоит на фактической верхней границе тонкой платформы; raycast и clearance не видят заполненной пустую часть клетки. Граница `x=-1` и нижний padding создаются без выхода за буфер. Visual/collision/occlusion адресуют одну клетку; повторная сборка не меняет её положение.

## 43. P0-22. Simplex noise и детерминированная генерация

**Подтверждённый пробел:** текущий `$.random.noise2D` — value noise. Simplex noise с seed/frequency имеет другую структуру и распределение; замена при том же пороге меняет длины платформ и расстояния между ними.

**Минимум:** добавить именованный алгоритм в существующее random namespace либо новый метод этого namespace. Контракт: algorithm/version, seed, frequency, диапазон значений и sample coordinates. Старый value noise оставить без изменения последовательностей. Octaves/fBm — optional, не предварительное условие.

Для сохранения геометрии нужны проверенные sample fixtures, а не совпадение одного названия алгоритма. При требовании точного воспроизведения конкретной функции фиксируются её вариант, seed mapping и нормализация. Если выбирается другой вариант, допустимость новой геометрии проверяется отдельно и не называется точным совпадением.

Layout thresholds, подбор свободных квадратов, группировка горизонтальных платформ по длине, центр/край спавна и вероятности остаются JS над `$.grid/$.tilemap/$.random`. Их не требуется переносить в C или оформлять как обязательный генератор движка. Native batch helper добавлять только при измеренном bottleneck.

**Приёмка:** эталонные samples и итоговый hash сетки стабильны. Изменение task budget не меняет клетки. Два разных пороговых профиля и регулярный безшумовой профиль строятся одним набором примитивов. Validation выполняется до публикации карты; логические ошибки пользовательского цикла не компенсируются скрытой логикой движка.

## 44. P0-23. Обработка узлов, visibility events и simulation ticks

**Подтверждённая основа:** `.visible/.show/.hide`, camera culling, body sleep и frame callbacks существуют. `.pause()` wrapper усыпляет тело; это не гарантированное отключение пользовательского physics callback, таймера и attack sensor.

Нужны отдельные opt-in policies для node update, fixed-step update, animation, timers и physics participation, с наследованием scope там, где оно явно включено. Усыпление body не считается отключением gameplay. Перевод в inactive не скрывает визуал автоматически и наоборот.

Visibility/activation helper публикует screen-enter/screen-exit или region-enter/exit. Используются реальные world bounds после §39, margin/hysteresis и выбранная камера. При нескольких камерах policy any/specific. Once-on-first-entry выражается через существующий once/event mechanism.

Публичный physics-step counter или fixed-step callback отделяется от render frame. Период «каждые 30 physics ticks» и время жизни «300 physics ticks» должны выражаться через `$` без зависимости от render FPS. Предпочтительно использовать duration или state-local tick counter; global tick modulo оставлять только как явно выбранную семантику.

**Приёмка:** inactive enemy не получает movement updates, его sensor включается отдельно при активации, а death timer освобождает объект по заявленному clock. Снаряд живёт одинаковое simulation time при разном FPS. Анимационная completion продолжает выполняться, если остановлено только movement logic. Объект не зависает навсегда из-за смешения visibility и processing.

## 45. P0-24. Фактическая загрузка и progress

**Подтверждённая основа:** `$.scene.loadAsync`, `$.loading`, `$.task` и resource registry есть. Из этого не следует worker I/O/decode: синхронный `read/decode` внутри порции JS всё ещё блокирует кадр.

Требуется native resource request с queued/loading/decoded/uploading/ready/failed/cancelled и progress в известных единицах. I/O/decode могут работать вне главного потока; GPU upload и установка JS-объектов выполняются безопасно в допустимом потоке. QuickJS context не используется конкурентно.

В `$` существующий loading/scene API получает resource request handle или dependency list. Progress различает реальные bytes/jobs и оценочный stage; неизвестная доля не выдаётся за точный процент. Scene instantiate остаётся кодом/prefab creation в безопасной фазе. Для тяжёлой инстанциации используется уже имеющийся `$.task`.

**Приёмка:** тяжёлый PNG/audio load не блокирует loading animation и cancel input в согласованном бюджете. Неверный path даёт failed, отменённая сцена не появляется позже новой. Таймер прохождения не считает загрузку, если такова policy игры. Старый синхронный API продолжает работать.

## 46. P1-11. Пользовательский экранный эффект

**Подтверждённая основа:** `$.gfx.defineShader`, sprite parameters и built-in `$.gfx.post` с grain/scanline/chromatic/tint уже есть. Не предлагать shader API с нуля. Но screen distortion требует sampling всего ранее отрисованного изображения, иногда дополнительной noise texture, нескольких uniforms и выбранного clock.

Расширить существующий post/viewport путь одним безопасным screen pass: source texture, optional auxiliary texture, bounded typed parameters, resolution/time, blending и ownership. Запретить чтение из одновременно записываемого target. Момент включения UI определяется pass order; эффект можно применять к миру или к согласованному composition layer.

Для ограниченного набора художественных задач допустим встроенный параметризованный distortion preset вместо generic graph. Нельзя объявлять grain+chromatic эквивалентными tape smear/crease/jitter без визуальной проверки.

**Приёмка:** screen wave, noise и смещение каналов работают при resize и меняющейся камере, не требуют generic 3D/material runtime и имеют fallback. Save/replay логики не зависит от visual noise. Шейдерные ошибки сохраняют предыдущий рабочий effect и сообщают diagnostics.

## 47. P1-12. Недостающие параметры particle profile

**Уже есть:** rect/circle emission zones, direction/spread, life range, gravity vector, angle/angular velocity, size/color/alpha ramps, local/global, one-shot, explicit burst schedule, fields и blend. Trails/ribbons также есть в `$.fx`.

**Расширить только при необходимости соответствующего эффекта:**

- Emission cycle duration, explosiveness и timing randomness с определённым распределением рождения; explicit burst schedule может быть каноническим выходом authoring, если он воспроизводит нужный эффект.
- Per-emitter speed scale без изменения simulation clock всей игры.
- Radial/tangential acceleration от origin конкретного эмиттера. Существующее глобальное field не равнозначно этому автоматически, особенно при local particles и движении родителя.
- Hue variation в согласованном цветовом пространстве; при достаточности можно authoring-преобразованием выбрать particle colors из палитры, без нового runtime color model.

**Приёмка:** preset фиксирует seed и параметры, повторяется при fixed step, корректно работает с отрицательной gravity и перемещением emitter. Exact frame image определяется отдельной художественной приёмкой, а не совпадением названий параметров. Эти расширения не задерживают основной бой, если выбран принятый эффект на имеющихся параметрах.

## 48. P1-13. Audio bus effect isolation

**Уже есть:** шины, spatial helpers, playback, gain/pitch и reverb/DSP. Этого достаточно для базовых SFX, музыки и master-volume slider. Нельзя планировать новую audio subsystem.

**Конкретный gap:** если требуется реверберация только выбранных источников/шины, общий reverb всего mix не сохраняет такое поведение. Нужен wet/send или изолированный bus DSP в существующем backend. Иерархия/имена шин могут оставаться JS-моделью, но фактическая обработка PCM должна соответствовать выбранному route.

dB и linear gain различаются явно. Envelope от анимации применяется к своему playback handle/route. Layered music transport — независимое расширение §25, не обязательное условие нескольких обычных audio cues.

**Приёмка:** dry UI click остаётся dry при активном wet ambience; master volume управляет обоими путями; pause, restart и autoplay не оставляют лишние голоса. Проверка проводится по PCM/прослушиванию, не только по числу handles.

## 49. Минимальная последовательность закрытия функциональных пробелов

1. §39–40: transforms и независимые sensors. Gate: sword/muzzle/вращающаяся область совпадают после flip/rotation.
2. §41 + §6: multi-target tracks и единое время. Gate: полный attack clip с окном, частицами, звуком и interrupt.
3. §42–43: partial tiles и simplex. Gate: карта, платформы, свободные зоны и spawn описываются `$`-скриптом без новых игровых подсистем.
4. §44–45 + §5: processing/activation, загрузка и cleanup. Gate: start → room → death → retry → next room без оставшихся узлов/подписок.
5. §46–48: точность screen/particle/audio presentation для заявленного visual/audio-профиля.
6. Остальные P0-интеграционные проверки из основной части; затем P1/P2 по требуемому профилю продукта.

Этот порядок закрывает конкретную выразимость игровых сценариев. Игровое поведение пишется на существующем JavaScript через `$`, а сцены/ассеты описываются открытыми данными SDK. Публичный scripting API и архитектура узлов сохраняются.
