paint-brush
Pixi's Asset Pack 1.0: Is the New Version A Step Forward for Asset Management?by@fur

Pixi's Asset Pack 1.0: Is the New Version A Step Forward for Asset Management?

by Richard FSeptember 23rd, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Pixi's Asset Pack simplifies game asset management by automating texture packing, compression, and mipmaps. It also supports bundle manifest generation and efficient loading. Some issues still exist, like Spine atlas and bitmap font export problems, but it's a promising tool for streamlining development workflows.
featured image - Pixi's Asset Pack 1.0: Is the New Version A Step Forward for Asset Management?
Richard F HackerNoon profile picture

Pixi’s Asset Pack has officially reached version 1.0, 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.

Why Use Pixi's Asset Pack?

Here are some key features that make Asset Pack a valuable addition to your development toolkit:

Current Issues

While Asset Pack is promising, there are a few issues we’ve encountered:

  • Spine Atlas Export: Spine atlas is not correctly exported (submitted a PR for spine-runtime).
  • Bitmap Font Export: Bitmap fonts aren't exporting properly (submitted an issue).
  • Sound Sprite Support: Currently unsupported (submitted an issue).

How to Set Up Asset Pack

Setting up Asset Pack is straightforward. Begin by installing it with this commend:

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:

  • Single Sprite: Place textures in any file path. Reference them by filename (without extension), e.g., background. If there are two files with the same name, reference them with the relative path.

  • Spritesheet (Texture Packer): Put textures in a folder with a {tps} tag. Spritesheet Json files will be generated, and you can access the texture array by folder name, e.g., skins.

  • Spine: Place the Atlas, Json, and texture files in a folder. Access the spine data and atlas with their filenames (without extension). If your Atlas and Json share the same filename, you’ll need to use extensions, e.g., 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.

How to Use Packed Assets

Now, let’s look at the code to load the packed assets:

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 = 'https://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:

  • Files Location: Set baseUrl as a local or server folder path.
  • Resolution Handling: Set the preferred resolution (3x, 2x, 1x) based on devicePixelRatio.
  • Asset Loading: Use Assets.loadBundle() to load asset bundles defined in the manifest.
  • Unload Bundles: Once the loading screen is no longer needed, unload its assets with Assets.unloadBundle().
  • Accessing Assets: Use Sprite.from() for single sprites, Assets.cache.get() and new Sprite() for spritesheets, and Spine.from() for Spine animations.

Conclusion

While Pixi's Asset Pack is still evolving, it offers a solid foundation for managing assets efficiently in Pixi-based projects. I believe it has the potential to become an essential tool for many developers. Has anyone else worked with it? I’d love to hear your thoughts and experiences!