# Единые пакеты расширений `packages//manifest.json` объявляет точные версии, лицензии, зависимости, возможности и ресурсы. При запуске сервер проверяет весь граф зависимостей, размеры, SHA-256, пути и отсутствие symlink. Отсутствующая версия, цикл, неизвестная возможность или изменённый ресурс останавливают запуск. Публикуются только `client` и `common`; файлы `server` не имеют публичного маршрута. Ресурс повторно проверяется при HTTP-чтении. Примеры — `packages/base` и `packages/trampoline`. Все изображения, звук и модели авторские. Данные каталога происходят из официальных отчётов и измерения публичного API Java 26.2; ванильные текстуры и модели в пакеты не входят. Манифест schema 1 содержит: - `id`, `version` из трёх числовых частей, `license`; - `dependencies:[{id,version}]` с точными версиями; - `capabilities`, например `blocks.define`, `client.texture`, `server.on_jump`; - `resources:[{path,scope,role,sha256,size}]`. Один ресурс не больше 16 МиБ; пакет не больше 64 МиБ, до 128 ресурсов, до 128 записей в каталоге пакетов. Это ограничения сервера; браузер дополнительно ограничивает суммарно проверяемые публичные ресурсы 128 МиБ на подключение. Определения блоков имеют роль `definitions`, ресурс с этой ролью требует schema 1. Сервер допускает до 4096 дополнительных определений. Блок задаёт `state` как новый идентификатор `namespace:path` без свойств (строчные ASCII-буквы, цифры, `_`, `.`, `-`, дополнительно `/` в path), `color:[r,g,b]`, `collision:[{min,max}]` и необязательный `render` аналогичной формы. Необязательный `opacity` — число 0…1. Если render не указан, используется существующая авторская форма того же состояния или коллизия нового блока. Максимум 64 бокса на каждый набор; допустимый локальный диапазон координат −2…3. Дубликаты определений и переопределение `minecraft:*` отвергаются. Runtime ID назначает сохраняемый реестр; `Game::open` расширяет каталог проверенными определениями до регистрации в WorldStore. Обычный пакетный блок без `behavior` хранится и участвует в физике; `behavior.server_hook: on_jump` связывает его с активным WASM-провайдером. ```json { "schema": 1, "blocks": [{ "state": "example:spring", "color": [97,205,151], "collision": [{"min":[0,0,0],"max":[1,1,1]}], "render": [{"min":[0,0,0],"max":[1,1,1]}], "behavior": {"server_hook":"on_jump"} }] } ``` ## Исполнение модуля В MVP нужен ровно один активный провайдер серверного hook `on_jump`; отсутствие провайдера или два модуля с этой ролью останавливают запуск. Серверный `.wasm` объявляется ресурсом `role: "wasm-on-jump"`, `scope: "server"`; необходима capability `server.on_jump`. Экспорт `on_jump: () -> f32` возвращает импульс прыжка в блоках/с. Сервер вызывает его только при прыжке игрока с блока, который связан с hook через проверенное определение пакета. Исполнение идёт в Wasmi: без импортов, файлов, сети и системных вызовов; до 10 000 единиц fuel на вызов, одна память до 64 КиБ, одна таблица до 128 элементов, один экземпляр. Бинарный модуль не больше 64 КиБ. Результат должен быть конечным числом 0…20; trap или недопустимое значение фиксируется метрикой и даёт обычный прыжок. Выполняемый пример возвращает 10. Тесты проверяют реальный вызов, бесконечный цикл, превышение памяти, попытку импорта и NaN. Отдельный тест создаёт пакет `example:spring`, проверяет его SHA-256, добавляет новый блок в каталог, регистрирует и сохраняет runtime ID, связывает блок с модулем и получает импульс 12 от собственного бинарного WASM. Дубликаты, Minecraft override, недопустимая геометрия, opacity/идентификатор и изменение ресурса после загрузки отвергаются. Это ограниченный действующий API расширения, а не обещание произвольной совместимости с Forge/Fabric или доступа WASM к полному состоянию мира. Для нового hook необходима явная версия контракта. Spleef в этом MVP реализован серверным режимом Rust с сохраняемыми правилами. ## Клиентские ресурсы `/api/manifest` возвращает публичный список с URL, точной версией, размерами и SHA-256. Браузер скачивает файлы, проверяет размер и хеш **до входа**, затем кладёт в CacheStorage по хешу. При повторном подключении содержимое кэша тоже проверяется. Ошибка хеша удаляет повреждённую запись и запрещает вход. Неподходящий `manifest_hash` сервер отвергает. Публичный хеш не подтверждает, что клиентское приложение не модифицировано. Базовый пакет даёт пиксельную текстуру; trampoline — собственную текстуру, GLSL-функцию окраски, настройку стиля и короткий синтезированный звук. Они применяются собственным WebGL2-рендерером. В ядре и сервере отсутствует графический движок. Пакет не загружает произвольный привилегированный JavaScript. Для изменения пакета пересчитайте размер и SHA-256 каждого изменённого ресурса, увеличьте версию и обновите точные зависимости. `scripts/catalog_assets.py` воспроизводимо генерирует встроенные авторские ресурсы и манифесты. Формат ориентирован на будущий лаунчер: лаунчер сможет получить тот же manifest и кэшировать по `(id,version,sha256)`; интеграция конкретного лаунчера в этот репозиторий не входит.