UNPKG

pixi.js

Version:

<p align="center"> <a href="https://pixijs.com" target="_blank" rel="noopener noreferrer"> <img height="150" src="https://files.pixijs.download/branding/pixijs-logo-transparent-dark.svg?v=1" alt="PixiJS logo"> </a> </p> <br/> <p align="center">

1 lines 61.1 kB
{"version":3,"file":"Assets.mjs","sources":["../../src/assets/Assets.ts"],"sourcesContent":["/* eslint-disable max-len */\nimport { extensions, ExtensionType } from '../extensions/Extensions';\nimport { bitmapFontCachePlugin, loadBitmapFont } from '../scene/text-bitmap/asset/loadBitmapFont';\nimport { warn } from '../utils/logging/warn';\nimport { BackgroundLoader } from './BackgroundLoader';\nimport { Cache } from './cache/Cache';\nimport { cacheTextureArray } from './cache/parsers/cacheTextureArray';\nimport { detectAvif } from './detections/parsers/detectAvif';\nimport { detectDefaults } from './detections/parsers/detectDefaults';\nimport { detectMp4 } from './detections/parsers/detectMp4';\nimport { detectOgv } from './detections/parsers/detectOgv';\nimport { detectWebm } from './detections/parsers/detectWebm';\nimport { detectWebp } from './detections/parsers/detectWebp';\nimport { Loader } from './loader/Loader';\nimport { loadJson } from './loader/parsers/loadJson';\nimport { loadTxt } from './loader/parsers/loadTxt';\nimport { loadWebFont } from './loader/parsers/loadWebFont';\nimport { loadSvg } from './loader/parsers/textures/loadSVG';\nimport { type LoadTextureConfig, loadTextures } from './loader/parsers/textures/loadTextures';\nimport { loadVideoTextures } from './loader/parsers/textures/loadVideoTextures';\nimport { resolveJsonUrl } from './resolver/parsers/resolveJsonUrl';\nimport { resolveTextureUrl } from './resolver/parsers/resolveTextureUrl';\nimport { Resolver } from './resolver/Resolver';\nimport { convertToList } from './utils/convertToList';\nimport { isSingleItem } from './utils/isSingleItem';\n\nimport type { AssetExtension } from './AssetExtension';\nimport type { FormatDetectionParser } from './detections/types';\nimport type { LoadSVGConfig } from './loader/parsers/textures/loadSVG';\nimport type { BundleIdentifierOptions } from './resolver/Resolver';\nimport type { ArrayOr, AssetsBundle, AssetsManifest, ResolvedAsset, UnresolvedAsset } from './types';\n\n/**\n * Callback function for tracking asset loading progress. The function is called repeatedly\n * during the loading process with a progress value between 0.0 and 1.0.\n * @param progress - The loading progress from 0.0 (started) to 1.0 (complete)\n * @returns void\n * @example\n * ```ts\n * // Basic progress logging\n * const onProgress = (progress: number) => {\n * console.log(`Loading: ${Math.round(progress * 100)}%`);\n * };\n *\n * // Update loading bar\n * const onProgress = (progress: number) => {\n * loadingBar.width = progress * 100;\n * loadingText.text = `${Math.round(progress * 100)}%`;\n * };\n *\n * // Load assets with progress tracking\n * await Assets.load(['sprite1.png', 'sprite2.png'], onProgress);\n *\n * // Load bundle with progress tracking\n * await Assets.loadBundle('levelAssets', (progress) => {\n * // Progress is normalized (0.0 - 1.0)\n * updateLoadingScreen(progress);\n * });\n * ```\n * > [!IMPORTANT] Do not rely on the progress callback to determine when all assets are loaded.\n * > Use the returned promise from `Assets.load()` or `Assets.loadBundle()` to know when loading is complete.\n * @category assets\n * @standard\n */\nexport type ProgressCallback = (progress: number) => void;\n\n/**\n * Extensible preferences that can be used, for instance, when configuring loaders.\n * @since 7.2.0\n * @advanced\n * @category assets\n */\nexport interface AssetsPreferences extends LoadTextureConfig, LoadSVGConfig, PixiMixins.AssetsPreferences {}\n\n/**\n * Options for initializing the Assets class. These options configure how assets are loaded,\n * resolved, and managed in your PixiJS application.\n * @category assets\n * @standard\n */\nexport interface AssetInitOptions\n{\n /**\n * Base path prepended to all asset URLs. Useful for CDN hosting.\n * @example\n * ```ts\n * await Assets.init({\n * basePath: 'https://my-cdn.com/assets/'\n * });\n *\n * // Now you can load assets like this:\n * // Will load from: https://my-cdn.com/assets/images/sprite.png\n * const texture = await Assets.load('images/sprite.png');\n * ```\n */\n basePath?: string;\n\n /**\n * URL parameters to append to all asset URLs.\n * Useful for cache-busting or version control.\n * @example\n * ```ts\n * // As a string\n * await Assets.init({\n * defaultSearchParams: 'version=1.0.0'\n * });\n *\n * // As an object\n * await Assets.init({\n * defaultSearchParams: {\n * version: '1.0.0',\n * t: Date.now()\n * }\n * });\n * ```\n * @advanced\n */\n defaultSearchParams?: string | Record<string, any>;\n\n /**\n * A manifest defining all your application's assets.\n * Can be a URL to a JSON file or a manifest object.\n * @example\n * ```ts\n * // Using a manifest object\n * await Assets.init({\n * manifest: {\n * bundles: [{\n * name: 'game-screen',\n * assets: [\n * {\n * alias: 'hero',\n * src: 'hero.{png,webp}'\n * },\n * {\n * alias: 'map',\n * src: 'map.json'\n * }\n * ]\n * }]\n * }\n * });\n *\n * // Using a URL to manifest\n * await Assets.init({\n * manifest: 'assets/manifest.json'\n * });\n *\n * // loading a bundle from the manifest\n * await Assets.loadBundle('game-screen');\n *\n * // load individual assets from the manifest\n * const heroTexture = await Assets.load('hero');\n * ```\n */\n manifest?: string | AssetsManifest;\n /**\n * Configure texture loading preferences.\n * Useful for optimizing asset delivery based on device capabilities.\n * @example\n * ```ts\n * await Assets.init({\n * texturePreference: {\n * // Prefer high-res textures on retina displays\n * resolution: window.devicePixelRatio,\n *\n * // Prefer modern formats, fallback to traditional\n * format: ['avif', 'webp', 'png']\n * }\n * });\n * ```\n */\n texturePreference?: {\n /** Preferred texture resolution(s). Can be a single number or array of resolutions in order of preference. */\n resolution?: number | number[];\n\n /** Preferred texture formats in order of preference. Default: ['avif', 'webp', 'png', 'jpg', 'jpeg'] */\n format?: ArrayOr<string>;\n };\n\n /**\n * Skip browser format detection for faster initialization.\n * Only use if you know exactly what formats your target browsers support.\n * @example\n * ```ts\n * await Assets.init({\n * skipDetections: true,\n * texturePreference: {\n * format: ['webp', 'png'] // Must explicitly set formats\n * }\n * });\n * ```\n * @advanced\n */\n skipDetections?: boolean;\n\n /**\n * Override how bundle IDs are generated and resolved.\n *\n * This allows you to customize how assets are grouped and accessed via bundles and allow for\n * multiple bundles to share the same asset keys.\n * @advanced\n * @example\n * ```ts\n * const manifest = {\n * bundles: [\n * {\n * name: 'bunny1',\n * assets: [\n * {\n * alias: ['character', 'character2'],\n * src: 'textures/bunny.png',\n * },\n * ],\n * },\n * {\n * name: 'bunny2',\n * assets: [\n * {\n * alias: ['character', 'character2'],\n * src: 'textures/bunny-2.png',\n * },\n * ],\n * },\n * ]\n * };\n *\n * const bundleIdentifier: BundleIdentifierOptions = {\n * connector: ':',\n * };\n *\n * await Assets.init({ manifest, basePath, bundleIdentifier });\n *\n * const resources = await Assets.loadBundle('bunny1');\n * const resources2 = await Assets.loadBundle('bunny2');\n *\n * console.log(resources.character === resources2.character); // false\n * ```\n */\n bundleIdentifier?: BundleIdentifierOptions;\n\n /**\n * Optional preferences for asset loading behavior.\n * @example\n * ```ts\n * await Assets.init({\n * preferences: {\n * crossOrigin: 'anonymous',\n * parseAsGraphicsContext: false\n * }\n * });\n * ```\n */\n preferences?: Partial<AssetsPreferences>;\n}\n\n/** @internal */\nexport class AssetsClass\n{\n /**\n * The URL resolver for assets. Maps various asset keys and URLs to their final loadable form.\n * @advanced\n */\n public resolver: Resolver;\n /**\n * The loader responsible for loading all assets. Handles different file types\n * and transformations.\n * @advanced\n */\n public loader: Loader;\n /**\n * The global cache for all loaded assets. Manages storage and retrieval of\n * processed assets.\n * @example\n * ```ts\n * // Check if an asset is cached\n * if (Assets.cache.has('myTexture')) {\n * const texture = Assets.cache.get('myTexture');\n * }\n * ```\n * @see {@link Cache} For detailed cache documentation\n */\n public cache: typeof Cache;\n\n /** takes care of loading assets in the background */\n private readonly _backgroundLoader: BackgroundLoader;\n\n private readonly _detections: FormatDetectionParser[] = [];\n\n private _initialized = false;\n\n constructor()\n {\n this.resolver = new Resolver();\n this.loader = new Loader();\n this.cache = Cache;\n\n this._backgroundLoader = new BackgroundLoader(this.loader);\n this._backgroundLoader.active = true;\n\n this.reset();\n }\n\n /**\n * Initializes the Assets class with configuration options. While not required,\n * calling this before loading assets is recommended to set up default behaviors.\n * @param options - Configuration options for the Assets system\n * @example\n * ```ts\n * // Basic initialization (optional as Assets.load will call this automatically)\n * await Assets.init();\n *\n * // With CDN configuration\n * await Assets.init({\n * basePath: 'https://my-cdn.com/assets/',\n * defaultSearchParams: { version: '1.0.0' }\n * });\n *\n * // With manifest and preferences\n * await Assets.init({\n * manifest: {\n * bundles: [{\n * name: 'game-screen',\n * assets: [\n * {\n * alias: 'hero',\n * src: 'hero.{png,webp}',\n * data: { scaleMode: SCALE_MODES.NEAREST }\n * },\n * {\n * alias: 'map',\n * src: 'map.json'\n * }\n * ]\n * }]\n * },\n * // Optimize for device capabilities\n * texturePreference: {\n * resolution: window.devicePixelRatio,\n * format: ['webp', 'png']\n * },\n * // Set global preferences\n * preferences: {\n * crossOrigin: 'anonymous',\n * }\n * });\n *\n * // Load assets after initialization\n * const heroTexture = await Assets.load('hero');\n * ```\n * @remarks\n * - Can be called only once; subsequent calls will be ignored with a warning\n * - Format detection runs automatically unless `skipDetections` is true\n * - The manifest can be a URL to a JSON file or an inline object\n * @see {@link AssetInitOptions} For all available initialization options\n * @see {@link AssetsManifest} For manifest format details\n */\n public async init(options: AssetInitOptions = {}): Promise<void>\n {\n if (this._initialized)\n {\n // #if _DEBUG\n warn('[Assets]AssetManager already initialized, did you load before calling this Assets.init()?');\n // #endif\n\n return;\n }\n\n this._initialized = true;\n\n if (options.defaultSearchParams)\n {\n this.resolver.setDefaultSearchParams(options.defaultSearchParams);\n }\n\n if (options.basePath)\n {\n this.resolver.basePath = options.basePath;\n }\n\n if (options.bundleIdentifier)\n {\n this.resolver.setBundleIdentifier(options.bundleIdentifier);\n }\n\n if (options.manifest)\n {\n let manifest = options.manifest;\n\n if (typeof manifest === 'string')\n {\n manifest = await this.load<AssetsManifest>(manifest);\n }\n\n this.resolver.addManifest(manifest);\n }\n\n const resolutionPref = options.texturePreference?.resolution ?? 1;\n const resolution = (typeof resolutionPref === 'number') ? [resolutionPref] : resolutionPref;\n\n const formats = await this._detectFormats({\n preferredFormats: options.texturePreference?.format,\n skipDetections: options.skipDetections,\n detections: this._detections\n });\n\n this.resolver.prefer({\n params: {\n format: formats,\n resolution,\n },\n });\n\n if (options.preferences)\n {\n this.setPreferences(options.preferences);\n }\n }\n\n /**\n * Registers assets with the Assets resolver. This method maps keys (aliases) to asset sources,\n * allowing you to load assets using friendly names instead of direct URLs.\n * @param assets - The unresolved assets to add to the resolver\n * @example\n * ```ts\n * // Basic usage - single asset\n * Assets.add({\n * alias: 'myTexture',\n * src: 'assets/texture.png'\n * });\n * const texture = await Assets.load('myTexture');\n *\n * // Multiple aliases for the same asset\n * Assets.add({\n * alias: ['hero', 'player'],\n * src: 'hero.png'\n * });\n * const hero1 = await Assets.load('hero');\n * const hero2 = await Assets.load('player'); // Same texture\n *\n * // Multiple format support\n * Assets.add({\n * alias: 'character',\n * src: 'character.{webp,png}' // Will choose best format\n * });\n * Assets.add({\n * alias: 'character',\n * src: ['character.webp', 'character.png'], // Explicitly specify formats\n * });\n *\n * // With texture options\n * Assets.add({\n * alias: 'sprite',\n * src: 'sprite.png',\n * data: { scaleMode: 'nearest' }\n * });\n *\n * // Multiple assets at once\n * Assets.add([\n * { alias: 'bg', src: 'background.png' },\n * { alias: 'music', src: 'music.mp3' },\n * { alias: 'spritesheet', src: 'sheet.json', data: { ignoreMultiPack: false } }\n * ]);\n * ```\n * @remarks\n * - Assets are resolved when loaded, not when added\n * - Multiple formats use the best available format for the browser\n * - Adding with same alias overwrites previous definition\n * - The `data` property is passed to the asset loader\n * @see {@link Resolver} For details on asset resolution\n * @see {@link LoaderParser} For asset-specific data options\n * @advanced\n */\n public add(assets: (ArrayOr<UnresolvedAsset>)): void\n {\n this.resolver.add(assets);\n }\n\n /**\n * Loads one or more assets and returns a promise that resolves with the loaded content.\n * Assets are cached, so subsequent loads will return the same instance of the asset without re-fetching.\n * @param urls - Single URL/alias or array of URLs/aliases to load\n * @param onProgress - Optional callback for load progress (0.0 to 1.0)\n * @returns Promise that resolves with loaded asset(s)\n * @example\n * ```ts\n * // Load a single asset\n * const texture = await Assets.load('images/sprite.png');\n *\n * // Load using an alias\n * const heroTexture = await Assets.load({ alias: 'hero', src: 'images/hero.png' });\n *\n * // Load multiple assets\n * const assets = await Assets.load([\n * 'images/background.png',\n * 'images/character.png',\n * 'fonts/game.fnt'\n * ]);\n * console.log(assets['images/background.png']); // Access by URL\n *\n * // Load with progress tracking\n * const textures = await Assets.load(['sprite1.png', 'sprite2.png'],\n * (progress) => console.log(`Loading: ${Math.round(progress * 100)}%`)\n * );\n *\n * // Load with format preference\n * const characterTexture = await Assets.load({\n * alias: 'character',\n * src: 'character.{webp,png}' // Will choose best format\n * });\n *\n * // Load with custom options\n * const spriteTexture = await Assets.load({\n * alias: 'sprite',\n * src: 'sprite.png',\n * data: {\n * scaleMode: SCALE_MODES.NEAREST,\n * mipmap: MIPMAP_MODES.ON\n * }\n * });\n *\n * // Load with a specific loader, can be useful if your asset does not have an extension\n * const image = await Assets.load({\n * alias: 'imageWithoutExtension',\n * src: 'images/imageWithoutExtension',\n * loadParser: 'loadTextures' // Use the JSON loader\n * });\n * ```\n * @remarks\n * - Assets are cached automatically to prevent duplicate loading\n * - URLs are resolved to the best format for the current browser\n * - Asset types are detected automatically based on file extension\n * - Progress callback receives values from 0.0 to 1.0\n * - You can define with loader to use for an asset by specifying the `loadParser` property, which is useful for assets that do not have a file extension.\n * @throws {Error} If the asset cannot be loaded or parsed\n * @see {@link Assets.add} For registering assets with aliases\n * @see {@link Assets.backgroundLoad} For loading assets in the background\n * @see {@link Assets.unload} For releasing loaded assets\n */\n public async load<T = any>(\n urls: string | UnresolvedAsset,\n onProgress?: ProgressCallback,\n ): Promise<T>;\n public async load<T = any>(\n urls: string[] | UnresolvedAsset[],\n onProgress?: ProgressCallback,\n ): Promise<Record<string, T>>;\n public async load<T = any>(\n urls: ArrayOr<string> | ArrayOr<UnresolvedAsset>,\n onProgress?: ProgressCallback\n ): Promise<T | Record<string, T>>\n {\n if (!this._initialized)\n {\n await this.init();\n }\n\n const singleAsset = isSingleItem(urls);\n\n const urlArray: string[] = convertToList<UnresolvedAsset | string>(urls)\n .map((url) =>\n {\n if (typeof url !== 'string')\n {\n const aliases = this.resolver.getAlias(url);\n\n if (aliases.some((alias) => !this.resolver.hasKey(alias)))\n {\n this.add(url);\n }\n\n return Array.isArray(aliases) ? aliases[0] : aliases;\n }\n\n // if it hasn't been added, add it now\n if (!this.resolver.hasKey(url)) this.add({ alias: url, src: url });\n\n return url;\n }) as string[];\n\n // check cache first...\n const resolveResults = this.resolver.resolve(urlArray);\n\n // remap to the keys used..\n const out: Record<string, T> = await this._mapLoadToResolve<T>(resolveResults, onProgress);\n\n return singleAsset ? out[urlArray[0] as string] : out;\n }\n\n /**\n * Registers a bundle of assets that can be loaded as a group. Bundles are useful for organizing\n * assets into logical groups, such as game levels or UI screens.\n * @param bundleId - Unique identifier for the bundle\n * @param assets - Assets to include in the bundle\n * @example\n * ```ts\n * // Add a bundle using array format\n * Assets.addBundle('animals', [\n * { alias: 'bunny', src: 'bunny.png' },\n * { alias: 'chicken', src: 'chicken.png' },\n * { alias: 'thumper', src: 'thumper.png' },\n * ]);\n *\n * // Add a bundle using object format\n * Assets.addBundle('animals', {\n * bunny: 'bunny.png',\n * chicken: 'chicken.png',\n * thumper: 'thumper.png',\n * });\n *\n * // Add a bundle with advanced options\n * Assets.addBundle('ui', [\n * {\n * alias: 'button',\n * src: 'button.{webp,png}',\n * data: { scaleMode: 'nearest' }\n * },\n * {\n * alias: ['logo', 'brand'], // Multiple aliases\n * src: 'logo.svg',\n * data: { resolution: 2 }\n * }\n * ]);\n *\n * // Load the bundle\n * await Assets.loadBundle('animals');\n *\n * // Use the loaded assets\n * const bunny = Sprite.from('bunny');\n * const chicken = Sprite.from('chicken');\n * ```\n * @remarks\n * - Bundle IDs must be unique\n * - Assets in bundles are not loaded until `loadBundle` is called\n * - Bundles can be background loaded using `backgroundLoadBundle`\n * - Assets in bundles can be loaded individually using their aliases\n * @see {@link Assets.loadBundle} For loading bundles\n * @see {@link Assets.backgroundLoadBundle} For background loading bundles\n * @see {@link Assets.unloadBundle} For unloading bundles\n * @see {@link AssetsManifest} For manifest format details\n */\n public addBundle(bundleId: string, assets: AssetsBundle['assets']): void\n {\n this.resolver.addBundle(bundleId, assets);\n }\n\n /**\n * Loads a bundle or multiple bundles of assets. Bundles are collections of related assets\n * that can be loaded together.\n * @param bundleIds - Single bundle ID or array of bundle IDs to load\n * @param onProgress - Optional callback for load progress (0.0 to 1.0)\n * @returns Promise that resolves with the loaded bundle assets\n * @example\n * ```ts\n * // Define bundles in your manifest\n * const manifest = {\n * bundles: [\n * {\n * name: 'load-screen',\n * assets: [\n * {\n * alias: 'background',\n * src: 'sunset.png',\n * },\n * {\n * alias: 'bar',\n * src: 'load-bar.{png,webp}', // use an array of individual assets\n * },\n * ],\n * },\n * {\n * name: 'game-screen',\n * assets: [\n * {\n * alias: 'character',\n * src: 'robot.png',\n * },\n * {\n * alias: 'enemy',\n * src: 'bad-guy.png',\n * },\n * ],\n * },\n * ]\n * };\n *\n * // Initialize with manifest\n * await Assets.init({ manifest });\n *\n * // Or add bundles programmatically\n * Assets.addBundle('load-screen', [...]);\n * Assets.loadBundle('load-screen');\n *\n * // Load a single bundle\n * await Assets.loadBundle('load-screen');\n * const bg = Sprite.from('background'); // Uses alias from bundle\n *\n * // Load multiple bundles\n * await Assets.loadBundle([\n * 'load-screen',\n * 'game-screen'\n * ]);\n *\n * // Load with progress tracking\n * await Assets.loadBundle('game-screen', (progress) => {\n * console.log(`Loading: ${Math.round(progress * 100)}%`);\n * });\n * ```\n * @remarks\n * - Bundle assets are cached automatically\n * - Bundles can be pre-loaded using `backgroundLoadBundle`\n * - Assets in bundles can be accessed by their aliases\n * - Progress callback receives values from 0.0 to 1.0\n * @throws {Error} If the bundle ID doesn't exist in the manifest\n * @see {@link Assets.addBundle} For adding bundles programmatically\n * @see {@link Assets.backgroundLoadBundle} For background loading bundles\n * @see {@link Assets.unloadBundle} For unloading bundles\n * @see {@link AssetsManifest} For manifest format details\n */\n public async loadBundle(bundleIds: ArrayOr<string>, onProgress?: ProgressCallback): Promise<any>\n {\n if (!this._initialized)\n {\n await this.init();\n }\n\n let singleAsset = false;\n\n if (typeof bundleIds === 'string')\n {\n singleAsset = true;\n bundleIds = [bundleIds];\n }\n\n const resolveResults = this.resolver.resolveBundle(bundleIds);\n\n const out: Record<string, Record<string, any>> = {};\n\n const keys = Object.keys(resolveResults);\n let count = 0;\n let total = 0;\n const _onProgress = () =>\n {\n onProgress?.(++count / total);\n };\n const promises = keys.map((bundleId) =>\n {\n const resolveResult = resolveResults[bundleId];\n\n total += Object.keys(resolveResult).length;\n\n return this._mapLoadToResolve(resolveResult, _onProgress)\n .then((resolveResult) =>\n {\n out[bundleId] = resolveResult;\n });\n });\n\n await Promise.all(promises);\n\n return singleAsset ? out[bundleIds[0]] : out;\n }\n\n /**\n * Initiates background loading of assets. This allows assets to be loaded passively while other operations\n * continue, making them instantly available when needed later.\n *\n * Background loading is useful for:\n * - Preloading game levels while in a menu\n * - Loading non-critical assets during gameplay\n * - Reducing visible loading screens\n * @param urls - Single URL/alias or array of URLs/aliases to load in the background\n * @example\n * ```ts\n * // Basic background loading\n * Assets.backgroundLoad('images/level2-assets.png');\n *\n * // Background load multiple assets\n * Assets.backgroundLoad([\n * 'images/sprite1.png',\n * 'images/sprite2.png',\n * 'images/background.png'\n * ]);\n *\n * // Later, when you need the assets\n * const textures = await Assets.load([\n * 'images/sprite1.png',\n * 'images/sprite2.png'\n * ]); // Resolves immediately if background loading completed\n * ```\n * @remarks\n * - Background loading happens one asset at a time to avoid blocking the main thread\n * - Loading can be interrupted safely by calling `Assets.load()`\n * - Assets are cached as they complete loading\n * - No progress tracking is available for background loading\n */\n public async backgroundLoad(urls: ArrayOr<string>): Promise<void>\n {\n if (!this._initialized)\n {\n await this.init();\n }\n\n if (typeof urls === 'string')\n {\n urls = [urls];\n }\n\n const resolveResults = this.resolver.resolve(urls);\n\n this._backgroundLoader.add(Object.values(resolveResults));\n }\n\n /**\n * Initiates background loading of asset bundles. Similar to backgroundLoad but works with\n * predefined bundles of assets.\n *\n * Perfect for:\n * - Preloading level bundles during gameplay\n * - Loading UI assets during splash screens\n * - Preparing assets for upcoming game states\n * @param bundleIds - Single bundle ID or array of bundle IDs to load in the background\n * @example\n * ```ts\n * // Define bundles in your manifest\n * await Assets.init({\n * manifest: {\n * bundles: [\n * {\n * name: 'home',\n * assets: [\n * {\n * alias: 'background',\n * src: 'images/home-bg.png',\n * },\n * {\n * alias: 'logo',\n * src: 'images/logo.png',\n * }\n * ]\n * },\n * {\n * name: 'level-1',\n * assets: [\n * {\n * alias: 'background',\n * src: 'images/level1/bg.png',\n * },\n * {\n * alias: 'sprites',\n * src: 'images/level1/sprites.json'\n * }\n * ]\n * }]\n * }\n * });\n *\n * // Load the home screen assets right away\n * await Assets.loadBundle('home');\n * showHomeScreen();\n *\n * // Start background loading while showing home screen\n * Assets.backgroundLoadBundle('level-1');\n *\n * // When player starts level, load completes faster\n * await Assets.loadBundle('level-1');\n * hideHomeScreen();\n * startLevel();\n * ```\n * @remarks\n * - Bundle assets are loaded one at a time\n * - Loading can be interrupted safely by calling `Assets.loadBundle()`\n * - Assets are cached as they complete loading\n * - Requires bundles to be registered via manifest or `addBundle`\n * @see {@link Assets.addBundle} For adding bundles programmatically\n * @see {@link Assets.loadBundle} For immediate bundle loading\n * @see {@link AssetsManifest} For manifest format details\n */\n public async backgroundLoadBundle(bundleIds: ArrayOr<string>): Promise<void>\n {\n if (!this._initialized)\n {\n await this.init();\n }\n\n if (typeof bundleIds === 'string')\n {\n bundleIds = [bundleIds];\n }\n\n const resolveResults = this.resolver.resolveBundle(bundleIds);\n\n Object.values(resolveResults).forEach((resolveResult) =>\n {\n this._backgroundLoader.add(Object.values(resolveResult));\n });\n }\n\n /**\n * Only intended for development purposes.\n * This will wipe the resolver and caches.\n * You will need to reinitialize the Asset\n * @internal\n */\n public reset(): void\n {\n this.resolver.reset();\n this.loader.reset();\n this.cache.reset();\n\n this._initialized = false;\n }\n\n /**\n * Instantly gets an asset already loaded from the cache. Returns undefined if the asset hasn't been loaded yet.\n * @param keys - The key or keys for the assets to retrieve\n * @returns The cached asset(s) or undefined if not loaded\n * @example\n * ```ts\n * // Get a single cached asset\n * const texture = Assets.get('hero');\n * if (texture) {\n * const sprite = new Sprite(texture);\n * }\n *\n * // Get multiple cached assets\n * const textures = Assets.get([\n * 'hero',\n * 'background',\n * 'enemy'\n * ]);\n *\n * // Safe pattern with loading fallback\n * let texture = Assets.get('hero');\n * if (!texture) {\n * texture = await Assets.load('hero');\n * }\n *\n * // Working with bundles\n * await Assets.loadBundle('game-ui');\n * const uiAssets = Assets.get([\n * 'button',\n * 'panel',\n * 'icons'\n * ]);\n * ```\n * @remarks\n * - Returns undefined if asset isn't loaded\n * - No automatic loading - use `Assets.load()` for that\n * - Cached assets are shared instances\n * - Faster than `load()` for already cached assets\n *\n * > [!TIP]\n * > When in doubt, use `Assets.load()` instead. It will return cached\n * > assets instantly if they're already loaded.\n * @see {@link Assets.load} For loading assets that aren't cached\n * @see {@link Assets.cache} For direct cache access\n */\n public get<T = any>(keys: string): T;\n public get<T = any>(keys: string[]): Record<string, T>;\n public get<T = any>(keys: ArrayOr<string>): T | Record<string, T>\n {\n if (typeof keys === 'string')\n {\n return Cache.get(keys);\n }\n\n const assets: Record<string, T> = {};\n\n for (let i = 0; i < keys.length; i++)\n {\n assets[i] = Cache.get(keys[i]);\n }\n\n return assets;\n }\n\n /**\n * helper function to map resolved assets back to loaded assets\n * @param resolveResults - the resolve results from the resolver\n * @param onProgress - the progress callback\n */\n private async _mapLoadToResolve<T>(\n resolveResults: ResolvedAsset | Record<string, ResolvedAsset>,\n onProgress?: ProgressCallback\n ): Promise<Record<string, T>>\n {\n const resolveArray = [...new Set(Object.values(resolveResults))] as ResolvedAsset[];\n\n // pause background loader...\n this._backgroundLoader.active = false;\n\n const loadedAssets = await this.loader.load<T>(resolveArray, onProgress);\n\n // resume background loader...\n this._backgroundLoader.active = true;\n\n // remap to the keys used..\n\n const out: Record<string, T> = {};\n\n resolveArray.forEach((resolveResult) =>\n {\n const asset = loadedAssets[resolveResult.src];\n\n const keys = [resolveResult.src];\n\n if (resolveResult.alias)\n {\n keys.push(...resolveResult.alias);\n }\n\n keys.forEach((key) =>\n {\n out[key] = asset;\n });\n\n Cache.set(keys, asset);\n });\n\n return out;\n }\n\n /**\n * Unloads assets and releases them from memory. This method ensures proper cleanup of\n * loaded assets when they're no longer needed.\n * @param urls - Single URL/alias or array of URLs/aliases to unload\n * @example\n * ```ts\n * // Unload a single asset\n * await Assets.unload('images/sprite.png');\n *\n * // Unload using an alias\n * await Assets.unload('hero'); // Unloads the asset registered with 'hero' alias\n *\n * // Unload multiple assets\n * await Assets.unload([\n * 'images/background.png',\n * 'images/character.png',\n * 'hero'\n * ]);\n *\n * // Unload and handle creation of new instances\n * await Assets.unload('hero');\n * const newHero = await Assets.load('hero'); // Will load fresh from source\n * ```\n * @remarks\n * > [!WARNING]\n * > Make sure assets aren't being used before unloading:\n * > - Remove sprites using the texture\n * > - Clear any references to the asset\n * > - Textures will be destroyed and can't be used after unloading\n * @throws {Error} If the asset is not found in cache\n */\n public async unload(\n urls: ArrayOr<string> | ResolvedAsset | ResolvedAsset[]\n ): Promise<void>\n {\n if (!this._initialized)\n {\n await this.init();\n }\n\n const urlArray = convertToList<string | ResolvedAsset>(urls)\n .map((url) =>\n ((typeof url !== 'string') ? url.src : url));\n\n // check cache first...\n const resolveResults = this.resolver.resolve(urlArray);\n\n await this._unloadFromResolved(resolveResults);\n }\n\n /**\n * Unloads all assets in a bundle. Use this to free memory when a bundle's assets\n * are no longer needed, such as when switching game levels.\n * @param bundleIds - Single bundle ID or array of bundle IDs to unload\n * @example\n * ```ts\n * // Define and load a bundle\n * Assets.addBundle('level-1', {\n * background: 'level1/bg.png',\n * sprites: 'level1/sprites.json',\n * music: 'level1/music.mp3'\n * });\n *\n * // Load the bundle\n * const level1 = await Assets.loadBundle('level-1');\n *\n * // Use the assets\n * const background = Sprite.from(level1.background);\n *\n * // When done with the level, unload everything\n * await Assets.unloadBundle('level-1');\n * // background sprite is now invalid!\n *\n * // Unload multiple bundles\n * await Assets.unloadBundle([\n * 'level-1',\n * 'level-2',\n * 'ui-elements'\n * ]);\n * ```\n * @remarks\n * > [!WARNING]\n * > - All assets in the bundle will be destroyed\n * > - Bundle needs to be reloaded to use assets again\n * > - Make sure no sprites or other objects are using the assets\n * @throws {Error} If the bundle is not found\n * @see {@link Assets.addBundle} For adding bundles\n * @see {@link Assets.loadBundle} For loading bundles\n */\n public async unloadBundle(bundleIds: ArrayOr<string>): Promise<void>\n {\n if (!this._initialized)\n {\n await this.init();\n }\n\n bundleIds = convertToList<string>(bundleIds);\n\n const resolveResults = this.resolver.resolveBundle(bundleIds);\n\n const promises = Object.keys(resolveResults).map((bundleId) =>\n this._unloadFromResolved(resolveResults[bundleId]));\n\n await Promise.all(promises);\n }\n\n private async _unloadFromResolved(resolveResult: ResolvedAsset | Record<string, ResolvedAsset>)\n {\n const resolveArray = Object.values(resolveResult);\n\n resolveArray.forEach((resolveResult) =>\n {\n Cache.remove(resolveResult.src);\n });\n\n await this.loader.unload(resolveArray);\n }\n\n /**\n * Detects the supported formats for the browser, and returns an array of supported formats, respecting\n * the users preferred formats order.\n * @param options - the options to use when detecting formats\n * @param options.preferredFormats - the preferred formats to use\n * @param options.skipDetections - if we should skip the detections altogether\n * @param options.detections - the detections to use\n * @returns - the detected formats\n */\n private async _detectFormats(options: {\n preferredFormats: string | string[],\n skipDetections: boolean,\n detections: FormatDetectionParser[]\n }): Promise<string[]>\n {\n let formats: string[] = [];\n\n // set preferred formats\n if (options.preferredFormats)\n {\n formats = Array.isArray(options.preferredFormats)\n ? options.preferredFormats : [options.preferredFormats];\n }\n\n // we should add any formats that are supported by the browser\n for (const detection of options.detections)\n {\n if (options.skipDetections || await detection.test())\n {\n formats = await detection.add(formats);\n }\n else if (!options.skipDetections)\n {\n formats = await detection.remove(formats);\n }\n }\n\n // remove any duplicates\n formats = formats.filter((format, index) => formats.indexOf(format) === index);\n\n return formats;\n }\n\n /**\n * All the detection parsers currently added to the Assets class.\n * @advanced\n */\n public get detections(): FormatDetectionParser[]\n {\n return this._detections;\n }\n\n /**\n * Sets global preferences for asset loading behavior. This method configures how assets\n * are loaded and processed across all parsers.\n * @param preferences - Asset loading preferences\n * @example\n * ```ts\n * // Basic preferences\n * Assets.setPreferences({\n * crossOrigin: 'anonymous',\n * parseAsGraphicsContext: false\n * });\n * ```\n * @remarks\n * Preferences are applied to all compatible parsers and affect future asset loading.\n * Common preferences include:\n * - `crossOrigin`: CORS setting for loaded assets\n * - `preferWorkers`: Whether to use web workers for loading textures\n * - `preferCreateImageBitmap`: Use `createImageBitmap` for texture creation. Turning this off will use the `Image` constructor instead.\n * @see {@link AssetsPreferences} For all available preferences\n */\n public setPreferences(preferences: Partial<AssetsPreferences>): void\n {\n // Find matching config keys in loaders with preferences\n // and set the values\n this.loader.parsers.forEach((parser) =>\n {\n if (!parser.config) return;\n\n (Object.keys(parser.config) as (keyof AssetsPreferences)[])\n .filter((key) => key in preferences)\n .forEach((key) =>\n {\n parser.config[key] = preferences[key];\n });\n });\n }\n}\n\n/**\n * The global Assets class is a singleton that manages loading, caching, and unloading of all resources\n * in your PixiJS application.\n *\n * Key responsibilities:\n * - **URL Resolution**: Maps URLs/keys to browser-compatible resources\n * - **Resource Loading**: Handles loading and transformation of assets\n * - **Asset Caching**: Manages a global cache to prevent duplicate loads\n * - **Memory Management**: Provides unloading capabilities to free memory\n *\n * Advanced Features:\n * - **Asset Bundles**: Group and manage related assets together\n * - **Background Loading**: Load assets before they're needed over time\n * - **Format Detection**: Automatically select optimal asset formats\n *\n * Supported Asset Types:\n * | Type | Extensions | Loaders |\n * | ------------------- | ---------------------------------------------------------------- | --------------------------------------------------------------------- |\n * | Textures | `.png`, `.jpg`, `.gif`, `.webp`, `.avif`, `.svg` | {@link loadTextures}, {@link loadSvg} |\n * | Video Textures | `.mp4`, `.m4v`, `.webm`, `.ogg`, `.ogv`, `.h264`, `.avi`, `.mov` | {@link loadVideoTextures} |\n * | Sprite Sheets | `.json` | {@link spritesheetAsset} |\n * | Bitmap Fonts | `.fnt`, `.xml`, `.txt` | {@link loadBitmapFont} |\n * | Web Fonts | `.ttf`, `.otf`, `.woff`, `.woff2` | {@link loadWebFont} |\n * | JSON | `.json` | {@link loadJson} |\n * | Text | `.txt` | {@link loadTxt} |\n * | Compressed Textures | `.basis`, `.dds`, `.ktx`, `.ktx2` | {@link loadBasis}, {@link loadDDS}, {@link loadKTX}, {@link loadKTX2} |\n * > [!NOTE] Some loaders allow for custom configuration, please refer to the specific loader documentation for details.\n * @example\n * ```typescript\n * import { Assets } from 'pixi.js';\n *\n * // Initialize with options (optional). You can call Assets.load directly without init.\n * await Assets.init({\n * // Base path for all asset URLs\n * basePath: 'https://my-cdn.com/assets/',\n * // Manifest object that defines all assets\n * manifest: {\n * bundles: [{ name: 'gameAssets', assets: [] }, ...],\n * }, *\n * // Preferred texture settings\n * texturePreference: {\n * resolution: window.devicePixelRatio,\n * format: ['avif', 'webp', 'png']\n * }\n * });\n *\n * // Basic loading\n * const texture = await Assets.load('images/sprite.png');\n *\n * // Load multiple assets\n * const assets = await Assets.load([\n * 'images/bg.png',\n * 'images/character.png',\n * 'fonts/game.fnt'\n * ]);\n *\n * // Using aliases + multiple formats\n * await Assets.load({ alias: 'hero', src: 'images/hero.{webp,png}' });\n * const sprite = Sprite.from('hero'); // Uses the best available format\n *\n * // background loading\n * Assets.backgroundLoad(['images/level1.json', 'images/level2.json']); // Loads in the background one at a time\n *\n * // Load a bundle of assets from the manifest\n * const levelAssets = await Assets.loadBundle('gameAssets');\n * // Background loading of a bundle. This will load assets in the background one at a time.\n * // Can be interrupted at any time by calling Assets.loadBundle('gameAssets') again.\n * Assets.backgroundLoadBundle('resultsAssets');\n *\n * // Memory management\n * await Assets.unload('hero');\n * await Assets.unloadBundle('levelOne');\n * ```\n * @remarks\n * - Assets are cached automatically and only loaded once\n * - Background loading helps eliminate loading screens\n * - Format detection ensures optimal asset delivery\n * - Bundle management simplifies resource organization\n *\n * > [!IMPORTANT]\n * > When unloading assets, ensure they aren't being used elsewhere\n * > in your application to prevent missing texture references.\n * @see {@link AssetInitOptions} For initialization options\n * @see {@link AssetsPreferences} For advanced preferences\n * @see {@link BackgroundLoader} For background loading capabilities\n * @see {@link AssetsManifest} For manifest-based asset management\n * @see {@link Loader} For the underlying loading system\n * @see {@link Cache} For the caching system\n * @see {@link Resolver} For URL resolution details\n * @category assets\n * @class\n * @standard\n */\nexport const Assets = new AssetsClass();\n\n// Handle registration of extensions\nextensions\n .handleByList(ExtensionType.LoadParser, Assets.loader.parsers)\n .handleByList(ExtensionType.ResolveParser, Assets.resolver.parsers)\n .handleByList(ExtensionType.CacheParser, Assets.cache.parsers)\n .handleByList(ExtensionType.DetectionParser, Assets.detections);\nextensions.add(\n cacheTextureArray,\n\n detectDefaults,\n detectAvif,\n detectWebp,\n detectMp4,\n detectOgv,\n detectWebm,\n\n loadJson,\n loadTxt,\n loadWebFont,\n loadSvg,\n loadTextures,\n loadVideoTextures,\n loadBitmapFont,\n\n bitmapFontCachePlugin,\n\n resolveTextureUrl,\n resolveJsonUrl\n);\n\nconst assetKeyMap = {\n loader: ExtensionType.LoadParser,\n resolver: ExtensionType.ResolveParser,\n cache: ExtensionType.CacheParser,\n detection: ExtensionType.DetectionParser,\n};\n\ntype AssetType = keyof typeof assetKeyMap;\n\n// Split the Asset extension into it's various parts\n// these are handled in the Assets.ts file\nextensions.handle(ExtensionType.Asset, (extension) =>\n{\n const ref = extension.ref as AssetExtension;\n\n Object.entries(assetKeyMap)\n .filter(([key]) => !!ref[key as AssetType])\n .forEach(([key, type]) => extensions.add(Object.assign(\n ref[key as AssetType],\n // Allow the function to optionally define it's own\n // ExtensionMetadata, the use cases here is priority for LoaderParsers\n { extension: ref[key as AssetType].extension ?? type },\n )));\n}, (extension) =>\n{\n const ref = extension.ref as AssetExtension;\n\n Object.keys(assetKeyMap)\n .filter((key) => !!ref[key as AssetType])\n .forEach((key) => extensions.remove(ref[key as AssetType]));\n});\n"],"names":["resolveResult"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAiQO,MAAM,WACb,CAAA;AAAA,EAiCI,WACA,GAAA;AALA,IAAA,IAAA,CAAiB,cAAuC,EAAC,CAAA;AAEzD,IAAA,IAAA,CAAQ,YAAe,GAAA,KAAA,CAAA;AAInB,IAAK,IAAA,CAAA,QAAA,GAAW,IAAI,QAAS,EAAA,CAAA;AAC7B,IAAK,IAAA,CAAA,MAAA,GAAS,IAAI,MAAO,EAAA,CAAA;AACzB,IAAA,IAAA,CAAK,KAAQ,GAAA,KAAA,CAAA;AAEb,IAAA,IAAA,CAAK,iBAAoB,GAAA,IAAI,gBAAiB,CAAA,IAAA,CAAK,MAAM,CAAA,CAAA;AACzD,IAAA,IAAA,CAAK,kBAAkB,MAAS,GAAA,IAAA,CAAA;AAEhC,IAAA,IAAA,CAAK,KAAM,EAAA,CAAA;AAAA,GACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwDA,MAAa,IAAA,CAAK,OAA4B,GAAA,EAC9C,EAAA;AACI,IAAA,IAAI,KAAK,YACT,EAAA;AAEI,MAAA,IAAA,CAAK,2FAA2F,CAAA,CAAA;AAGhG,MAAA,OAAA;AAAA,KACJ;AAEA,IAAA,IAAA,CAAK,YAAe,GAAA,IAAA,CAAA;AAEpB,IAAA,IAAI,QAAQ,mBACZ,EAAA;AACI,MAAK,IAAA,CAAA,QAAA,CAAS,sBAAuB,CAAA,OAAA,CAAQ,mBAAmB,CAAA,CAAA;AAAA,KACpE;AAEA,IAAA,IAAI,QAAQ,QACZ,EAAA;AA