Sunday, 13 September 2026

How to Use Figma for Game UI Design: Mockup, Export, and Bring It Into Unity

Most Unity developers design UI directly in the Unity Canvas. You drag in a Panel, add some buttons, resize things until they look roughly right, and keep going. It works, but it is slow — every tweak requires playing the game or entering Play Mode to see the result in context, and iteration is painful.

Figma changes this. You design the whole UI in a browser tool that gives you instant visual feedback, proper spacing controls, and reusable components that update everywhere at once. Then you export what you need and build it in Unity with a clear reference to work from instead of designing and building at the same time.

I started using Figma for game UI mockups about halfway through a mobile project where the menu system kept changing. Every time the layout shifted I was re-parenting Canvas elements and fighting with anchors in Unity. Moving the work to Figma first meant I could iterate freely in five minutes per change instead of twenty, then implement only when the design was settled. That alone made it worth learning.



Why Figma Over Other Design Tools

Figma runs in the browser. No installation, no OS restriction, works the same on Windows, Mac, and Linux. The free plan allows unlimited personal files with up to three editors on shared projects — which covers most solo developers and small teams without paying anything.

The component system is the feature that makes it genuinely useful for game UI specifically. You build a button once as a component, use it across fifty screens, and when the art direction changes you update one source component and every instance updates automatically. That is exactly how Unity prefabs work, and it makes Figma the natural design tool for developers who already think in terms of reusable objects.

Adobe XD is the closest alternative and is largely discontinued in terms of active development. Sketch is Mac-only. Canva is for marketing graphics, not UI wireframes. For game UI design in 2026, Figma is the tool worth learning.



Part 1: Setting Up for Game UI Work

Creating a Frame at Your Target Resolution

In Figma, a Frame is a fixed-size container that represents a screen. For game UI you want frames that match your target resolution. Common starting points:

  • Mobile portrait: 1080 x 1920 (or 390 x 844 for iPhone 14 logical resolution)
  • Mobile landscape: 1920 x 1080
  • Tablet: 2048 x 1536
  • PC / Console: 1920 x 1080 or 2560 x 1440

Press F (or the Frame tool in the toolbar) and either drag a custom size or pick a preset from the right panel. Everything you design for that screen goes inside this frame.

If your game supports multiple resolutions, create a separate frame for each. Figma's canvas is infinite — stack several resolution variants side by side and you can see how your UI scales across device types at once.

Grids and Layout Guides

Select a frame and in the right panel add a Layout Grid. For game UI, a simple grid with 8 or 16 pixel column spacing gives you a consistent spatial rhythm to work against. Nothing in the final UI will match perfect grid alignment, but having the guide prevents the random spacing that makes amateur UI feel visually unorganized.

Fonts

Figma uses Google Fonts by default, which are free and available in Unity through TextMesh Pro's font asset pipeline. If your game uses a custom font, upload it to Figma as a local font (the Figma desktop app required for local fonts) and make sure you have the same font file in your Unity project. Font consistency between mockup and implementation matters — a font that renders at 24pt in Figma may look completely different at the same nominal size in Unity depending on import settings.



Part 2: Components — The Most Important Figma Feature for Game Dev

A component in Figma works exactly like a prefab in Unity. You create the master version once, and every copy (called an instance) inherits the master's design. Change the master, all instances update.

Creating a Button Component

  1. Design one button in your mockup — background rectangle, label text, any icon.
  2. Select all elements of that button.
  3. Right-click and choose Create Component (or Ctrl+Alt+K on Windows, Cmd+Option+K on Mac).
  4. A purple diamond icon appears in the layer panel — that is the master component.
  5. From now on, duplicate this component (Ctrl+D) rather than copying the individual elements. Each duplicate is an instance that stays connected to the master.

When the art direction changes and you need a different button background color, you update the master component once. Every button across every screen in the mockup updates in seconds instead of you hunting down fifty individual button backgrounds.

Component Variants

Buttons need states — normal, hover, pressed, disabled. Figma handles this through Component Variants. Select the master component, click Add Variant in the right panel, and Figma creates a set where each variant represents a different state. In Unity implementation, these variants map directly to the Transition states on a Unity Button component.

Auto Layout

Auto Layout is Figma's flex-box equivalent. Apply it to a group of elements and they space themselves automatically with consistent padding. When you add or remove an item, everything reflows without manual repositioning. For inventory grids, skill bars, and button rows, Auto Layout eliminates most of the tedious manual spacing work that makes mockup maintenance painful.

Part 3: Designing Game-Specific UI Elements

Health and Progress Bars

Design the bar as two overlapping rectangles: the background track and the fill. In Figma you set the fill as a percentage of the track width using constraints. In Unity, progress bars should use fill images or shaders, not a simple image — so when you export, you export the bar track and bar fill as separate sprites, not as one flat image. This is one of the most common mistakes developers make when bringing UI from Figma into Unity: exporting the whole bar as a single PNG when the fill needs to animate independently.

Panels and Windows

Panels should often use 9-slice sprites. In Figma, design your panel as a single rectangle with a border, corner radius, and any decorative details. When exporting, note which areas are the scalable middle and which are the fixed corners — you will set the 9-slice borders in Unity's Sprite Editor after import. Export the panel as a PNG with enough padding around the corners so the border stays intact when Unity stretches the middle.

Icons

Icons work best as SVGs exported from Figma for simple, clean vector shapes, or as PNGs at 2x your base resolution for anything with gradients or complex effects that SVG does not handle well. Combine multiple UI sprites into one texture atlas to reduce draw calls and boost performance. In Figma, you can organize all your icons on a single frame and export them as individual slices, then combine them in Unity using a Sprite Atlas.

Text

Text should usually remain real text inside Unity — not exported as an image. Design the text style in Figma (font, size, color, line height) and use those values to configure TextMesh Pro settings in Unity. Exporting text as a flat PNG loses the ability to localize, resize dynamically, or update copy without reimporting assets.



Part 4: Exporting From Figma

Getting assets out of Figma correctly is where most of the implementation pain either happens or gets avoided.

Naming Layers Before Exporting

Naming is one of those things people ignore until it starts hurting production. A Figma layer named "Rectangle 47" exports as Rectangle_47.png and lands in Unity as an asset with a meaningless name that is annoying to find, track, and replace later. Name every exportable layer descriptively before touching the export dialog:

UI_Button_Primary_Normal
UI_Button_Primary_Disabled
UI_Panel_Inventory
UI_Icon_Sword
UI_HealthBar_Track
UI_HealthBar_Fill

This takes ten minutes at the start and saves hours across the project's lifetime.

Export Settings

  1. Select the layers or frames you want to export.
  2. In the right panel, click + under the Export section.
  3. Set format to PNG for most UI elements. Use SVG for simple vector icons without gradients.
  4. Set the multiplier. For a 1080p base resolution, 1x exports at native size. For mobile at 2x DPI, export at 2x and import into Unity at the corresponding pixels-per-unit setting.
  5. Click Export Selected.

Do not export everything as one flat screenshot of the frame. Export the parts you need, then build the layout properly in Unity. A flat image of a complete UI screen looks right in Figma and is useless in Unity — nothing can be animated, nothing can change state, and implementing anything dynamic means either rebuilding it from scratch or fighting with a single large texture.

Figma-to-Unity Plugins

Several plugins automate parts of the export-to-Unity pipeline. Figma UI Exporter for Unity exports designs as structured JSON and imports them as Unity prefabs with a single click, keeping designs pixel-perfect from Figma to game. UnityFigmaBridge by Simon Oliver is a popular open-source option that downloads images as PNGs, imports them as sprites, and attempts to match fonts from Google Fonts automatically.

These plugins are worth evaluating for projects with large UI surface areas. For smaller projects or for learning the pipeline, doing the export manually first builds the understanding that makes plugin-generated output easier to debug when something does not match the design.



Part 5: Implementing the Design in Unity

With exported sprites in hand and a clear Figma reference to work from, Unity implementation becomes significantly faster than designing and building simultaneously.

  1. Import all exported PNGs into a Assets/UI/Sprites/ folder in Unity.
  2. Select each imported sprite and in the Inspector set Texture Type to Sprite (2D and UI).
  3. For 9-slice panels, open the Sprite Editor and drag the border handles to define the nine regions that stay fixed versus the center that scales.
  4. Create a Sprite Atlas (Assets > Create > 2D > Sprite Atlas) and drag your UI sprite folder into it. This reduces draw calls significantly — Unity batches all sprites in an atlas into a single draw call rather than one per sprite.
  5. Build the Canvas hierarchy in Unity using your Figma mockup as the reference. The Figma frame is the Canvas. Figma components become prefabs. Figma layers become GameObjects.

Set Canvas Scaler on your Canvas component to Scale With Screen Size and enter your Figma design resolution as the reference resolution. Unity's Canvas Scaler adapts to all resolutions automatically once this is configured — the UI scales proportionally rather than staying at a fixed pixel size across all devices.

Where Beginners Go Wrong

  • Exporting the entire screen as one flat image. Looks fine as a static screenshot, unusable as a game UI. Export individual elements and rebuild the layout in Unity.
  • Not naming layers before exporting. "Rectangle 47.png" in Unity is a support ticket waiting to happen six months later when you cannot remember what it is.
  • Designing text as images. Text that needs to change, localize, or resize dynamically must stay as real TextMesh Pro text in Unity. Design the style in Figma, implement it as text in Unity.
  • Designing at the wrong resolution and not accounting for DPI. A button that looks the right size on a 1920x1080 Figma frame will appear tiny on a mobile device if you did not account for pixel density. Design at logical resolution or account for the multiplier at export.
  • Skipping the 9-slice setup for panels. A panel exported as a plain PNG and stretched in Unity looks blurry and pixelated at the corners. Set up 9-slice borders in Unity's Sprite Editor so the corners stay sharp regardless of how the panel is scaled.
  • Ignoring the Sprite Atlas. Each UI sprite without an atlas is a separate draw call. A UI with fifty sprites and no atlas burns fifty draw calls on what should be one. Set up the atlas early — retrofitting it later is more work than doing it from the start.


A Practical Workflow for Solo Developers

The full pipeline in order, for a developer who has not used Figma before:

  1. Create a Figma account at figma.com — free, no credit card, instant access.
  2. Create a new file and add frames at your target resolution.
  3. Start with a rough wireframe — grey boxes and placeholder text, no colors. Get the layout right before worrying about aesthetics.
  4. Once the layout is approved (even if only by yourself), convert repeated elements into components.
  5. Add visual design — colors, fonts, background textures referenced from your art style.
  6. Name every exportable layer properly.
  7. Export individual sprites using the settings described above.
  8. Import into Unity, configure Sprite Type and 9-slice borders, set up a Sprite Atlas.
  9. Build the Canvas hierarchy using the Figma mockup as the direct reference.

Keep the Figma file open on a second monitor while implementing in Unity. Having the exact design visible while building removes the constant switching between reference images and the editor that slows down UI implementation.

Next Topics To Learn

Friday, 11 September 2026

How to Use Unity Version Control (Formerly Plastic SCM): Setup, Branching, and Large Files

Git is the right answer for most developers most of the time. The Git guide earlier in this series explains why: it is free, widely understood, works with every tool in the ecosystem, and the hosting options are abundant. But there are two situations where Git starts causing real friction in Unity projects, and Unity Version Control exists specifically to address both of them.

The first is large binary files. Git tracks text changes efficiently. A modified .fbx or .psd file is not a text diff — it is an entirely new binary blob, and Git stores both the old and new version forever. A Unity project with a year of texture and mesh history can balloon to gigabytes in ways that slow clones, push times, and storage costs in ways Git LFS only partially addresses.

The second is artists on the team. Git's branching model is logical once you understand it, but it is not intuitive for non-programmers. An artist who needs to edit a scene file and does not know whether someone else has it open is one accidental overwrite away from a bad day. Unity Version Control's Smart Locks lets a team member lock a file before editing it, preventing others from making conflicting changes until the lock is released — a workflow that makes sense to artists who are used to checking files out of a shared drive, not merging divergent histories.

Unity Version Control, previously named Plastic SCM, was acquired by Unity in 2020 and is now part of Unity DevOps. If you have heard it called Plastic SCM, UVCS, or Unity DevOps Version Control — they are all the same product at different points in its naming history.



A Real Scenario Where This Matters

Three people working on a Unity project: a programmer, a 3D artist, and a level designer. The programmer uses Git comfortably. The 3D artist has never used version control before. The level designer edits scenes in Unity.

With Git: the artist keeps forgetting to pull before pushing, the level designer's scene merges produce conflicts in Unity's binary YAML format that are nearly impossible to resolve manually, and every time someone adds new textures the repository gets measurably slower to clone.

With Unity Version Control: the artist uses Gluon — UVCS's simplified interface designed specifically for artists and non-technical team members — which shows only their checked-in files and pending changes without exposing branch topology or merge concepts. The level designer locks scenes before editing them so nobody else can touch them simultaneously. Binary files are stored efficiently without the compounding history problem Git has.

This is not a hypothetical. It is the exact situation UVCS was designed for. Whether it is the right tool for your project depends heavily on whether you are in this situation or not.

Pricing: What Changed in March 2026

As of March 1, 2026, Unity updated Unity DevOps pricing significantly. The new structure includes unlimited seats for cloud-hosted Unity Version Control — no more per-seat charges — plus 25GB of free storage (five times the previous 5GB limit) and 100GB of free egress per month. Usage beyond those free tiers is pay-as-you-go per GB.

This is a meaningful change. The previous model charged per seat after the first three users, which made UVCS expensive for teams of five or more. Unlimited seats at the free tier makes it genuinely viable for small and medium teams at no monthly cost, provided you stay within 25GB of storage.

25GB goes faster than it sounds for a Unity project with high-resolution textures, audio files, and FBX meshes. A single AAA-quality character with textures can be several hundred MB. Keep an eye on storage usage in the Unity Cloud Dashboard and plan your asset pipeline accordingly — compressing textures before committing and keeping large reference files outside the repository where possible.

TierSeats Free StorageFree EgressOverage
FreeUnlimited    25 GB100 GB/monthPay-as-you-go per GB
Unity DevOps (paid)UnlimitedIncreased per planIncreased per planReduced per-GB rate

Verify current overage rates at unity.com/features/version-control — the per-GB pricing changes and the official page is the authoritative source.

Part 1: Setup and Installation

Creating a Repository

  1. Go to cloud.unity.com and sign in with your Unity ID.
  2. Create or select an organization.
  3. Go to DevOps > Version Control.
  4. Click Create Repository, give it a name matching your project, and confirm.

Installing the Client

Unity Version Control can be used from within the Unity Editor, as a standalone desktop client, or on Linux. For most developers, using it from within the Unity Editor is the fastest way to get started.

In Unity, go to Edit > Project Settings > Version Control. Set the Mode dropdown to Unity Version Control. Unity installs the necessary package and adds a UVCS panel to the editor.

Alternatively, download the standalone Unity Version Control desktop client from the Unity DevOps page for a full-featured interface outside the editor. The desktop client is worth installing even if you primarily work inside Unity — it provides better branch visualization and conflict resolution tools than the in-editor panel.

Connecting to Your Repository

  1. In the Unity editor's UVCS panel (or the desktop client), sign in with your Unity ID.
  2. Select the organization and repository you created.
  3. Choose a local workspace location — the folder on your machine where the repository files will live.
  4. Click Create Workspace.

Your project files now exist both in the Unity project folder and tracked by UVCS. The first checkin is next.

Part 2: The Daily Workflow

UVCS uses different terminology from Git, which trips people up when switching. The concepts map closely — the words are just different.

Git TermUVCS TermWhat It Means
CommitCheckinSave a snapshot of changes to the repository
Commit hashChangesetA numbered snapshot of changes at a point in time
PushPush (same)Send local changesets to the cloud repository
PullUpdate / SyncGet latest changes from the cloud to local workspace
BranchBranch (same)An independent line of development
Staging areaPending ChangesChanges ready to be included in the next checkin

Checking In Changes

  1. In the UVCS panel inside Unity (or the desktop client), you will see Pending Changes — files that have been modified since the last checkin.
  2. Review the list. Select the files to include in this checkin.
  3. Enter a comment describing what changed.
  4. Click Checkin.

The checkin is local by default — it saves to the local repository. To push to the cloud, click Push in the toolbar. In practice, most developers check in and push in the same action by using the combined Push button.

Updating From the Cloud

Before starting work each session, sync to get the latest changes from your team:

  1. Click Sync / Update in the UVCS panel or desktop client.
  2. UVCS downloads any changesets pushed by other team members since your last sync.
  3. If there are conflicts, UVCS shows them in a conflict resolution window — described in the troubleshooting section below.

Part 3: Branching and Task Branches

UVCS handles branching similarly to Git but with a workflow that maps more naturally to how game teams actually work — particularly through task branches.

Creating a Branch

  1. In the Branch Explorer (desktop client: View > Branch Explorer), right-click the branch you want to branch from (usually main).
  2. Select Create Branch.
  3. Name it descriptively: task/add-enemy-patrol, fix/jump-height-bug.
  4. UVCS switches your workspace to the new branch.

Merging Back to Main

  1. Switch to the main branch.
  2. Right-click your task branch in the Branch Explorer.
  3. Select Merge.
  4. UVCS shows a merge preview. Confirm and the changes integrate into main.

The Branch Explorer's visual tree is one of UVCS's genuine advantages over Git for developers who are not comfortable with command-line branching. Seeing the branch history as a graphical tree rather than as terminal output makes the state of the repository immediately readable for the whole team, including non-programmers.

Part 4: Smart Locks for Artists

Smart Locks is UVCS's file locking system. When a team member locks a file, others are prevented from making conflicting edits until the lock is released — even across branches, where the lock travels until it reaches the destination branch and the change is merged.

This is specifically valuable for Unity scene files, large textures, and audio files — binary assets where a merge conflict means "two people both changed this file and there is no way to automatically combine the results."

Locking a File

  1. In the desktop client, right-click a file in the workspace.
  2. Select Lock.
  3. The file is now locked to your user. Others attempting to check in changes to the same file see a warning that it is locked.

The Gluon Interface for Artists

Gluon is UVCS's simplified interface designed for artists and other non-technical team members. It shows only the files in the workspace without exposing branch topology, changeset history, or merge concepts. The Gluon workflow is: update to get the latest files, lock the file you are about to edit, make your changes, check in. That is the entire workflow non-programmers need to know.

Pointing artists at Gluon rather than the full UVCS client removes most of the friction that comes from asking non-programmers to use version control at all.

UVCS vs Git: Which Should You Use

This is the honest version of the comparison, not the marketing version.

FactorGit + GitHub/GitLabUnity Version Control
Setup timeFast — widely documentedModerate — Unity account and cloud setup required
Large binary filesNeeds Git LFS, still has limitationsNative, efficient, no LFS setup
Artist-friendly workflowSteep learning curveGluon makes it accessible to non-programmers
File lockingGit LFS locks, limitedSmart Locks, robust and branch-aware
Unity Editor integrationVia third-party pluginsNative, built into the editor
Ecosystem / toolingEnormous — GitHub Actions, CI/CD, code review toolsUnity-specific — less third-party tooling
Cost (small team)Free on GitHubFree up to 25GB storage
Cost at scaleVaries by hostPay-as-you-go per GB over 25GB
Best forSolo developers, programmer-only teams, open source projectsTeams with artists, projects with large binary assets, studios wanting Unity-native workflow

The honest answer for a solo programmer: Git is probably still the right choice. The Git guide and GitHub Actions guide earlier in this series cover a workflow that is free, well-documented, and integrates with more external tools than UVCS does.

The honest answer for a team with artists who struggle with Git, or a project pushing large textures and audio regularly: UVCS is worth the switch. Smart Locks and Gluon solve real problems that Git LFS only partially addresses.

Common Mistakes

  • Checking in Unity's Library folder. The Library folder is generated by Unity from your source assets — it is large, machine-specific, and should never be in version control. Add a .uvcsignore file (equivalent to .gitignore) at the root of the workspace and exclude Library, Temp, and Logs before the first checkin.
  • Not syncing before starting work. Checking in changes on top of stale local files creates conflicts that would not have existed if you had pulled the latest changesets first. Sync at the start of every work session, not just when something breaks.
  • Forgetting to release locks. A locked file that nobody is actively editing blocks the whole team from touching it. Release locks as soon as the file is checked in. Set a team convention that locks must be released within a reasonable window — leaving files locked across weekends is a recurring source of friction.
  • Committing with no comment. A changeset with no comment is useless for understanding project history. Even "Fix player jump height" is better than nothing. Make descriptive comments a team requirement from day one.
  • Exceeding 25GB storage without planning. The free tier is generous but Unity projects with large asset libraries fill it. Monitor storage usage in the Unity Cloud Dashboard regularly and establish a convention for what assets belong in version control versus external storage before you hit the limit unexpectedly.

Troubleshooting

Merge conflict on a Unity scene file.

Scene file conflicts are the most painful kind — Unity's YAML scene format is technically mergeable but practically difficult. The best fix is prevention: use Smart Locks on scene files so only one person edits them at a time. For a conflict that has already happened, UVCS's visual merge tool shows both versions side by side. For scene files specifically, picking one version entirely (theirs or mine) is usually less painful than trying to merge line by line.

Workspace shows files as changed that you did not touch.

Unity regenerates certain files automatically — project settings, package manifests, generated meta files — when the editor opens or imports assets. Check whether the "changed" files are ones you actually modified or Unity auto-generated changes. If they are auto-generated, either add them to .uvcsignore or check them in as part of a housekeeping changeset so the workspace stays clean.

Push fails with an authentication error.

Your Unity ID session has likely expired. Sign out and sign back in through the UVCS panel or desktop client. If the issue persists, check whether your Unity organization's permissions still include access to the repository — organization administrators can revoke access without the affected user being notified immediately.

Storage usage growing faster than expected.

Check the Unity Cloud Dashboard's storage breakdown by repository. Large spikes usually come from accidentally committing generated files (Library, Temp), binary assets that should be compressed before committing, or keeping too many large historical versions of frequently-changed textures. Compressing textures before committing and enforcing the .uvcsignore file for generated folders prevents most runaway storage growth.

Action Steps

  1. Create a Unity ID and sign into cloud.unity.com if you do not already have an account.
  2. Create a new UVCS repository for your current Unity project.
  3. Connect via the Unity Editor's Project Settings > Version Control panel.
  4. Create a .uvcsignore file excluding Library, Temp, Logs, and any other generated folders before making the first checkin.
  5. Do a first checkin of the entire project with a comment like "Initial checkin — project setup."
  6. If working with a team: add each member, have artists install Gluon, and establish a locking convention for scene files before anyone starts parallel work.

Next Topics To Learn

  • Git and GitHub for Beginners — if you are a solo developer or programmer-only team, the Git guide covers the simpler and more widely supported alternative with the same core version control concepts.
  • GitHub Actions for Beginners — automated build pipelines that connect to your version control workflow, covering the CI/CD side of what Unity DevOps Build Automation also provides.
  • Unity Android Build Setup Guide — once version control is in place, the next production concern is the build pipeline — Android and iOS build configuration covered in those guides.

Tuesday, 1 September 2026

How to Use Unity Addressables: Fix Build Size, Memory, and Asset Loading for Beginners

There is a specific moment in most Unity projects when asset management stops working. You have been using the Resources folder since day one because it is simple — put a prefab in Resources, call Resources.Load, done. Then you add a few hundred assets, your build size balloons, your load times get worse, and you start noticing that Unity loads everything in Resources at startup whether the current scene needs it or not.

That is when most developers search for "Unity Addressables" for the first time.

Addressables is Unity's answer to the Resources folder problem. It provides a way to load assets by a string address — like a key — rather than a direct reference, supports asynchronous loading from any location, and handles dependency management and memory counting automatically. The setup is more involved than Resources.Load, but the tradeoff is real control over what is in memory, when it loads, and where it comes from.

This guide covers the full beginner path: installing the package, marking assets as addressable, loading them in code, releasing memory correctly, and understanding Groups well enough to make sensible decisions about your project's asset structure.



Resources Folder vs Addressables: The Real Difference

Before touching any Addressables setup, understanding why the Resources folder falls apart at scale saves you from second-guessing the switch later.

When you put an asset in a Resources folder, Unity includes it in the build unconditionally. Every texture, prefab, and audio clip in Resources gets packed into the game regardless of whether a player ever reaches the content that uses it. On mobile especially, this punishes your build size and your startup memory without any benefit to players who never trigger those assets.

Addressables loads assets on demand. Only the assets your code explicitly requests get loaded, and only when they are requested. Assets can live locally in the build, or remotely on a server, and the loading code is identical either way. That last part is what makes Addressables worth the setup cost for projects planning any kind of content delivery beyond the initial install.

Area Resources Folder Addressables
Asset loading Synchronous, blocks main thread Asynchronous, non-blocking
Build inclusion Everything in Resources, always Only what is explicitly loaded
Memory management Manual, easy to leak Reference counted, explicit release
Remote content Not supported Built-in, same code as local
Setup complexity None — just put files in folder Moderate — package install + Groups config
Best for Small projects, prototypes, jam games Any project targeting mobile or planning DLC

The Resources folder is not wrong for small projects. If you are making a game jam entry or a quick prototype with fifty assets, Addressables adds overhead you do not need. The switch makes sense when build size starts to matter, when you want scene-by-scene memory control, or when you are planning post-launch content updates.


Part 1: Installing the Addressables Package

  1. In Unity, go to Window > Package Manager.
  2. In the dropdown at the top left, select Unity Registry.
  3. Search for Addressables.
  4. Select Addressables from the results and click Install.

After installation, go to Window > Asset Management > Addressables > Groups. Unity prompts you to create the Addressables settings — click Create Addressables Settings. This generates a set of configuration assets in your project under Assets/AddressableAssetsData/. You do not need to edit these files directly — the Groups window is where all configuration happens.

The Groups window is the Addressables control panel. Every asset you mark as Addressable appears here, organized into groups. Groups control how assets are bundled for the build and where they are loaded from.

Part 2: Marking Assets as Addressable

Any asset in Unity — prefab, texture, audio clip, scene, ScriptableObject — can be made Addressable.

Method 1: Inspector Checkbox

  1. Select any asset in the Project window.
  2. In the Inspector, check the Addressable checkbox that now appears after the package is installed.
  3. An address field appears below the checkbox, pre-filled with the asset's path. You can leave this as-is or replace it with a shorter, more meaningful address like "PlayerPrefab" or "Enemies/Goblin".

Method 2: Drag Into Groups Window

  1. Open the Groups window (Window > Asset Management > Addressables > Groups).
  2. Drag assets from the Project window directly into a group in the Groups window.

Both methods do the same thing. The Inspector checkbox is faster for individual assets. Drag-and-drop is better for marking many assets at once or for organizing assets into specific groups during initial setup.

Choosing Addresses

The address is a string you use in code to request the asset. The default (the asset's full project path) works but is fragile — if you move or rename the asset, the path changes and your code breaks. A custom address like "UI/HealthBar" or "Characters/Orc_Warrior" decouples the code from the file system location. Moving the asset later only requires updating the address in the Inspector, not in every script that references it.

Labels are another organizational tool. A label is a tag you apply to multiple assets — "Enemy", "Level1", "AudioMusic" — and you can load all assets with a specific label at once rather than loading each by individual address. Labels become useful when you want to load an entire category of assets, like all enemies for a specific chapter.



Part 3: Loading Addressable Assets in Code

This is where Addressables requires a different approach from Resources.Load. Addressables uses asynchronous loading — you request an asset and get back a handle that completes when the asset is ready. You cannot use the loaded asset on the line immediately after you request it the way you can with synchronous Resources.Load.

Loading a Prefab and Instantiating It

using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;

public class EnemySpawner : MonoBehaviour
{
    [SerializeField] private string enemyAddress = "Characters/Orc_Warrior";

    private AsyncOperationHandle<GameObject> _handle;

    public void SpawnEnemy(Vector3 position)
    {
        Addressables.LoadAssetAsync<GameObject>(enemyAddress).Completed += OnEnemyLoaded;
    }

    private void OnEnemyLoaded(AsyncOperationHandle<GameObject> handle)
    {
        _handle = handle;

        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            Instantiate(handle.Result, transform.position, Quaternion.identity);
        }
        else
        {
            Debug.LogError($"Failed to load enemy: {enemyAddress}");
        }
    }

    private void OnDestroy()
    {
        if (_handle.IsValid())
            Addressables.Release(_handle);
    }
}

Three things worth understanding in this code before moving on.

.Completed += registers a callback that fires when the async operation finishes. You can alternatively use async/await with Addressables if you are comfortable with C# async patterns — either approach works, the callback version is shown here because it does not require additional setup.

handle.Status == AsyncOperationStatus.Succeeded is the error check. Addressables loads can fail — wrong address string, missing bundle, network error on remote assets. Always check the status before using the result.

Addressables.Release(_handle) in OnDestroy is not optional. Addressables counts references automatically and unloads assets when the count reaches zero — but only if you call Release. Forgetting Release is the most common Addressables memory leak. The asset stays in memory permanently until the application quits.

Instantiate and Release Together

For prefabs that you want to instantiate once and never reuse, there is a shortcut:

Addressables.InstantiateAsync(enemyAddress, position, Quaternion.identity).Completed += handle =>
{
    if (handle.Status == AsyncOperationStatus.Succeeded)
    {
        // The instance is already in the scene
        // Release is handled automatically when the GameObject is destroyed
        // IF you use Addressables.ReleaseInstance instead of Destroy
    }
};

When using InstantiateAsync, call Addressables.ReleaseInstance(gameObject) instead of Destroy to properly decrement the reference count. Calling regular Destroy on an Addressables-instantiated object destroys the GameObject but does not release the underlying asset from memory.

Part 4: Understanding Groups

Groups determine how Addressable assets are bundled together for the build. Getting Groups wrong does not break anything immediately — it degrades performance and build size over time in ways that are hard to diagnose later.

Default Local Group

The default group Unity creates is fine for getting started. Assets in this group are packed into the build and loaded from local storage. For a project that does not need remote content or DLC, one well-organized local group covers most needs.

One Asset Per Bundle vs Pack Together

In each group's settings, the Bundle Mode controls how assets within the group get packed:

  • Pack Together — all assets in the group go into one bundle file. Loading any asset from the group loads the entire bundle into memory. Good for assets that are almost always used together (all assets for a specific level, all UI sprites).
  • Pack Separately — each asset gets its own bundle. Fine-grained memory control, but more bundle files and more overhead per load request. Good for large assets you load infrequently.
  • Pack Together by Label — assets sharing a label get bundled together. The most flexible option for projects with meaningful label organization.

The Pack Together trap: if you put all your game's assets in one group set to Pack Together, loading a single enemy prefab loads the entire bundle — potentially hundreds of assets — into memory at once. This defeats the purpose of Addressables. Organize groups by when assets are used, not by asset type.


Part 5: Building and Testing

Building Addressable Content

Before testing Addressables in a build, you need to build the Addressable content separately from the main Unity build:

  1. Open the Groups window.
  2. Click Build > New Build > Default Build Script.
  3. Wait for the build to complete. Unity generates bundle files in your project's Library folder for local groups.

After building content, build the player as normal. The Addressables bundles are included automatically.

Testing in the Editor

In the Groups window, the Play Mode Script dropdown controls how Addressables behave in Play Mode:

  • Use Asset Database (fastest) — loads assets directly from the project without going through bundles. Fastest iteration but does not test actual bundle loading behavior.
  • Simulate Groups (advanced) — simulates bundle loading without building bundles. Slower than Asset Database but catches dependency and grouping issues without a full build.
  • Use Existing Build (requires built groups) — tests exactly what will happen in a real build. Requires the Addressable content build to be up to date.

Use Asset Database during active development. Switch to Use Existing Build when testing a release candidate to confirm the actual bundle loading behavior matches what you expect.

Common Mistakes

  • Forgetting Addressables.Release after loading. This is the source of most Addressables memory leaks. Every LoadAssetAsync call needs a corresponding Release when the asset is no longer needed. Store the handle and release it in OnDestroy or when the asset's lifetime ends.
  • Using regular Destroy on Addressables-instantiated objects. Destroy removes the GameObject but does not release the asset from Addressables' reference count. Use Addressables.ReleaseInstance(gameObject) instead.
  • Putting all assets in one Pack Together group. Loading any single asset from a Pack Together group loads the entire bundle. One massive group effectively re-creates the Resources folder problem — everything in memory, all at once.
  • Not rebuilding Addressable content after changing assets. If you mark new assets as Addressable or change group settings after the last content build, the bundles are stale. Always rebuild content before testing with Use Existing Build play mode.
  • Using the full asset path as the address and then moving the file. If the address is the file path and you reorganize your project folder, the address changes and any code referencing the old path breaks silently at runtime. Custom addresses decouple code from file location.
  • Mixing Addressables and Resources.Load for the same asset. If an asset is marked as Addressable and also sits in a Resources folder, Unity may include it twice in the build — once in the Resources bundle and once in the Addressables bundle. Remove assets from Resources when you mark them as Addressable.

Action Steps

  1. Install the Addressables package through Package Manager and create the initial settings file.
  2. Identify three to five assets in your current project that are loaded at runtime — enemy prefabs, UI elements, audio clips — and mark them as Addressable with meaningful custom addresses.
  3. Replace any Resources.Load calls for those assets with Addressables.LoadAssetAsync, add the Completed callback, and add Release in OnDestroy.
  4. Organize those assets into groups based on when they are used — not by asset type.
  5. Run a content build and test with Use Existing Build play mode to confirm loading works as expected.

Next Topics To Learn

  • Unity Scene Management Explained — Addressables handles scene loading too. Addressables.LoadSceneAsync replaces SceneManager.LoadScene for scenes you want to load on demand from bundles.
  • Unity Mobile Optimization Guide — build size reduction, memory management, and texture compression decisions connect directly to how Addressables groups are organized for mobile targets.
  • Unity Save System Guide — ScriptableObject-based save data pairs well with Addressables when save state needs to reference assets by address rather than by direct reference.

Saturday, 1 August 2026

How to Use GitHub Actions: Automate Your Builds and Stop Doing Repetitive Work

At some point you will push a change, forget to test it, and break something. Or you will spend ten minutes manually zipping a build and uploading it somewhere before you can share it with a tester. Or you will be three weeks into a project before realizing that two different people on the team have been building with different dependency versions and their outputs are subtly different in ways that are annoying to track down.

GitHub Actions solves all of that. You define workflows as YAML files that trigger on events like pushes, pull requests, or a schedule, and GitHub runs those steps on its own servers. No external tools, no separate accounts, everything lives in your repository.

I avoided GitHub Actions for longer than I should have because "CI/CD pipeline" sounded like enterprise infrastructure, not something a solo developer needed. Turns out a workflow that runs your tests and uploads a build artifact every time you push to main takes about fifteen minutes to write and saves a disproportionate amount of manual work over the course of a project. This guide covers how to write one from scratch, how to use secrets safely, and how to set up an automated Unity build — tying directly into the Git guide from this series.



How GitHub Actions Works

Every GitHub Actions workflow is a YAML file sitting in .github/workflows/ inside your repository. When a specified event happens — someone pushes code, opens a pull request, or a timer fires — GitHub reads that file and runs the steps it defines on a virtual machine it spins up specifically for that run.

Five terms you need before writing any YAML:

  • Workflow — the whole thing. One YAML file, one workflow.
  • Event — what triggers the workflow. A push, a pull request, a schedule, a manual button click.
  • Job — a group of steps that run together on one virtual machine. Workflows can have multiple jobs running in parallel or in sequence.
  • Step — one task inside a job. Either a shell command or a pre-built action from the marketplace.
  • Runner — the virtual machine that runs the job. GitHub provides ubuntu-latest, windows-latest, and macos-latest for free.

That is the whole mental model. Everything else is details about how to configure these five things.



Part 1: Your First Workflow

Create this folder structure in your repository: .github/workflows/

Inside it, create a file called ci.yml. Paste this:

name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Print a message
        run: echo "The workflow ran successfully"

Push this file to your repository. Go to the Actions tab on GitHub. You will see a workflow run appear, go yellow (running), then green (succeeded). That is GitHub Actions working. The actual steps do nothing useful yet — that is fine. You have confirmed the plumbing works before writing anything that matters.

Breaking Down the YAML

name: CI sets the display name in the Actions tab. Name it whatever makes sense for what it does.

on: push/pull_request defines the trigger. This workflow runs when code is pushed to main or when a pull request targets main. You can add more events or change these to whatever makes sense for your project.

runs-on: ubuntu-latest tells GitHub which virtual machine to use. Ubuntu is the fastest and cheapest for most workflows. Use windows-latest or macos-latest only when you specifically need those environments.

uses: actions/checkout@v4 is a pre-built action that checks out your repository's code onto the runner. Almost every workflow starts with this step — without it, the runner is a blank machine with none of your files on it.

run: echo "..." runs a shell command directly. Any command you could run in a terminal works here.

Part 2: A Real Workflow — Running Tests

The most common first use of GitHub Actions is running tests automatically on every push, so broken code cannot be merged without someone noticing. Here is a workflow for a Node.js project:

name: Test

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

uses: actions/setup-node@v4 is another pre-built action, this one installs a specific Node.js version. The with: block passes parameters to it — the version and whether to cache dependencies. Caching is worth enabling on anything that installs packages, because it can cut minutes off your run time by not re-downloading the same packages on every run.

npm ci instead of npm install is intentional. npm ci installs exactly what is in the lockfile, which is what you want on a CI runner. npm install can update the lockfile and introduce version drift between runs.

For a Python project, replace the setup-node step with actions/setup-python@v5 and the npm commands with pip and pytest. The structure is identical — just different setup actions and commands.


Part 3: Using Secrets Safely

Secrets are credentials, API keys, and other sensitive values that your workflow needs but absolutely cannot be hardcoded in the YAML file. A YAML file in a public repository is public. Putting an API key directly in it means that key is visible to everyone on the internet.

GitHub Secrets solve this. They are stored encrypted in your repository settings and injected as environment variables into your workflow at runtime.

Adding a Secret

  1. Go to your repository on GitHub.
  2. Click Settings > Secrets and variables > Actions.
  3. Click New repository secret.
  4. Name it (all caps, underscores: MY_API_KEY) and paste the value.
  5. Save it.

Using a Secret in a Workflow

- name: Deploy
  env:
    API_KEY: ${{ secrets.MY_API_KEY }}
  run: ./deploy.sh

${{ secrets.MY_API_KEY }} is the syntax for referencing a secret. GitHub replaces it with the actual value at runtime and masks it in the workflow logs — if the value is accidentally printed to the log, it shows as *** instead of the real key.

Never echo a secret directly or pass it as a command-line argument in a way that appears in the process list. The masking in logs is a safety net, not a license to handle secrets carelessly.

Part 4: Saving Build Outputs as Artifacts

Running tests is useful. Having something to download after the workflow runs is even more useful — a compiled binary, a generated APK, a documentation site. GitHub Actions can save these as artifacts that appear in the workflow run summary and can be downloaded directly.

- name: Build project
  run: npm run build

- name: Upload build artifact
  uses: actions/upload-artifact@v4
  with:
    name: build-output
    path: ./dist/
    retention-days: 7

actions/upload-artifact@v4 takes whatever is in the specified path and saves it to GitHub's artifact storage. After the workflow finishes, anyone with access to the repository can go to the workflow run and download the artifact directly from the browser. No separate file hosting, no manual uploads.

retention-days: 7 tells GitHub to delete the artifact after seven days. The default is 90 days. Artifacts count against your GitHub storage limit, so setting a sensible retention period matters if you run builds frequently.

Part 5: A Unity Build Workflow

This is the section specific to this blog's audience. Getting an automated Unity build running on GitHub Actions requires a few extra steps compared to a standard web project, mainly because Unity needs a license activated before it can build anything — even headlessly on a CI runner.

GameCI (game.ci) is the most widely used open-source collection of GitHub Actions for Unity. It handles license activation and deactivation automatically, runs in a Docker container with Unity pre-installed, and supports all major build targets.

Prerequisites

  • Your Unity project is in a GitHub repository (covered in the Git guide).
  • You have a Unity Personal or Pro license. Free Personal licenses work with GameCI.
  • Git LFS is enabled if your project contains large binary files (textures, audio, scenes).

Step 1: Get Your Unity License File

GameCI needs your Unity license as a secret. To get it:

  1. Add this workflow file to your repository temporarily:
name: Acquire Activation File
on: [push]
jobs:
  getManualLicenseFile:
    runs-on: ubuntu-latest
    steps:
      - uses: game-ci/unity-request-activation-file@v2
      - uses: actions/upload-artifact@v4
        with:
          name: Manual Activation File
          path: ./*.alf
  1. After the workflow runs, download the .alf artifact from the run summary.
  2. Go to license.unity3d.com, upload the .alf file, and download the resulting .ulf license file.
  3. Add your license file content as a GitHub Secret named UNITY_LICENSE.
  4. Add your Unity email as UNITY_EMAIL and password as UNITY_PASSWORD.
  5. Delete the temporary activation workflow file.

Step 2: The Build Workflow

name: Unity Build

on:
  push:
    branches: [main]

jobs:
  build:
    name: Build for ${{ matrix.targetPlatform }}
    runs-on: ubuntu-latest

    strategy:
      matrix:
        targetPlatform:
          - StandaloneWindows64
          - Android

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          lfs: true

      - uses: actions/cache@v4
        with:
          path: Library
          key: Library-${{ matrix.targetPlatform }}-${{ hashFiles('Assets/**', 'Packages/**', 'ProjectSettings/**') }}
          restore-keys: |
            Library-${{ matrix.targetPlatform }}-
            Library-

      - uses: game-ci/unity-builder@v4
        env:
          UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
          UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
          UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
        with:
          targetPlatform: ${{ matrix.targetPlatform }}

      - uses: actions/upload-artifact@v4
        with:
          name: Build-${{ matrix.targetPlatform }}
          path: build/${{ matrix.targetPlatform }}

What This Workflow Does

strategy: matrix: targetPlatform: runs the job once for each platform listed, in parallel. Both StandaloneWindows64 and Android builds run at the same time rather than sequentially, halving the total time compared to running them one after another.

lfs: true on the checkout step pulls Git LFS objects during the checkout. Without this, large binary assets from LFS are missing from the build and Unity throws import errors.

actions/cache@v4 caches Unity's Library folder between runs. Unity regenerates this folder from scratch if it is missing, which takes several minutes on a large project. Caching it cuts build time significantly after the first run. The cache key includes hashes of your Assets, Packages, and ProjectSettings directories, so it invalidates correctly when those change.

game-ci/unity-builder@v4 handles the actual build. It activates the license, runs Unity headlessly with the correct build target, and deactivates the license when done.



Free Tier and Pricing

GitHub Actions is free for public repositories and gives private repositories 2,000 free minutes per month on the Free plan. Minutes are consumed based on the runner type — ubuntu-latest counts at 1x, windows-latest at 2x, and macos-latest at 10x. A Unity build that takes ten minutes on ubuntu-latest costs ten minutes. The same build on macos-latest costs 100 minutes.

For a solo developer with one or two Unity projects, 2,000 minutes per month is usually enough if you are building on Linux. IL2CPP builds targeting Windows or macOS are CPU-intensive, and GitHub-hosted runner minutes can add up fast on large projects — self-hosted runners are worth considering once build frequency scales up. A self-hosted runner is just a machine you own or rent that registers itself with GitHub and runs workflows locally instead of on GitHub's infrastructure.

Paid plans for GitHub Actions exist as part of GitHub's overall plans (Pro, Team, Enterprise) and add more monthly minutes rather than changing the feature set.

Things That Will Trip You Up

The YAML indentation is wrong and the workflow fails to parse.

YAML is whitespace-sensitive and GitHub's error messages for YAML syntax errors are not always pinpointing the exact problem. Use a YAML linter (yamllint.com or the YAML extension in VS Code) to validate your workflow file before pushing. Two-space indentation everywhere is the convention — mixing spaces and tabs causes parse errors that are invisible to the human eye.

The workflow runs but steps fail with "command not found."

The runner is a fresh Ubuntu/Windows/macOS machine with no custom tools pre-installed. Anything beyond the basics needs a setup step. If you need Python, add actions/setup-python. If you need the Unity Editor, use game-ci. Check what is pre-installed on each runner type in GitHub's documentation before assuming a tool is available.

Secrets are showing as empty strings in the workflow.

Secret names are case-sensitive. UNITY_LICENSE and unity_license are different secrets. Double-check the name in Settings matches exactly what you wrote in the YAML. Also confirm the secret was saved to the repository, not to an organization or environment with different access rules.

The Unity build fails with a license activation error.

Either UNITY_EMAIL, UNITY_PASSWORD, or UNITY_LICENSE is wrong, or the license has expired or been revoked. Unity Personal licenses require periodic reactivation. If the build was working and suddenly starts failing, check when the license was last activated and whether it needs renewal.

The cache is not being used between runs.

The cache key needs to match exactly for a cache hit to occur. If your Assets directory changed since the last run, the key changes and the cache misses — this is correct behavior, not a bug. If the cache is never being used even on unchanged code, check whether the cache key expression is evaluating correctly by looking at the "Post cache" step output in the workflow log.



What to Build Next

The workflows in this guide cover the basics. Once they are running reliably, a few natural extensions:

Automatic releases. Add a step using softprops/action-gh-release that creates a GitHub Release and attaches the build artifacts whenever you push a tag. One git tag push produces a versioned release with downloadable builds automatically.

Scheduled workflows. Set a workflow to run on a cron schedule (every night at midnight, for example) to catch any drift or dependency issues that appear over time even without active development.

Multiple environments. Use GitHub Environments (Settings > Environments) to create separate configurations for staging and production, with different secrets and optional approval requirements before a deployment can proceed.

None of those are difficult once the basic workflow structure is familiar. The YAML syntax is the steepest part of the learning curve, and it stops feeling foreign fairly quickly once you have read and modified a few working examples.

Next Topics To Learn

Tuesday, 28 July 2026

How to Use ElevenLabs for Game Development: AI Voice Acting, NPC Dialogue, and Sound Design

Most indie games ship without voice acting. Not because developers do not want it, but because hiring voice actors is expensive, scheduling them is slow, and revising recorded lines after the script changes means paying them again. So the game gets subtitles and silence, and it is a little bit flatter for it.

ElevenLabs has made this calculation genuinely worth revisiting. The voice quality is not "pretty good for AI." On certain voice types and delivery styles it is difficult to distinguish from a recorded human performance without a direct A/B comparison. It is not perfect across the board, but it is good enough that the question "should I voice my game?" now has a different answer for solo developers than it did two years ago.

This guide covers what ElevenLabs can and cannot do for game development specifically, how the credit and pricing system actually works, how to set up a voice cloning workflow for consistent character voices, and how to get the audio into Unity.



What ElevenLabs Does

ElevenLabs converts text to speech using AI models trained on large amounts of human voice recordings. You type a line of dialogue, pick a voice, and get an audio file back. The voices have natural variation in pacing, emphasis, and emotional tone — not the flat robotic cadence of older TTS systems.

There are three main ways to get voices:

  • Pre-made voices — a library of built-in voice options across different accents, ages, and tones. No setup required.
  • Voice Design — generate a synthetic voice with specific characteristics (age, accent, tone, gender) without providing any recording. Good for creating unique character voices that do not sound like a specific real person.
  • Voice Cloning — upload recordings of a real voice (your own, a voice actor's with permission, or a custom character recording) and generate new lines in that voice.

For game development, Voice Design and Voice Cloning are where the practical value lives. The pre-made voices are fine for narrators and generic NPCs, but any character who appears repeatedly needs a consistent, distinctive voice — which means either picking one pre-made voice and sticking to it, or cloning a voice specifically for that character.



Pricing and the Credit System

ElevenLabs bills based on credits. Credits are consumed by every generation, with different models and quality settings costing different amounts per character of text. The relationship between credits and usable audio time is not straightforward, and the pricing page is not the most transparent thing to read.

Here is what the relevant tiers actually get a solo game developer, as of mid-2026:

Plan Monthly Price Credits Approx. Audio Commercial Rights Voice Cloning
Free $0 10,000/month ~10 min (Multilingual) or ~20 min (Flash) No — attribution required No
Starter $5/month 30,000/month ~30 min (Multilingual) or ~60 min (Flash) Yes Instant cloning only
Creator $22/month 100,000/month ~100 min (Multilingual) Yes Professional cloning
Pro $99/month 500,000/month ~500 min Yes Professional cloning

Two things about this table worth flagging before you make any decisions.

First: the free plan has no commercial usage rights. Content created on the free plan requires ElevenLabs attribution and cannot be used in a monetized product, client work, or anything revenue-adjacent. For a game you plan to sell or distribute through any store, you need at minimum Starter at $5/month. This trips up a lot of people who test the free tier, like the results, and then discover the fine print when they try to ship.

Second: instant voice cloning versus professional voice cloning is a meaningful quality difference. Instant cloning works from a minute or two of audio and is available on Starter. Professional cloning requires more training data and is available from Creator upward — it produces more stable, natural results across long dialogue sessions. For a main character who speaks hundreds of lines, professional cloning is worth the upgrade. For a minor NPC with a dozen lines, instant cloning is probably fine.

Annual billing saves roughly 17% across all tiers. Always verify current pricing at elevenlabs.io before subscribing — plans and credit allocations change frequently and the pricing page is the authoritative source.



Part 1: Setting Up a Character Voice

The fastest way to get started is using one of the pre-made voices from the Voice Library. Go to the Voices section, browse by category (narrator, villain, young adult, and so on), preview them, and save the ones that feel right for your character types. Each saved voice appears in your generation panel.

For characters who need a distinctive, custom voice, Voice Design is the better option.

Voice Design Workflow

  1. Go to Voices > Voice Design in the ElevenLabs interface.
  2. Describe the voice in the text prompt: "A gruff middle-aged man, slightly raspy, slight Eastern European accent, sounds like he has seen too much war." ElevenLabs generates multiple voice variants matching that description.
  3. Preview each variant with a sample line. Generate more variants until one fits.
  4. Save the voice to your voice library. It now appears in every generation panel as a selectable option.

Voice Design voices are synthetic — they are not trained on or derived from any specific real person's recordings. They are consistent across generations, unlike a cloned voice that can sometimes drift slightly on unusual phoneme combinations.

Instant Voice Cloning (Starter and Above)

If you want to record your own voice and use it as a character voice, or if you have hired a voice actor for a short session and want to generate additional lines without rebooking:

  1. Go to Voices > Add a New Voice > Instant Voice Clone.
  2. Upload 1-3 minutes of clean audio with minimal background noise. A phone recording works; a recording with music underneath does not.
  3. Name the voice and save it.
  4. Generate new lines in that voice.

For instant cloning, one to three minutes of clean mono audio at 22 kHz or higher produces a usable clone. The voice holds up for short lines but can sound slightly off on very long sentences or unusual phrases. Test across a range of your actual dialogue before committing to it for a main character.

Part 2: Generating Dialogue

Go to Text to Speech in the navigation. Select your character voice, paste a dialogue line, and generate. The output is a .mp3 or .wav file you can download immediately.

Settings That Change the Output

Setting What It Does Game Dev Starting Point
Model Eleven Multilingual v2 for best quality; Flash v2.5 for faster/cheaper generation at slightly lower quality. Use Multilingual for final lines, Flash for draft review.
Stability Higher stability = more consistent but flatter delivery. Lower = more expressive but can drift between generations. 0.4-0.6 for most NPC dialogue. Lower for emotional scenes.
Similarity Boost For cloned voices, how closely the output matches the original recording. Higher values can cause artifacts. 0.7-0.8. Above 0.9 often sounds unnatural.
Style Exaggeration Emphasizes the speaking style in the voice. Can add character but also amplify oddities. 0-0.3 for normal dialogue. Higher for stylized characters.

The Speaker Boost checkbox is worth enabling for any voice that sounds slightly muddy on playback — it adds a processing pass that clarifies the audio. It costs slightly more credits per generation.

Directing Delivery Through Text

ElevenLabs does not have a separate emotion selector for most models. You direct the emotional delivery through the text itself — punctuation, pacing cues, and in some cases explicit stage direction in brackets.

These techniques actually work:

  • Ellipsis for hesitation: "I... I don't know what to say."
  • Capitalization for stress: "I told you NOT to open that door."
  • Dashes for interrupted speech: "Wait, before you go — listen to me."
  • Brackets for tone direction (Eleven v3): "[whispering] They're still out there."

The bracket-based direction is a v3 feature and not available on all models. Test which techniques work on your specific voice and model combination rather than assuming all of them apply.

Part 3: Getting Audio Into Unity

Unity supports .mp3 and .wav imports directly. The workflow is simple but there are a few things that will save you time at scale.

Basic Import

  1. Download generated audio as .wav (higher quality, larger file) or .mp3 (smaller, fine for most dialogue).
  2. Drag into a designated folder in your Unity Project window — something like Assets/Audio/Dialogue/CharacterName/.
  3. Select the imported clip and check the Inspector settings: set Compression Format to Vorbis for dialogue (better compression than PCM), set Load Type to Streaming for long files or Decompress on Load for short lines.
  4. Assign to an AudioSource component in your NPC's script, or reference it in your dialogue system's audio playback logic.

Managing a Large Dialogue Library

A game with dozens of NPCs and hundreds of dialogue lines generates a lot of audio files. A naming convention from the start prevents the folder from becoming unmanageable:

NPC_Guard_Line001_Idle.wav
NPC_Guard_Line002_Alert.wav
NPC_Merchant_Line001_Greeting.wav

If your dialogue system uses a ScriptableObject-based structure (covered in the ScriptableObjects guide from this series), you can store AudioClip references directly in the dialogue data assets alongside the text. This keeps dialogue text and audio tied together in the same place rather than scattered across separate folders that drift out of sync as the script changes.

What Works Well and What Does Not

ElevenLabs is genuinely impressive for certain voice types and delivery styles. Calm narration, conversational NPC chatter, villain monologues with measured delivery, elderly characters with gravelly voices — these tend to come out well without much tweaking.

It struggles with:

  • Shouting and extreme emotion. Screaming, rage, and intense fear often come out sounding strained or artificial. These are the lines worth recording with a real voice actor if any lines in your game are.
  • Non-English phonemes in otherwise English text. A character name like "Xrathul" or a place name like "Aelionthar" will be mispronounced in ways that vary between generations. Test proper noun pronunciation early.
  • Very long lines without natural pause points. Lines over 200-300 characters sometimes have pacing issues. Break long dialogue into multiple shorter generations and edit them together in an audio editor if needed.
  • Singing. ElevenLabs has a music feature but it is not designed for character singing in the way game vocals usually work. For anything sung, a real recording remains the practical option.

The Sound Effects Generator is worth knowing about but is not a replacement for a proper game audio library. It generates short sound effects from text prompts — "heavy wooden door creaking open," "distant thunderstorm," "coins dropping on stone floor." The results are inconsistent. Sometimes usable, sometimes clearly artificial. Worth testing on any specific sound you need and cannot source elsewhere, but not something to build a full audio pipeline around.



ElevenLabs vs Alternatives

Tool Strengths Weaknesses Price
ElevenLabs Best overall voice quality in 2026, voice cloning, large voice library, good emotional range on supported delivery styles. No commercial rights on free tier, credit system is confusing, struggles with extreme vocal delivery. Free; $5/month (Starter); $22/month (Creator)
Murf AI Clean interface, good for narration and corporate-style voices, integrated editing tools. Lower emotional range than ElevenLabs, less convincing for character acting versus narration. Free tier; paid from $19/month
Play.ht Wide voice selection, API-friendly for automation, good multilingual support. Quality ceiling slightly below ElevenLabs on character voices. Free tier; paid from $31/month
Real voice actors Authentic delivery, natural extreme emotion, human direction, fully licensable. Cost, scheduling, revision cycles, not scalable for large NPC casts on indie budgets. $100-500+ per hour session

The honest comparison to real voice actors is worth thinking through rather than dismissing. For a protagonist with 500+ lines across 20 hours of gameplay, ElevenLabs is not going to produce the same emotional performance a professional actor would. For 50 lines of ambient dialogue across 30 different minor NPCs, it absolutely is the practical choice.

Common Problems

The voice sounds right sometimes but inconsistent across multiple generations of the same line.

Stability is too low. Raise the Stability slider toward 0.6-0.7. If consistency still varies, the voice itself may be inherently unstable on this model — try a different model (Multilingual v2 tends to be more consistent than Flash for character work) or regenerate and use the most consistent take.

Proper nouns and character names are being mispronounced.

Spell them phonetically in the text input. "Xrathul" becomes "Zrathool" or "Zr-ath-ul" depending on which phonetic spelling produces the correct sound on your specific voice. Test phonetic spelling early in production — going back through hundreds of lines to fix a name pronunciation is slow.

The audio has a slight robotic or unnatural quality at certain points.

Speaker Boost is the first thing to try — it adds clarity and reduces the uncanny valley quality on some voices. Also check whether the model is set to Flash (faster, lower quality) rather than Multilingual v2. For voice clones specifically, lowering Similarity Boost from above 0.85 to around 0.75 often improves naturalness.

Free tier audio cannot be used in the game.

This is not a technical problem, it is a terms of service issue. The free tier has no commercial usage rights. Upgrade to at least Starter ($5/month) before generating any audio you intend to include in a distributed or monetized game.



A Practical Dialogue Pipeline for Solo Developers

This is the workflow that makes ElevenLabs actually manageable when you have more than a handful of lines to generate.

  1. Finalize the script first. Generate audio for lines that are locked. Generating audio for dialogue that later changes costs credits twice and creates file management headaches.
  2. Create one voice per major character. Either a pre-made voice you have tested across a range of line types, a Voice Design voice you have generated and saved, or a cloned voice. Stick to it throughout production.
  3. Generate in batches by character. Generate all lines for one character in one session while the settings and voice are loaded. Switching between characters mid-session wastes time on setup and makes it harder to catch inconsistencies.
  4. Name files consistently from the start using the convention described above. No renaming later.
  5. Keep a generation log. A simple spreadsheet with line ID, text, voice used, generation date, and Unity file path. When the script changes and you need to regenerate specific lines, you can find exactly which file needs replacing without listening through everything.

What to Do With It Now

Create a free account at elevenlabs.io — no credit card required. Generate ten lines using the pre-made voice library to get a feel for quality before worrying about custom voices or cloning. Try the same line with different Stability settings to see how much that single slider changes the output. Then try Voice Design with a specific character concept from your current project.

If the quality is good enough for your game's dialogue needs, upgrade to Starter before generating anything you plan to actually ship. Five dollars a month for commercial rights and thirty minutes of high-quality dialogue audio per month is genuinely good value for an indie developer.

Next Topics To Learn

How to Use Figma for Game UI Design: Mockup, Export, and Bring It Into Unity

Most Unity developers design UI directly in the Unity Canvas. You drag in a Panel, add some buttons, resize things until they look roughly...