Text Animator for Unity already contains the mechanism
that dialogue blips need. It is not a separate plugin,
and it is not a custom script. It is the
OnCharacterVisible event, which the plugin
fires every time a character becomes visible during the
typewriter effect, and which passes the revealed
char as a parameter[reference:0]. A developer
who subscribes to that event and plays a blip in the
callback has implemented dialogue blips, without
building a custom dialogue system or writing a
character-by-character reveal loop.
This is different from the approach in the generic typewriter blip guide, which assumes the developer controls the reveal loop and can count characters manually. Text Animator owns the reveal loop. The integration is therefore a matter of hooking into an event that the plugin already provides, and configuring the sound playback so that it respects the rate at which the plugin reveals characters.
This article covers three integration paths, in order
of complexity: the built-in OnCharacterVisible
event with a minimal playback script, the official
TypeWriter Sounds example package that the plugin ships
with, and the newer Dialogue Sounds Toolkit for
projects that need layered dialogue audio beyond simple
blips. The blip design itself is covered in the
square-wave synthesis guide
and the
genre-specific frequency guide.
What does the OnCharacterVisible event actually provide?
The event is defined on the typewriter component, which
is added to the same GameObject as the
TextAnimator component[reference:1]. It fires
once per character as the text is revealed, and it
passes the character itself as a char
parameter. The documentation states explicitly that the
event “passes a char as a parameter, so you can play
different sounds based on different letters as
well”[reference:2].
The event has one important edge case: it also fires on spaces. The documentation warns that “the event is triggered on spaces too, so play sounds according to the character type you prefer”[reference:3]. For blips, the practical consequence is that the callback should check whether the character is alphanumeric before playing a sound. A blip on a space sounds like a stutter, and the player will notice it immediately.
The typewriter component comes in two variants:
TypewriterByCharacter, which reveals one
letter at a time, and TypewriterByWord,
which reveals word by word[reference:4]. The
OnCharacterVisible event exists on both,
but the practical behavior is different. With
TypewriterByCharacter, the event fires once
per letter and the blip rate is whatever the reveal
speed dictates. With TypewriterByWord, the
event may fire once per word or per character depending
on the internal implementation, and the blip timing
becomes less predictable. For dialogue blips,
TypewriterByCharacter is the correct
choice.
The reveal speed is controlled by the typewriter's settings, not by the blip code. A typewriter that reveals 30 characters per second will fire the event 30 times per second, which means a naive “play a blip on every event” implementation would produce 30 blips per second. The Web Audio blip tutorial describes why this is above the rate at which the ear can distinguish individual events. The callback needs to throttle itself.
How do you write the minimal integration script?
The script has three responsibilities: subscribe to the event, check whether the character should trigger a blip, and play the blip with a minimum delay between playbacks. The minimum delay is the parameter that prevents the blip rate from matching the character rate.
using Febucci.UI.Core;
using UnityEngine;
public class DialogueBlips : MonoBehaviour
{
[SerializeField] TypewriterCore typewriter;
[SerializeField] AudioSource blipSource;
[SerializeField] AudioClip[] blipClips;
[SerializeField] float minSoundDelay = 0.06f;
private float lastBlipTime = -999f;
void OnEnable()
{
typewriter.onCharacterVisible.AddListener(OnCharacterVisible);
}
void OnDisable()
{
typewriter.onCharacterVisible.RemoveListener(OnCharacterVisible);
}
void OnCharacterVisible(char c)
{
// Skip spaces and punctuation
if (!char.IsLetterOrDigit(c)) return;
// Throttle: enforce a minimum gap between blips
if (Time.time - lastBlipTime < minSoundDelay) return;
lastBlipTime = Time.time;
// Play a random clip from the array
if (blipClips.Length == 0) return;
var clip = blipClips[Random.Range(0, blipClips.Length)];
blipSource.PlayOneShot(clip);
}
}
The minSoundDelay is set to 0.06 seconds in
the example, which produces a maximum blip rate of
about 16 blips per second. That is within the range
that the ear can distinguish as separate events, and it
is below the rate at which the blips start to merge into
a continuous tone. The
typewriter blip guide
recommends a target rate of 8 to 15 blips per second;
0.06 seconds sits at the upper end of that range and is
a reasonable default for a typewriter that reveals
around 40 characters per second.
The character check is doing more work than it appears.
char.IsLetterOrDigit returns false for
spaces, punctuation, and most special characters. This
means the blip fires only on letters and numbers, which
is the behavior most dialogue systems use. A developer
who wants punctuation to produce a different sound (a
longer blip on a period, for example) can replace the
check with a switch on the character type and play a
different clip for each category.
The AudioSource.PlayOneShot call is the
right playback method because it allows overlapping
blips. If the typewriter reveals characters faster than
the blip's duration, the previous blip is still playing
when the next one starts, and PlayOneShot
mixes them rather than interrupting. The
mix hierarchy guide
covers the bus routing that keeps the blips at a
consistent level relative to the dialogue voice and the
music.
What does the official TypeWriter Sounds package provide?
Text Animator ships with an example package called “TypeWriter Sounds” in the “Extra” folder. The documentation for the 2.x version describes it as a reference implementation that demonstrates the same pattern as the minimal script above, with four additional parameters that make it more configurable [reference:5].
| Parameter | Purpose |
|---|---|
| Source | The AudioSource that plays the blips |
| Min Sound Delay | Minimum time before another sound can play |
| Interrupt Previous Sound | Whether a new blip stops the previous one |
| Random Sequence | Random clip selection vs. sequential |
The Min Sound Delay parameter is the same
throttle as the minSoundDelay in the
minimal script. The Interrupt Previous Sound
parameter is the one that changes the character of the
blip set: when true, the blips are tightly packed and
each one cuts off the previous one, which produces a
staccato, mechanical feel. When false, the blips overlap
and the sound is smoother. For most dialogue, false is
the right choice, because the overlapping blips merge
into a continuous texture rather than a series of
discrete ticks.
The Random Sequence parameter controls
whether the clips are chosen randomly or played in
order. Random is the default for dialogue blips,
because the sequential order becomes predictable after
the first cycle. The
randomized blip variation guide
covers the distribution question in detail; the
practical setting for a dialogue system is random
selection with a pool of at least four clips.
The example package is a starting point, not a complete solution. It does not handle per-character blips (the character parameter is ignored), it does not differentiate between letters and punctuation, and it does not provide a way to change the blip set based on the speaking character. Those features require either extending the example script or using the Dialogue Sounds Toolkit described below.
What does the Dialogue Sounds Toolkit add that the built-in package does not?
The Dialogue Sounds Toolkit is a separate asset created by the same developers as Text Animator. Its purpose is to handle the parts of dialogue audio that the built-in example package does not: per-character voices, layered effects, and the organization of a large sound library[reference:6].
The toolkit is not a replacement for Text Animator. It is designed to work alongside it, and its documentation states that it “works great together with Text Animator for Unity”[reference:7]. The integration is the same pattern as the minimal script: the toolkit subscribes to the typewriter's events and plays sounds based on what the typewriter reveals.
The features that justify the toolkit over the built-in package are specific. It provides 40 sounds across 8 categories with 400 variations in the base library [reference:8]. It supports Selector and Parallel clips, which allow layered dialogue audio (a blip plus a breath plus a room tone, for example) rather than a single clip per character[reference:9]. It includes per-character behavior, which means each speaking character can have a different blip set without separate scripts[reference:10]. And it provides ordered effect chains for reverb, EQ, pitch shifting, and other processing, which are applied at the dialogue audio level rather than in a DAW[reference:11].
The toolkit is $21 at the time of writing, discounted from $30[reference:12]. For a project that needs layered dialogue audio or per-character voices, the toolkit replaces what would otherwise be a custom implementation, and the cost is justified by the saved development time. For a project that needs simple blips on a single character, the built-in example package or the minimal script is sufficient, and the toolkit is not necessary.
How do you adjust the blip set when the text speed changes?
Text Animator allows the reveal speed to be changed at
runtime, either through the typewriter's settings or
through the player's text speed preference. A blip
script that uses a fixed minSoundDelay
will produce a different blip density when the text
speed changes, because the character rate changes while
the throttle does not.
The fix is to tie the minSoundDelay to the
typewriter's current reveal speed. A text speed of 30
characters per second produces 30 events per second, so
the blip throttle should be set to produce a target of
10 to 15 blips per second regardless of the text speed.
The formula is straightforward: if the typewriter is
revealing N characters per second and the
target blip rate is 10, the throttle should allow a
blip every N / 10 characters.
// In the callback, instead of a fixed time throttle:
private int characterCount = 0;
private int blipEveryNChars = 3; // adjusted based on text speed
void OnCharacterVisible(char c)
{
if (!char.IsLetterOrDigit(c)) return;
characterCount++;
if (characterCount % blipEveryNChars != 0) return;
// play blip
}
The blipEveryNChars value should be
recalculated whenever the text speed changes. At the
default text speed of 30 characters per second and a
target of 10 blips per second, the value is 3. At a
fast text speed of 60 characters per second, the value
becomes 6. At a slow text speed of 15 characters per
second, the value becomes 2 (rounded from 1.5, because
a blip every character at 15 characters per second is
still 15 blips per second, which is at the upper end of
the acceptable range).
The per-character counting approach is the one that the typewriter blip guide recommends for any character-by-character reveal system. The time-based throttle is simpler to implement, but it does not adapt to text speed changes, and the player who changes the text speed will notice the blip density change even if they do not consciously identify it as a problem.
What happens when the dialogue also has voice acting?
Text Animator does not know whether the dialogue line has a voice track. The typewriter reveals characters regardless of whether there is a voice speaking, and the blip script will play blips regardless of whether there is a voice. The result is a dialogue system where a voiced line produces both the voice and the blips, which is usually the wrong sound.
The standard fix is to disable the blips when the voice track is present. The dialogue system that feeds text to Text Animator usually knows whether a line is voiced, and it can pass that information to the blip script. The script then checks a boolean before playing each blip, and skips playback when the line is voiced.
public bool IsVoiced { get; set; }
void OnCharacterVisible(char c)
{
if (IsVoiced) return;
// ... rest of the blip logic
}
The alternative is to keep the blips but reduce their volume during voiced lines. A reduction of 12 to 18 dB is the range that makes the blips present as a subtle texture rather than a competing layer. The ducking guide covers the sidechain approach that automates this reduction based on the voice track's level.
The choice between disabling and reducing depends on the game's aesthetic. A visual novel with full voice acting usually disables the blips, because the voice is doing the work that the blips would otherwise do. A game with partial voice acting (grunts and exclamations rather than full lines) keeps the blips at full volume and lets the voice and the blips coexist. The visual novel blip guide covers the specific considerations for the first case.
The integration between Text Animator and a dialogue
system that knows about voice acting is straightforward,
because Text Animator is not the system that owns the
voice. The dialogue system owns both the text and the
voice, and it can set the IsVoiced property
on the blip script before calling
typewriter.ShowText(textValue). The blip
script does not need to know where the information came
from; it only needs the boolean.
Text Animator provides the event that makes dialogue
blips possible. The integration is not a custom dialogue
system, and it is not a separate plugin. It is a
subscription to OnCharacterVisible, a
character check, and a throttle. The built-in example
package and the Dialogue Sounds Toolkit are optional
extensions for projects that need more than the minimal
script, but the minimal script is enough to produce
dialogue blips that match the quality of the rest of the
UI audio, and it is the starting point that any
Text Animator project should begin with.
Generate the Blip Clips for the Script
Open the SfxMaker blip generator and create a small
set of four to six blips at the 1000–1400 Hz range,
with a sine or triangle waveform and a 30–50 ms
duration. These are the clips that the
blipClips array in the minimal script
will reference, and the set is large enough for
random selection to sound varied without requiring
a large library.