visit
Pixi’s Asset Pack has officially reached , and after diving deep into it, I can confidently say that it shows a lot of promise for our projects. However, there are still some issues that need ironing out. In this post, I’ll walk you through how it works, the benefits it offers, and a few limitations we’ve encountered.
npm install --save-dev @assetpack/core
Next, create an .assetpack.js
file with the following content:
import { pixiPipes } from '@assetpack/core/pixi';
export default {
entry: './raw-assets',
output: './public/assets',
pipes: [
...pixiPipes({
resolutions: { high: 3, default: 2, low: 1 },
manifest: {
trimExtensions: true
},
texturePacker: { texturePacker: { removeFileExtension: true }},
}),
],
};
The pixiPipes
function creates a default configuration that works in most cases. Here's a breakdown of what my preferred settings do:
resolutions
: Specifies three resolutions (high, default, low). I will explain more about this later.manifest:trimExtensions
: Removes texture file extensions in the manifest for easier reference in your code.texturePacker:texturePacker:removeFileExtension
: Removes texture file extensions in the spritesheet Json when packing textures, again for easier reference.Next, create a folder called raw-assets
in your project root. Each folder inside raw-assets
will represent a bundle, and you need to specify it with a {m}
tag. For our project, I created the following bundles:
game-screen{m}
: Contains all game assets and starts loading after the loading screen is shown.load-screen{m}
: Assets used in the loading screen. These are unloaded once the screen is hidden to save memory.shared{m}
: Assets used by both the loading screen and the game.ui{m}
: UI assets, separated for easier management (though they can be put in the game-screen folder).Based on asset type, structure the folders like this:
background
. If there are two files with the same name, reference them with the relative path.
{tps}
tag. Spritesheet Json files will be generated, and you can access the texture array by folder name, e.g., skins
.
character.json
and character.atlas
.Finally, run the CLI command:
npm assetpack
This packs everything into the public/assets
folder and generates a manifest.json
containing all file references. You can also set up a GitHub workflow to automate this process.
import { type AssetsManifest, Assets } from '@pixi/assets';
import type { Spritesheet } from '@pixi/spritesheet';
import * as utils from '@pixi/utils';
import { Sprite } from '@pixi/sprite';
import { Spine } from '@esotericsoftware/spine-pixi';
(async () => {
const baseUrl = './public/assets';
// const baseUrl = '//s3/my-bucket';
const response = await fetch(baseUrl + '/manifest.json');
const manifest = (await response.json()) as AssetsManifest;
if (!manifest.bundles) {
throw new Error('[Assets] Invalid assets manifest');
}
const resolution = Math.min(utils.isMobile.any ? window.devicePixelRatio : 3, 3);
await Assets.init({
basePath: baseUrl,
manifest,
texturePreference: { resolution: [resolution, 1], format: ['webp', 'png'] },
});
await Assets.loadBundle('shared');
await Assets.loadBundle('load-screen');
// load-screen assets loaded, show load screen
await Assets.loadBundle('ui');
await Assets.loadBundle('game-screen', onProgress); // onProgress to feed the progress bar
// game assets loaded, wait for player to hide load screen
Assets.unloadBundle('load-screen');
const singleSprite = Sprite.from('background');
const spritesheet = Assets.cache.get<Spritesheet>('skins');
const spritesheetSprite = new Sprite(spritesheet.textures['hat']);
const spine = Spine.from('character-skel', 'character');
})();
This code loads assets using the manifest and adjusts resolution preferences based on device pixel density. Here are the key steps:
baseUrl
as a local or server folder path.devicePixelRatio
.Assets.loadBundle()
to load asset bundles defined in the manifest.Assets.unloadBundle()
.Sprite.from()
for single sprites, Assets.cache.get()
and new Sprite()
for spritesheets, and Spine.from()
for Spine animations.