Манифест ресурсов и его структура

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

Манифест ресурсов — это структурированный объект (или внешний JSON-файл), содержащий информацию о:

  • наборах ресурсов (bundles),
  • ключах (aliases),
  • путях к файлам,
  • типах ресурсов,
  • дополнительных параметрах загрузки.

В современной архитектуре PixiJS (начиная с версии 7) манифест тесно связан с системой Assets, заменившей устаревший Loader.


Система Assets и роль манифеста

Модуль Assets в PixiJS предоставляет высокоуровневый интерфейс для:

  • асинхронной загрузки,
  • кэширования,
  • группировки ресурсов,
  • повторного использования загруженных данных,
  • динамической подгрузки.

Манифест подключается через метод:

await Assets.init({ manifest });

После инициализации ресурсы можно загружать по имени bundle:

await Assets.loadBundle('ui');

Или по конкретному ключу:

const texture = await Assets.load('button');

Таким образом, манифест формирует контракт между структурой проекта и системой загрузки.


Базовая структура манифеста

Минимальная структура манифеста выглядит следующим образом:

const manifest = {
  bundles: [
    {
      name: 'ui',
      assets: [
        { alias: 'button', src: 'assets/ui/button.png' },
        { alias: 'panel', src: 'assets/ui/panel.png' }
      ]
    }
  ]
};

Основные поля

bundles — массив групп ресурсов.

Каждый bundle содержит:

  • name — уникальное имя группы.
  • assets — массив описаний ресурсов.

Каждый ресурс включает:

  • alias — уникальный ключ.
  • src — путь к файлу.

Bundles: логическая группировка ресурсов

Bundles позволяют разделять ассеты по смыслу или этапу использования:

  • preload — обязательные ресурсы для старта
  • ui — интерфейс
  • level1 — ресурсы первого уровня
  • audio — звуки
  • common — общие текстуры

Пример расширенной структуры:

const manifest = {
  bundles: [
    {
      name: 'preload',
      assets: [
        { alias: 'logo', src: 'assets/common/logo.png' }
      ]
    },
    {
      name: 'level1',
      assets: [
        { alias: 'background', src: 'assets/levels/1/bg.jpg' },
        { alias: 'enemy', src: 'assets/levels/1/enemy.png' }
      ]
    }
  ]
};

Преимущества такого подхода:

  • уменьшение времени первичной загрузки,
  • ленивое подключение уровней,
  • управление памятью через выгрузку bundle,
  • модульная архитектура.

Поддержка разных типов ресурсов

Манифест не ограничивается изображениями. Поддерживаются:

  • изображения (PNG, JPG, WebP),
  • атласы текстур (JSON + PNG),
  • шрифты,
  • видео,
  • аудио,
  • бинарные файлы.

Пример с атласом:

{
  alias: 'characters',
  src: 'assets/atlas/characters.json'
}

PixiJS автоматически определяет тип ресурса по расширению и применяет соответствующий парсер.


Использование массивов источников (множественные src)

Для поддержки разных форматов (например, WebP и PNG) можно указать массив:

{
  alias: 'background',
  src: [
    'assets/bg.webp',
    'assets/bg.png'
  ]
}

Система выберет первый поддерживаемый формат. Это особенно важно для кроссбраузерной совместимости.


Глобальные настройки манифеста

Возможна передача дополнительных параметров в Assets.init:

await Assets.init({
  manifest,
  basePath: './',
  defaultSearchParams: { v: '1.0.0' }
});

basePath

Позволяет задать общий префикс для всех путей.

defaultSearchParams

Добавляет query-параметры ко всем запросам (например, для кэш-бастинга).


Расширенная структура: вложенные объекты

Вместо массива assets допускается объектная форма:

{
  name: 'ui',
  assets: {
    button: 'assets/ui/button.png',
    panel: 'assets/ui/panel.png'
  }
}

PixiJS автоматически преобразует её к стандартному формату.

Это удобно при генерации манифеста сборщиками (Webpack, Vite и т.п.).


Динамическое добавление bundles

Манифест может быть расширен после инициализации:

Assets.addBundle('dlc', [
  { alias: 'boss', src: 'assets/dlc/boss.png' }
]);

Это позволяет:

  • подключать DLC,
  • загружать ресурсы с сервера,
  • реализовывать модульную систему плагинов.

Удаление и выгрузка ресурсов

Система Assets поддерживает освобождение памяти:

Assets.unloadBundle('level1');

Или конкретного ресурса:

Assets.unload('enemy');

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


Кэширование и повторное использование

Загруженные ресурсы автоматически сохраняются в кэше. Повторный вызов:

await Assets.load('button');

не инициирует новый HTTP-запрос.

Внутренне используется карта ресурсов, сопоставляющая alias с загруженным объектом (Texture, SpriteSheet, AudioBuffer и т.д.).


Асинхронная модель загрузки

Все операции возвращают Promise. Это позволяет:

  • использовать async/await,
  • управлять параллельной загрузкой,
  • реализовывать прогресс-бары,
  • обрабатывать ошибки централизованно.

Пример параллельной загрузки:

await Promise.all([
  Assets.loadBundle('ui'),
  Assets.loadBundle('audio')
]);

Интеграция с системой сборки

В продакшн-проектах манифест часто генерируется автоматически:

  • через Webpack asset modules,
  • через Vite plugins,
  • через кастомные Node.js-скрипты.

Типичный процесс:

  1. Сканирование директории.
  2. Формирование JSON.
  3. Минификация.
  4. Подключение в приложение.

Такой подход исключает ручные ошибки в путях.


Разделение манифеста на файлы

В больших играх манифест разбивается:

  • core-manifest.json
  • levels-manifest.json
  • ui-manifest.json

Загрузка может происходить каскадно:

const levelManifest = await fetch('levels-manifest.json').then(r => r.json());
await Assets.init({ manifest: levelManifest });

Это уменьшает объём стартового JS-бандла.


Обработка ошибок

При отсутствии ресурса или ошибке сети Assets.load() генерирует исключение.

Пример обработки:

try {
  await Assets.load('missingTexture');
} catch (error) {
  console.error('Ошибка загрузки:', error);
}

Для критических ресурсов целесообразно предусматривать fallback-логику.


Организация alias: архитектурные рекомендации

Alias должен быть:

  • уникальным,
  • кратким,
  • логически структурированным.

Часто применяется нейминг:

ui.button.primary
ui.button.secondary
level1.enemy.goblin
level1.enemy.boss

Это облегчает масштабирование проекта.


Связь манифеста с архитектурой приложения

Манифест становится частью слоя инфраструктуры и влияет на:

  • систему сцен,
  • менеджер уровней,
  • управление памятью,
  • стратегию ленивой загрузки,
  • оптимизацию производительности.

Правильно спроектированная структура bundles позволяет:

  • загружать только необходимые ресурсы,
  • минимизировать время первого рендера,
  • контролировать потребление GPU-памяти,
  • упрощать поддержку проекта.

Взаимодействие с текстурным кэшем

После загрузки изображений через манифест они автоматически регистрируются в текстурном кэше PixiJS. Это обеспечивает совместимость со спрайтами:

const sprite = Sprite.from('button');

Если alias присутствует в кэше, текстура извлекается без дополнительной загрузки.


Эволюция системы загрузки

Ранее в PixiJS использовался PIXI.Loader, требующий императивного описания загрузки:

loader.add('button', 'button.png');

Современная система Assets и манифестный подход:

  • декларативны,
  • масштабируемы,
  • лучше интегрируются с ES-модулями,
  • поддерживают tree-shaking,
  • удобнее для крупных приложений.

Практическая модель манифеста для игры

Пример структурированной архитектуры:

const manifest = {
  bundles: [
    {
      name: 'core',
      assets: {
        logo: 'assets/core/logo.png',
        fontMain: 'assets/core/font.fnt'
      }
    },
    {
      name: 'ui',
      assets: {
        buttonPrimary: 'assets/ui/button-primary.png',
        window: 'assets/ui/window.png'
      }
    },
    {
      name: 'level1',
      assets: [
        { alias: 'bg1', src: 'assets/levels/1/bg.jpg' },
        { alias: 'enemy1', src: 'assets/levels/1/enemy.png' }
      ]
    }
  ]
};

Такая структура обеспечивает:

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

Манифест ресурсов в PixiJS является фундаментальным элементом архитектуры современного графического приложения. Его грамотное проектирование напрямую влияет на производительность, управляемость кода и стабильность работы приложения.