Unity WebGL: Tips to Optimize Game Size for the Web

Unity WebGL: Tips to Optimize Game Size for the Web

This article was originally written by our community developer Kaban.

Special thanks to: Maxim Pyatirublevy, Andrey Ivashentsev, Chica, Alexandr STG

The size of a game matters — a lot. For some players, even 20 MB can be too much, especially in areas with limited mobile connectivity. But even if everyone had lightning-fast internet, loading speed would still be critical for web games.

Why? Because faster loading directly translates into better player retention. The quicker your game loads, the higher your chances of success. So let’s dive into what resources can and should be optimized for web games made with Unity.


Sprites

Sprites play a major role: if you set them up incorrectly, they can take up too much space. Here are a few tips that will help you save memory:

  1. All sprites should have dimensions that are powers of 2: 16x16, 32x32, 64x64, 128x128, etc. At the very least, each side should be divisible by 4. This allows Unity to compress the sprite more efficiently, potentially reducing its size by up to 3x times.
  2. You can make some sprites 1 pixel wide. For example, you can make a 1 x 1,024 gradient from red to blue. Then you just have to widen it. For example, for the Russian flag, you need no more than 3 pixels. There is no point in loading a 128 x 128 texture if you can achieve the same effect, take up less space, and improve performance.
  3. Textures should be compressed using Unity's editor.
  4. Sprites should be stored in atlases. You can create them manually or use Unity’s Sprite Atlas.

A bit more about gradients. You can create a 1x512 white gradient or design cool backgrounds with smoothly blended colors. Let's check out some examples.

Article content
Article content
Article content
Article content

Creating a UI gradient

You can achieve the same results as shown in the images with just a bit of code.

Article content

Script: https://disk.yandex.ru/d/qUSuzrd42pAeMw

How to use 9-Slicing

You should definitely use 9-slicing.

Let's tackle this question by creating the button below in 345 bytes using the following tool: uiextensions.

Article content

1.    Create a sprite of a regular circle in Unity. By default, it is 256 by 256 pixels.

2.    Set Max Size to 32 to change the circle to 32 x 32.

Use the same settings as shown in the picture below.

Article content
Settings of our circle

You need to set up the borders. See the example in the picture below.

Now, you can expand the center of the button while preserving the original rounding.

Article content
Settings of our circle

3.    Create an Image and set it to "Sliced" in the settings.

Our button now looks like this:

Article content


Now we need to add a gradient using uiextensions.

Add the 1 x 512 white gradient you’ve already created, then use the UIAdditiveEffect script (feel free to delete it after it applies the necessary material).

This is just one example. There are plenty of other ways you can use this in your UI.

Compression formats

Let’s explore them using three images: a 16 x 16 pixel art, a 128 x 128 white UI icon, and a 512 x 512 image.

Without compression:

16—63 kB (the texture is in the atlas; that is why it is so big. But right now, we are more interested in its quality. The atlas size is 112 x 144)

128—64 kB

512—1 MB

When compressed in the default way:

16—2.7 kB. Compression quality: 100 (awful)

128—1.5 kB. Compression quality: 20

512—11.2 kB. Compression quality: 0

Article content
Without compression


RGB(A) Compressed ASTC 12 x 12 blocks.

16—1.9 kB. Compression quality: 100

128—1.9 kB. Compression quality: 50

512—28.9 kB. Compression quality: 50.

Regardless of the compression quality we set, the size remains unchanged, and only the 16 x 16 image’s quality is affected.

Article content
RGB(A) Compressed ASTC 12 x 12 blocks.


RGB(A) Compressed ASTC 10 x 10 blocks.

16—2.8 kB. Compression quality: 100

128—2.6 kB. Compression quality: 0

512—42.3 kB. Compression quality: 0

Article content
RGB(A) Compressed ASTC 10 x 10 blocks.


RGB(A) Compressed ASTC 8 x 8 blocks.

16—3.9 kB. Compression quality: 100

128—4 kB. Compression quality: 0

512—64 kB. Compression quality: 0

Article content
RGB(A) Compressed ASTC 8 x 8 blocks.


RGB(A) Compressed ASTC 4 x 4 blocks — the best for pixel games

16—15.8 kB. Compression quality: 50

128—4 kB. Compression quality: 0

512—64 kB. Compression quality: 0

Article content
RGB(A) Compressed ASTC 4 x 4 blocks


RGBA Crunched ETC2 — the best for most textures

16—3 kB. Compression quality: 100

128—2 kB. Compression quality: 30

512—11 kB. Compression quality: 0

Article content
RGBA Crunched ETC2


ARGB 16 bit

This is essentially a regular sprite, but it looks twice as bad and can't be compressed.

16—31.5 kB

128—32 kB

512—0.5 MB

Article content
ARGB 16 bit.


RGB Crunched DXT1|BC1

They don’t have a background, and adjusting the compression quality didn’t make any difference.

16—2.4 kB. Compression quality: 100

128—0.8 kB. Compression quality: 0

512—6.8 kB. Compression quality: 0

Article content
RGB Crunched DXT1|BC1

To summarize, we recommend focusing on the compression of pixel sprites, as the results for higher-quality textures tend to be either unsatisfactory or barely noticeable.

For pixel sprites, we suggest using one of two types of compression: RGB(A) Compressed ASTC 4x4 blocks or ARGB 16-bit.

Audio

Is some cases, audio can take up from 5% to 20% of the total game size. That’s why it’s so important to keep an eye on it, especially when it comes to music.

1. You can try to convert audio to Mono, but sometimes this can have the opposite effect and actually increase the size.

2. Pay close attention to the music settings. More details below.

Audio settings

That's the parameters you should change 👇

Article content

We recommend disabling “Preload audio data” and enabling "Load in background". That's the way to speed game loading up simply by checking a few boxes.

Audio formats

By setting the audio quality in Unity to 50 (indicated in parentheses), you can reduce its size by 40% depending on the format:

  • ogg—1.5 MB (0.8 MB)
  • wav—3.8 MB (1.5 MB)
  • mp3—2.1 MB (1.3 MB)
  • flac—3.8 MB (1.5 MB)

Keep in mind that this method won't work if you compress audio using third-party tools. For instance, if you take a 30 MB audio file and compress it with an online tool, the final build will still show the same file size as before compression. That's because Unity handles all the compression itself.

Audio settings in project settings

Here, you can see different options for the buffer size. Experiment with these settings in your game, as the audio may crackle depending on your specific setup.

Article content

Addressable

If your game takes a long time to load, this is the only thing that can help.

How will it help load a 50 MB game in 10 seconds?

Let’s look at an example. We have a 30-minute music selection, added to the project and placed in an addressable. The game size is 53 MB.


Article content

We've only loaded 8 MB so far, and we're already in the game.

Article content
You can view this information in the browser console in the “Network” tab.

But if we click the button to download the music, the game size immediately jumps to 51 MB.

Article content
You can view this information in the browser console in the “Network” tab.

In other words, you don’t need to download 50 MB of music just to start the game. The same applies to sprites, sounds, and anything else that takes up space.

Splash screen

It might seem like adding a custom background to the Unity logo is a great idea, especially since the background is already used in the game and there's no need to load it twice, right

Article content

However, Unity sees it as a separate image, which is not compressed. The background in the picture above takes up 0.8 MB.

Compressing fonts

The default LiberationSans font takes up 350 kB. Text Mesh Pro, for example, is another 1 MB.

Fonts that support Japanese or Chinese may take up even more.

Article content

Currently a single font takes up ¼ of an empty project.

You can go to your TMP font and click "Update Atlas Texture". Let’s assume that there is very little text in your game, so let’s type only the bare minimum: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z. Without spaces, of course.

Article content

After that, click the "Generate Font Atlas", then "Save". If you need only 10 letters, then there is no point in storing an atlas with 1,024 x 1,024 letters. You can compress it to 128 x 128, or, in this case, to 256 x 256. Now our game has only one language, and the font takes up 260 kB or 7.1% of the empty project.

If your game has many different symbols and this option isn’t suitable, we recommend compressing the atlas to 512 x 512. Keep the Atlas population set to "Dynamic" and adjust the Sample point size to 50 (if the font still looks reasonably good, you can try setting it to a lower value). Set the padding to 1-5. This will help fit more symbols in or slightly improve the quality of the existing ones. With this setup, a 1 MB font can shrink down to just 264 KB.

Article content

You can also compress a standard font using the same parameters. If you don’t need LiberationSans, set all its values to zero or simply delete it. Just make sure to replace the default font with another one in the Project settings.

Article content

Emoji fonts are created along with Text mesh pro. They are almost never used, and they take up space, so we suggest deleting them.

Compressing animations

You can compress animations, and the player will probably not even notice. More about it here: https://www.techarthub.com/animation-compression-unity/

Go to the imported animation, and you will see "Anim. Compression" on the "Animation" tab.

Article content

You can see examples of how much the quality of animation changes by following the link above.

  • Error at 0.5—119 kB
  • Error at 10—69 kB
  • Error at 100—14 kB

URP

Disabling post processing

If you're not using Post-processing, disable it. It generates sprites that increase the build size.

Article content

Dynamic batching

If you need Dynamic batching, then you have to check the corresponding box for URP projects, as in the screenshot below.

Article content

Go to Preferences → Core render pipeline → Visibility → All visible and enable Dynamic batching.

Article content

Build settings

Project settings

Compression Formats:

Gzip: 7.68 MB

Brotli: 5.8 MB

IL2CPP Code Generation: Faster Runtime

Do not use the "Faster (smaller) build" option. While it reduces the size of the build, it does not improve the loading speed. Yes, the build will be smaller, but performance will decrease, and it's not worth the trade-off.

Managed Stripping Level: medium

It has a greater effect on size, but can cause problems. For example, it may remove something you need for the game. Which, in turn, causes errors in the code.

If you want to set it to "High" to reduce the size as much as possible, we recommend checking the manual and reading the "Root Annotations" section. This will allow you to specify what cannot be cut, helping you achieve the smallest possible build.

https://docs.unity3d.com/Manual/ManagedCodeStripping.html

Build settings

Set Code optimization to Runtime speed only. Use "Shorter build time" only if you want to check how the game build works. Avoid doing it for a release.

Internet speed in different countries

If you're planning to release your game in Turkish, it's worth considering the type of internet connection they have. For example, translating a 90 MB game into Hindi (India) might not be ideal, given that the average internet speed in the country is 5 Mbps (0.63 MB).

Here are a few sites that can help you find out the average Internet speed by country:

Once you know the speed, subtract 25%. This will give you an estimate of how quickly the game will download.

To make things simpler, you can limit the Internet speed in your browser: F12 → Network → Add.

Article content

Other useful tips

1. The number of objects in the scene affects game loading. It’s better to start with 3 objects and then load the remaining 30 for your interface. This approach is faster than loading all 33 objects at once.

2. Players are more likely to wait an additional 10 seconds if they see that the game has already loaded, and they’re just waiting for another loading phase. Alternatively, you can let them play something simple, like Cookie clicker, in the meantime.

3. Use at least Unity 2021. If you’re targeting mobile as well, go for 2022.

4. Child objects in animations can negatively impact performance.

5. WebGPU is not available in Unity, so don’t expect it to enhance your game with advanced features.

6. In Canvas, remove the Raycast target from all non-clickable objects.

7. The second and any subsequent builds will always be larger than the first one.

So, like that we’ve covered all the key points. These are fairly simple steps that don’t require much effort, but they have a significant impact because loading speed is one of the most crucial factors on the web.

If you have any questions or want to find more more tips about optimizing your game on the web, feel free to join our Discord server.

Interesting and very insightful. There are products out there like reimage.dev which help game devs optimise items like sprites on the fly via dynamic URLs. We use this for our web games at PlaySpark.

To view or add a comment, sign in

More articles by Yandex Games

Others also viewed

Explore content categories