Skip to content
/a/ FaceCue Performance Studio

The Cue Registry

How the runtime finds the bake for a clip. The naming rule, the registry window, and Addressables as the alternative.

Baking writes a cue file. It does not tell the game the file exists. The registry is what closes that gap, and it is the one step between a successful bake and a character that actually speaks.

What the Registry Does

A registry is an asset holding a table: which clip has cues, and where those cues live.

At play time a character does not go looking through your project for a file. It takes the name of the clip that just started and asks the registry for that name. If the registry has it, the cues load. If it does not, the mouth stays still.

That is the whole mechanism, and its simplicity is the point. There is no path to keep in sync, no folder layout to preserve, and moving a cue file inside your project breaks nothing as long as the registry still knows about it.

The Cue Registry window, showing two groups of clips with their phoneme and emotion files

A registry with two groups. Each row pairs a clip with the cue files that belong to it.

Two Ways to Hold a Clip

A registry sorts its clips into groups, and the group a clip is in decides when its cues reach memory.

Streamable groups are the ordinary case. The registry holds the names and leaves the cue data on disk until something plays, so a project with thousands of baked lines carries a list at runtime and not thousands of cue files. Each streamable group is its own asset, so a group loads as a unit and only when it is wanted.

The Auto-Load Group is the one you opt into. Its clips come in with the registry itself and stay resident, which suits lines that are used constantly and have to be there the instant they are asked for, a character's barks being the clearest case.

FaceCue keeps track of which group holds which clip, so finding one never means opening every group, and it keeps that up to date for you.

Neither One Is Expensive

Cue data is text, and not much of it. A line of dialogue bakes to something in the tens of kilobytes, so a resident group of them is a rounding error next to the audio it goes with, let alone the meshes and textures around it.

Resolving a clip costs nothing either way. The registry reaches its groups directly, with no Addressables machinery in the path, and at most loads the one group that holds it.

The number worth watching is how many clips sit in one group. An Auto-Load Group's clips come in together and stay, and a streamable group comes in whole the first time any of its lines plays. Splitting by chapter or content pack keeps every group small on its own, which is the same thing you would do for tidiness.

The First Time a Line Plays

A Cue Registry's streamable group loads the first time one of its lines plays, and stays loaded from then on. Loading is quick, too quick to notice on most devices, but on very low-end or older mobile devices it can show as a brief, millisecond-long stall on that line's first frame.

The Speaker Context's On First Load, under Cue Loading's Streamable Groups, decides how that first load happens:

On First Load What happens
Wait To Load The group loads on the line's first frame, and the face is in step from the start
Load In Background The group loads without holding up a frame, and the face joins the line a moment later, fully in step
Auto Loads in the background where there's time, and waits only for what is still missing when the line's first cue arrives, so the face is in step from the start

Auto, the default, suits most projects. In the editor it behaves as Wait To Load. Building a player updates the registry asset with what Auto needs, so commit that change like any other.

Lines found through Addressables or a loader of your own always load on their first frame.

A Very Large Streamable Group

The registry is fast, but a streamable group holding thousands of lines, left to load when its first line plays, can still cause a small stall, or have that line's face join a moment late. Split large groups by scene, episode or chapter, or better, load them ahead of time when the game or a scene starts, as described next.

Loading Ahead of Time

When you know which lines are coming, such as the next scene's dialogue or a conversation about to start, load them before they play, a whole group at once or a line at a time. Either way, a line starts with its cues in place, whatever On First Load is set to.

A Whole Group

The calls are on the registry itself. A script that keeps a registry in a field asks it for the names of its streamable groups, the same names the Cue Registry window shows, and loads a group by name:

Member of FaceCueRegistry What it does
IReadOnlyList<string> StreamableGroupNames { get; } The names of the registry's streamable groups, as the window shows them. Reading them loads nothing
bool PreloadGroup(string groupName) Loads the group now, in this call, and returns whether it loaded. For a loading screen
CueGroupPreload PreloadGroupAsync(string groupName) Starts loading the group in the background and returns a request to wait on. For use during play

A loaded group stays loaded for the rest of the run, and every character's lines from it start with it in place. Asking for it again costs nothing. A name the registry does not have loads nothing, and the Console says so, listing the names it does have.

The request works like Unity's own load requests:

Member of CueGroupPreload What it does
string GroupName { get; } The group the request loads
bool IsDone { get; } True once the request has finished, whether or not the group loaded
bool IsLoaded { get; } True when the group is loaded. Read it once the request is done
event Action<CueGroupPreload> Completed Raised once, on the main thread, when the request finishes. A handler added later is called at once
void WaitForCompletion() Finishes the request now, in this call
public FaceCueRegistry registry;

System.Collections.IEnumerator Start()
{
    yield return registry.PreloadGroupAsync("Chapter 2");
}

The package's Preload Cue Groups On Load example does this without code. Find it in FaceCue's Examples/CueLoading folder, add it to an object in the scene, give it your registries, pick the groups to load from its Groups To Load dropdown, and choose whether they load in the background. It loads them when its object starts.

A Single Line

The calls are on the FaceCue Brain, and the same calls are on its Speaker Context:

Member What it does
bool PreloadCues(AudioClip clip) Loads the line's cues now, in this call, and returns whether the clip has any. For a loading screen
bool PreloadCues(string clipId) The same, by the name the line's cue files were baked under
CuePreload PreloadCuesAsync(AudioClip clip) Starts loading the line's cues in the background and returns a request to wait on. For use during play
CuePreload PreloadCuesAsync(string clipId) The same, by the name the line's cue files were baked under

Loading one line of a streamable group loads the whole group, so the group's other lines start quickly too. Its request works the same way as a group's:

Member of CuePreload What it does
bool IsDone { get; } True once the request has finished, whether or not cues were found
bool HasCues { get; } True when the clip has cues for this character. Read it once the request is done
event Action<CuePreload> Completed Raised once, on the main thread, when the request finishes. A handler added later is called at once
void WaitForCompletion() Finishes the request now, in this call

Yield it from a coroutine, or, on Unity 2023.1 and later, await it:

System.Collections.IEnumerator SayLine(FaceCueBrain brain, AudioSource source, AudioClip line)
{
    yield return brain.PreloadCuesAsync(line);
    source.clip = line;
    source.Play();
}

async Awaitable SayLineAsync(FaceCueBrain brain, AudioSource source, AudioClip line)
{
    await brain.PreloadCuesAsync(line);
    source.clip = line;
    source.Play();
}

You don't have to wait for a preload to finish before the line plays. A line that starts while its cues or its group are still loading carries on from where the preload got to, then follows its character's On First Load setting.

The line calls belong to a character, on its FaceCue Brain or Speaker Context, so they need that character set up first: call them from its Start onward, not from Awake. The group calls belong to the registry and work at any time. Call all of them from the main thread.

A Timeline does this for itself. When a Timeline with FaceCue voice tracks starts in a player, the character begins loading the cues of every clip on them, so no clip loads its cues on the frame it begins.

The Naming Rule

The link between a clip and its cues is the clip's name.

When the baker runs, it writes <clip name>_phonemes.json beside the audio, plus <clip name>_emotions.json if anything in the line put an emotion on the character, such as emotion tags, or a laugh that brings one. When you add that file to a registry, the registry records the name with the suffix stripped. At play time the character looks up the name of the AudioClip that is playing.

So three things have to agree: the audio asset's name, the cue file's base name, and the entry in the registry. The baker gets all three right on its own. What breaks them is renaming afterwards.

Renaming Is the Common Failure

Rename an audio clip after registering it and the registry still holds the old name. Nothing errors at edit time, and the line plays silently wrong the next time you test it.

If you rename, re-add the clip to the registry, or rename the cue files to match and re-add. The registry window's own report will show you which entries no longer resolve.

One Suffix Is Ignored on Purpose

A clip name ending in _el is looked up without it, so barks_01_el finds the cues registered for barks_01. It is a convenience for audio exported from tools that append that suffix.

It also means a clip you genuinely wanted to call something_el will look for something. That is worth knowing before you name a file that way.

Making One

Open the Cue Registry window and use Registry Create Global Registry. That puts a registry where the runtime looks for it, and for most projects it is the only one you will ever need. Create Custom Registry…, in the same menu, lets you choose the name and location instead, which is what you want once you are splitting content across several.

Keep both under a Resources folder. That is where every part of a registry works, streamable groups included, and a registry saved there is placed in a FaceCue folder inside it for you.

Adding Clips

Bake, then use Add To Registry from the baker's Results row. That is the short path and it is the one to build a habit around, because it happens while you are already looking at the thing you just made.

Otherwise, open the Cue Registry window and add clips or whole folders to it. A batch adds as a folder, and the window groups the output by clip name for you, so registering 100 lines is the same amount of work as registering one.

If the clips you want are the ones you have just baked, Registry Import Last Bake takes the whole output folder in one go, which saves finding it again.

The Actions Menu

Everything the window does to a registry as a whole sits under Actions.

Action What it does
Create Global Registry Makes the one most projects need, where the runtime looks for it
Create Custom Registry… Makes one with a name and location you choose
Import Last Bake Takes in the folder the baker last wrote to
Validate Reports entries that no longer resolve, and cue files the registry has lost
Remove Orphans Clears out entries with no cue file assigned at all
Rebuild Index Rebuilds the lookup of which group holds which clip

Validation is the one to know about. It walks the registry and reports entries that no longer resolve, which is how a rename surfaces at edit time instead of as a silent mouth in a playtest. Auto-Validate keeps it running as you work, so the report stays current without you asking. Remove Orphans clears the entries with no cue file at all, and says how many before it does. An entry whose cue file has gone missing is not one of them. It gets relinked instead, covered next.

Missing Cue Files & Relinking

A registry holds each cue file by Unity's identity for that file, not by its name. When cue files reach a project without their .meta files, copied in from outside Unity for example, Unity gives them new identities, and the registry loses track of them even though they are right there in the project.

The window says so as soon as the registry opens. A banner at the top counts the missing files, and Relink Missing Cue Files finds each one again by its exact name, <clip name>_phonemes or <clip name>_emotions, never by a similar one. A name with a single match is relinked straight away, all in one undo. Where more than one file shares the name, you pick which.

Validate lists the same files one by one, as Cue File Missing, each with a relink of its own. One with no file of that name anywhere in the project is left as a note: bake the clip again, or assign its cue file by hand.

Being Told When a Registry Loads

A registry with problems raises a popup when it opens, listing what it found, with Validate one click away. It speaks up once per registry you open, not again after a script reload. Inform Me On sets what it takes to raise it: Nothing, Warnings, which is the default and includes errors, or Errors. It sits in the window's settings, beside Auto-Validate, and in the popup itself.

Rebuild Index is the rare one. FaceCue keeps the index current by itself, so you would reach for this only if a registry had been changed from outside the window and its index no longer matched its groups.

More Than One Registry

A project can hold as many registries as it likes, and most projects want more than one eventually, usually split by chapter, character or content pack.

Every registry kept under a Resources folder is found, so a character with no registry assigned still finds any clip in any of them. Nothing has to be nominated as the main one. Keep every registry there, ideally in Resources/FaceCue, where Create Global Registry puts it.

A Registry Outside Resources

A registry that ends up somewhere else, moved by mistake for example, is still found, but only its Auto-Load Group works. Streamable groups only load from under Resources, which is what lets their cue data stay on disk until a clip needs it, so move the registry back to use them.

A character can also be given a specific registry, which changes what happens when a clip is not in it:

Scope If the assigned registry does not have the clip
Preferred Falls back to the project-wide index and looks everywhere else
Exclusive Stops there. The clip does not resolve

Exclusive is the stricter setting and it exists for content that must not accidentally pick up cues from elsewhere, a downloadable pack being the clearest case.

Registries Have to Be Under Resources

A registry the runtime cannot reach in a build is not part of the index, and FaceCue looks for them the same way in the editor as it does in a player.

That is deliberate. Searching the whole project in the editor would find registries a build cannot, which is exactly the kind of difference that works all through development and fails on the device.

Addressables Instead

If your project already loads content through Addressables, cue files can go that way instead. Add To Addressables in the baker becomes available once the package is installed, and the cues load by address when the clip plays.

The address a character looks for is the clip's name with _phonemes or _emotions on the end, such as greeting_phonemes, and that is the address Add To gives each cue. A project that files its addresses under a folder of its own, such as VO/Mara/greeting_phonemes, sets that folder as the prefix, VO/Mara/, in the Speaker Context's Phoneme Cue Prefix and Emotion Cue Prefix, in the Addressables group under Cue Loading. That group shows only while the character's Cue Backend can use Addressables.

It is an alternative to the registry, not an addition to it. Neither is required to use FaceCue, and a project that keeps everything in Resources never needs Addressables at all.

The Registry Is the Faster Route

Use Addressables for cues when your project is already committed to it and you want everything loading the same way. It is the slower of the two, and the gap grows with the number of clips.

The reason is what each one does to find a cue. The registry holds the answer already and then reaches its group directly, with none of the address resolution or bundle bookkeeping that Addressables does per entry. That overhead is small once and noticeable across thousands of entries, and cues come in pairs, so a project with a few thousand baked lines is asking for several thousand addresses.

If you have no particular reason to route cues through Addressables, the registry is the one to pick.

When a Clip Will Not Load

A line plays and the mouth does not move. Work through these in order.

Check the Console first. When no registry or address holds the clip, FaceCue logs Cue Data Not Found the first time it happens on a character, naming the clip and its Look Up Chain, the places it looked, in order. The line then plays another way if it can, and Speech Fallback Engaged says which mode took over and why, while Speech Fallback FAILURE says why none could. Those messages usually end the investigation, and their absence is informative too: if nothing is logged, the clip never reached FaceCue and the problem is upstream.

Then, in order:

  1. Was it baked? Look for <clip name>_phonemes.json anywhere in the project. The baker writes it beside the audio unless Output Path sent it somewhere else.
  2. Was it added? Open the registry and search for the clip's name.
  3. Is its cue file missing? A banner at the top of the window says so. See Missing Cue Files & Relinking.
  4. Do the names match? The audio asset's name and the registry entry have to be identical. This is where a rename shows up.
  5. Is the registry under Resources? Outside it, only its Auto-Load Group loads.
  6. Is the character set to Exclusive with a registry that does not hold this clip? Switch to Preferred, or add the clip to that registry.

If all six pass and the mouth still does not move, the problem is no longer the registry. Playing It Back covers what else has to be true for a line to drive a face.