Loading 3D Assets in PlayCanvas
The web imposes constraints that traditional game development does not face. Every asset must download over the network before it can be used, and users on mobile connections may have limited bandwidth and data caps. PlayCanvas addresses these constraints with format conversion at import time, compression tools for textures and models, flexible preloading controls, and a runtime asset registry that supports on-demand loading with progress tracking.
Import 3D Models into the Editor
The primary format for 3D models in PlayCanvas is glTF 2.0 (GL Transmission Format), the open standard from the Khronos Group specifically designed for efficient delivery and loading of 3D content. glTF files come in two variants: .gltf (a JSON file with separate binary and texture files) and .glb (a single binary file that bundles everything together). GLB is typically the more convenient format because it keeps all the model data in one file.
To import a model, drag the file from your computer directly into the editor's asset panel. PlayCanvas processes the file immediately, extracting geometry, materials, textures, skeleton data, and animations into separate asset entries. Each extracted material becomes its own asset that you can edit independently, and textures are stored as separate image assets that the materials reference. This decomposition lets you swap materials between models, adjust textures without re-importing the model, and reuse assets across different entities.
The editor also accepts FBX and OBJ files, which it converts to an internal format during import. However, glTF produces more predictable results because it is a well-defined standard with fewer interpretation differences between exporters and importers. If your 3D modeling tool (Blender, Maya, 3ds Max, or Cinema 4D) supports glTF export, prefer that format. Blender in particular has an excellent built-in glTF exporter that handles PBR materials, skeletal animation, morph targets, and multiple animation clips reliably.
After import, add the model to your scene by dragging it from the asset panel into the viewport or creating an entity with a Render component and assigning the model asset. The Render component replaces the older Model component and supports features like lightmapping, instancing, and per-entity material overrides. Check the model's scale and orientation in the viewport. If the model appears too small, too large, or rotated incorrectly, adjust the entity's scale and rotation rather than re-exporting the model, unless the issue affects animation or physics alignment.
Optimize Textures for Web Delivery
Textures are almost always the largest component of your game's download size and memory footprint. A single uncompressed 2048x2048 RGBA texture consumes 16MB of GPU memory, and a typical game scene might use dozens of textures. Without optimization, a game with 30 textures at this resolution would require nearly 500MB of VRAM, far exceeding what most mobile devices can provide.
PlayCanvas supports Basis Universal texture compression, which compresses textures at build time into a format that the GPU decompresses natively at render time. This reduces both download size (by 4 to 6 times compared to PNG) and runtime memory consumption (by 4 to 8 times compared to uncompressed textures). Enable Basis compression on a per-texture basis from the asset inspector by selecting the "Basis" option in the compression settings.
Resolution is another lever. Not every texture needs to be 2048x2048. Normal maps for distant objects might look fine at 512x512. Roughness maps with gradual gradients can work at 256x256. The editor lets you set maximum resolution per texture, automatically downscaling on import if the source image exceeds the limit. Set conservative limits globally and increase them only for hero assets that the player sees up close.
Mipmaps are pre-computed downscaled versions of a texture that the GPU uses when rendering the texture at smaller apparent sizes on screen. They prevent shimmering artifacts and improve cache coherence. PlayCanvas generates mipmaps automatically for imported textures, and you should leave this enabled for almost all textures. The exception is UI textures and pixel-art textures that should not be filtered, where you can disable mipmaps and set the filtering mode to "Nearest" to preserve sharp pixel boundaries.
Anisotropic filtering improves texture quality at oblique viewing angles, like a ground texture stretching toward the horizon. The editor lets you configure anisotropy levels from 1 (no anisotropic filtering) to 16 (maximum quality). Higher values look better but consume slightly more GPU time. Set a global default of 4 or 8 and increase to 16 only for ground surfaces and walls where oblique viewing is common.
Configure Preloading and Asset Bundles
Every asset in PlayCanvas has a "preload" toggle in its inspector. When enabled, the asset downloads and decodes before the application's start event fires, guaranteeing it is available from the first frame. When disabled, the asset exists in the registry but must be loaded explicitly through code before it can be used. For a small game with few assets, preloading everything is the simplest approach and avoids runtime loading complexity entirely.
For larger projects, preloading everything creates unacceptable startup times. A game with 200MB of total assets should not force the player to wait for all of them before seeing the main menu. Instead, preload only what the initial screen needs (the menu UI, ambient music, background assets) and load level-specific content on demand when the player starts a level or transitions between areas.
Asset bundles group related assets into a single downloadable package. Create a bundle from the asset panel, then drag assets into it. At runtime, loading a bundle downloads all its constituent assets in one HTTP request, which is faster than downloading each asset individually due to reduced connection overhead. Organize bundles by level, zone, or feature so you can load exactly what is needed for the current gameplay context.
The engine fires progress events during bundle and asset loading, providing a normalized 0-to-1 progress value that you can use to drive a loading bar UI. Wrap your loading calls in a loading screen scene that displays progress and transitions to the gameplay scene once loading completes. Handle loading errors gracefully with fallback assets or retry logic so a single failed download does not crash the entire game.
Load Assets at Runtime with the Asset Registry
The Asset Registry (accessible as this.app.assets in scripts) is your interface for finding, loading, and accessing assets during gameplay. Every asset uploaded to the project is registered here, whether or not it has been loaded yet. Use this.app.assets.find("assetName") to locate an asset by name, or this.app.assets.get(assetId) to retrieve one by its numeric ID, which is more reliable when multiple assets share similar names.
To load an asset that is not preloaded, call this.app.assets.load(asset) and listen for the "load" event on the asset object. The load event fires once the asset's resource is fully downloaded and ready for use. For models, this means the geometry and materials are parsed. For textures, the image data is decoded and uploaded to the GPU. Always check the asset's loaded property before attempting to use its resource to avoid null reference errors.
For batch loading scenarios, you can queue multiple asset loads and track overall progress. Create an array of assets to load, initiate loading for each one, and count completion events. Divide the completed count by the total to get a progress percentage. The asset registry's loadFromUrl method also supports loading assets from external URLs that are not part of the project, which is useful for user-generated content or dynamically served resources from a game server.
Runtime asset swapping is a powerful technique for memory management. Load a low-resolution version of a model or texture initially, then swap in the high-resolution version when the player approaches. The engine handles the GPU resource transition smoothly, and you free the low-resolution resource from memory once the swap is complete. This streaming approach is commonly used in open-world games to maintain visual quality near the player while conserving memory for distant content.
Manage Audio and Font Assets
Audio files import through the same drag-and-drop process as other assets. PlayCanvas supports MP3, OGG, WAV, and M4A formats. For sound effects that play frequently and need instant playback, use WAV or OGG for low-latency decoding. For background music tracks that stream during playback, MP3 or M4A provide better compression ratios without perceivable quality loss at typical bitrates of 128 to 192 kbps.
The Sound component provides 3D spatial audio with configurable attenuation curves. Set the reference distance (the distance at which the sound plays at full volume), the maximum distance (beyond which the sound is inaudible), and the rolloff factor that controls how quickly volume decreases between those two distances. The Doppler effect simulates pitch changes for moving sound sources, adding realism to passing vehicles, projectiles, and flying objects.
Each Sound component supports multiple slots, where each slot references a different audio asset and has independent volume, pitch, looping, and overlap settings. This lets you attach multiple sound types to a single entity. An enemy character might have slots for footsteps, attack sounds, hurt reactions, and death audio, all managed from one component with separate trigger logic in the entity's scripts.
Font assets for in-game text use the standard web font formats (TTF, WOFF, WOFF2). Import the font file, then reference it in Text elements or the Element component for UI text rendering. PlayCanvas generates signed distance field (SDF) font textures from the imported font, which scale cleanly to any size without pixelation. Configure the character set to include only the characters your game actually uses, reducing the generated texture size for languages with large character sets.
Use glTF as your primary model format, compress textures with Basis Universal, preload only what the first screen needs, and use asset bundles for level-specific content. This strategy minimizes load times while keeping GPU memory usage under control across all devices.