A single blip is a click with a pitch. It communicates the event, but it does not communicate the event's weight, direction, or aftermath. A button press that plays only a blip feels like a digital key on a calculator. A button press that plays a blip, a brief whoosh that arrives 20 milliseconds before it, and a soft impact that arrives 10 milliseconds after feels like a physical button on a real device. The information is the same in both cases, but the perceived quality is not.
Layering is the technique that turns a blip into a tactile event. It is the same principle that the weapon sound layering guide describes for combat sounds, applied to the much shorter timescale of a UI interaction. The layers are different, because the timescale is different, but the logic is the same: each layer contributes a specific quality that the others cannot provide, and the combination is more than the sum of the parts.
This article covers the three layers that are worth adding to a blip — the whoosh, the impact, and the sub-tone — the specific millisecond offsets that make each one support the blip rather than compete with it, and the UI events where the extra layers are worth the extra cost. The blip synthesis guide covers the core layer; this article is about what goes around it.
What does each layer actually contribute to a UI sound?
Each layer contributes a different quality, and the quality is the reason the layer exists. A layer that does not contribute a distinct quality is a layer that should be removed, because it only adds complexity without adding perceived richness.
| Layer | Quality it contributes | Frequency range | Duration |
|---|---|---|---|
| Blip (core) | The event itself — the pitch and the identity | 800–2000 Hz | 40–80 ms |
| Whoosh (lead-in) | Movement and approach — the sense that something arrived | 200–8000 Hz (sweeping) | 80–200 ms |
| Impact (weight) | Contact and mass — the sense that the event has weight | 80–400 Hz | 60–150 ms |
| Sub-tone (tail) | Aftermath and emphasis — a low-frequency presence after the event | 40–120 Hz | 200–500 ms |
The whoosh is the layer that gives the event a sense of approach. It is a noise-based sweep, typically filtered so that the center frequency moves from high to low or from low to high across its duration. In a UI context, it is the layer that makes a menu transition feel like the menu is sliding into place rather than appearing instantly.
The impact is the layer that gives the event weight. It is a short burst of low-frequency energy, usually filtered noise or a pitched sub-oscillator with a fast decay. In a UI context, it is the layer that makes a confirmation feel final rather than tentative.
The sub-tone is the layer that gives the event aftermath. It is a low-frequency presence that continues after the blip and the impact have finished, and it communicates that the event had an effect that is still unfolding. In a UI context, it is the layer that makes an important state change feel significant.
The three layers are not always used together. A checkbox toggle needs only the blip. A menu transition needs the blip and the whoosh. A purchase confirmation needs all four. The UI sound design guide covers the broader structure of the UI sound set; the layering decision is made per-event, based on how much weight the event deserves.
What are the millisecond offsets that make the layers work together?
The timing of each layer relative to the blip is what makes the combined sound feel like a single event rather than a sequence of sounds. The offsets are small — a few tens of milliseconds in most cases — and they are the difference between a layered sound that feels cohesive and one that feels like a sound effect parade.
| Layer | Offset from blip start | Why this offset |
|---|---|---|
| Whoosh | −30 to −20 ms | Arrives before the blip, creating the sense of approach |
| Blip | 0 ms (anchor) | The event moment; everything is timed relative to this |
| Impact | +5 to +15 ms | Arrives just after the blip, adding weight to the event |
| Sub-tone | +10 to +30 ms | Fades in behind the impact, providing the aftermath |
The whoosh's negative offset is the counterintuitive one. The whoosh arrives before the blip, which means the player hears the approach before the event. This is what makes the combined sound feel like something arrived rather than something appeared. The offset is short enough (20 to 30 milliseconds) that the two sounds are still perceived as part of the same event, but long enough that the whoosh's sweep has begun before the blip's attack lands.
The impact's positive offset is the other key timing. The impact arrives just after the blip, which is what makes the event feel like it has weight rather than just pitch. A 5 to 15 millisecond offset is below the perceptual threshold for a separate event (which is around 20 to 30 milliseconds for most listeners), so the two layers are heard as a single moment. A longer offset would start to read as a delay.
The sub-tone's offset is the one that varies most. A sub-tone that starts immediately after the impact is a punchy, aggressive presence. A sub-tone that fades in over 50 to 100 milliseconds is a more subtle, atmospheric presence. The choice depends on whether the event is supposed to feel explosive or significant. The friendly/hostile tone design guide covers the emotional mapping that determines which choice is right for a given event.
The offsets are not rigid. They are starting points, and the right values depend on the specific layers. A whoosh with a very slow sweep might need a longer lead-in, because the sweep has to begin earlier to be audible by the time the blip lands. An impact with a very fast attack might need a larger offset, because the attack itself is doing the work of the impact and the offset is just separating it from the blip.
How do you keep the layers from masking each other?
The four layers occupy different frequency ranges, and the separation is what keeps them from masking each other. The blip's fundamental is at 800 to 2000 Hz, which is above the impact's 80 to 400 Hz and the sub-tone's 40 to 120 Hz. The whoosh is broadband, but its energy is concentrated in the high frequencies, which is where the blip has less energy.
The masking that does occur is at the boundaries. The blip's low harmonics overlap with the impact's high harmonics around 800 to 1200 Hz, and the whoosh's low end overlaps with the blip's fundamental. These overlaps are what need to be managed, and the specific tools for managing them are level and filtering.
| Overlap | Tool | Typical setting |
|---|---|---|
| Blip harmonics vs. impact top | High-pass on impact, low-pass on blip | Impact HPF at 300 Hz, blip LPF at 3000 Hz |
| Whoosh low end vs. blip fundamental | High-pass on whoosh | Whoosh HPF at 400 Hz |
| Sub-tone vs. impact | Low-pass on impact, high-pass on sub-tone | Sub-tone HPF at 30 Hz, impact LPF at 200 Hz |
The high-pass on the whoosh is the most important of the three, because the whoosh's low end is the layer most likely to muddle the blip. A whoosh that has energy at 200 Hz will compete with the blip's fundamental, and the combined sound will feel muddy. A whoosh with a 400 Hz high-pass sits above the blip's fundamental and creates a clear separation.
The impact's high-pass is the second most important. An impact with energy at 800 Hz will compete with the blip's harmonics, which is what gives the blip its perceived brightness. A 300 Hz high-pass on the impact keeps the weight in the sub-bass and leaves the mid-range to the blip.
The sub-tone is the least likely to cause masking because its frequency range is below everything else. The main risk is that it is too loud, which makes the whole sound feel muddy. The sub-tone should be the quietest of the four layers, typically 6 to 10 dB below the blip. The mix hierarchy guide covers the routing that makes it easy to adjust the sub-tone level independently.
Which UI events actually justify a layered sound?
Layering adds complexity, CPU cost, and file size. The events that justify the cost are the ones where the event itself is significant enough to warrant more than the minimum feedback. A checkbox toggle is not one of them; a purchase confirmation is.
| UI event | Layers | Reason |
|---|---|---|
| Button press (routine) | Blip only | The event is frequent; extra layers would be fatiguing |
| Checkbox toggle | Blip only | Frequent and low-significance |
| Menu transition | Blip + whoosh | The event involves movement; the whoosh conveys it |
| Confirmation (save, submit) | Blip + impact | The event is final; the impact conveys weight |
| Error / invalid input | Blip + impact (low-pitched) | The event is negative; the impact conveys severity |
| Purchase / unlock | Blip + whoosh + impact | The event is significant; all three layers are warranted |
| Achievement / level-up | Blip + whoosh + impact + sub-tone | The event is a milestone; all four layers are warranted |
The pattern is that the number of layers scales with the significance of the event. A routine event gets one layer; a milestone gets four. The frequency of the event is the constraint: a button press that plays hundreds of times per session cannot afford the layers that a purchase confirmation that plays twice can.
The rule of thumb is that an event that plays more than once per minute should be a single layer. An event that plays less than once per five minutes can afford two layers. An event that plays once per session can afford all four. The voice limiting guide covers the budget that determines how many layers a project can afford across the whole set.
How do you implement the layered sound in code?
The implementation is a wrapper around the blip generator, with each additional layer scheduled at its own offset. The layers can be generated from the same Web Audio context, which means they are sample-aligned to the same clock.
function playLayeredUI({
blipParams,
addWhoosh = false,
addImpact = false,
addSubTone = false
} = {}) {
const ctx = getAudioContext();
const now = ctx.currentTime;
// Layer 1: whoosh (arrives 25 ms before the blip)
if (addWhoosh) {
const whooshStart = now - 0.025;
const whoosh = ctx.createOscillator();
const whooshGain = ctx.createGain();
const whooshFilter = ctx.createBiquadFilter();
whoosh.type = 'sawtooth';
whoosh.frequency.setValueAtTime(4000, whooshStart);
whoosh.frequency.exponentialRampToValueAtTime(
800, whooshStart + 0.10
);
whooshFilter.type = 'highpass';
whooshFilter.frequency.value = 400;
whooshGain.gain.setValueAtTime(0, whooshStart);
whooshGain.gain.linearRampToValueAtTime(
0.15, whooshStart + 0.02
);
whooshGain.gain.exponentialRampToValueAtTime(
0.001, whooshStart + 0.10
);
whoosh.connect(whooshFilter);
whooshFilter.connect(whooshGain);
whooshGain.connect(ctx.destination);
whoosh.start(whooshStart);
whoosh.stop(whooshStart + 0.12);
}
// Layer 2: blip (anchor at now)
playBlipFromParams(blipParams, now);
// Layer 3: impact (arrives 10 ms after the blip)
if (addImpact) {
const impactStart = now + 0.010;
const impact = ctx.createOscillator();
const impactGain = ctx.createGain();
impact.type = 'sine';
impact.frequency.setValueAtTime(120, impactStart);
impact.frequency.exponentialRampToValueAtTime(
60, impactStart + 0.08
);
impactGain.gain.setValueAtTime(0, impactStart);
impactGain.gain.linearRampToValueAtTime(
0.4, impactStart + 0.003
);
impactGain.gain.exponentialRampToValueAtTime(
0.001, impactStart + 0.10
);
impact.connect(impactGain);
impactGain.connect(ctx.destination);
impact.start(impactStart);
impact.stop(impactStart + 0.12);
}
// Layer 4: sub-tone (arrives 20 ms after the blip)
if (addSubTone) {
const subStart = now + 0.020;
const sub = ctx.createOscillator();
const subGain = ctx.createGain();
sub.type = 'sine';
sub.frequency.setValueAtTime(55, subStart);
subGain.gain.setValueAtTime(0, subStart);
subGain.gain.linearRampToValueAtTime(
0.2, subStart + 0.05
);
subGain.gain.exponentialRampToValueAtTime(
0.001, subStart + 0.40
);
sub.connect(subGain);
subGain.connect(ctx.destination);
sub.start(subStart);
sub.stop(subStart + 0.45);
}
}
The function shows the four layers with their offsets and their envelope shapes. The whoosh uses a sawtooth oscillator with a downward pitch sweep from 4000 to 800 Hz, high-passed at 400 Hz to keep it out of the blip's frequency range. The impact uses a sine oscillator with a downward sweep from 120 to 60 Hz, which is the low-frequency thump that gives the event weight. The sub-tone uses a sine at 55 Hz, which is the low-frequency presence that gives the event aftermath.
The function is deliberately modular. Each layer is optional, which means the same function can produce a blip-only sound, a blip-plus-whoosh transition, or a full four-layer milestone. The generator architecture guide covers the data-driven approach that extends this function to a full set of layered UI sounds.
The whoosh's negative offset is the part that requires
care in the implementation. The
whooshStart = now - 0.025 schedules the
whoosh 25 milliseconds in the past, which is only valid
if the audio context has not yet reached that time.
In practice, the function should be called immediately
after the triggering event, which means now
is at most a few milliseconds behind the actual audio
clock. The 25-millisecond offset is within the tolerance
of the audio system's scheduling buffer, so it will play
correctly, but a larger offset would require a different
approach.
For a whoosh with a longer lead-in — 50 milliseconds or more — the scheduling should be done on the event that precedes the blip, not on the blip itself. For example, a menu transition might trigger the whoosh when the menu button is pressed and the blip when the new menu becomes visible. The two events are already separated in time, and the whoosh can be scheduled at the first event without the negative offset.
When does layering make the UI sound worse?
Layering is not always an improvement. The specific situations where it makes the sound worse are worth knowing, because a designer who layers every UI sound produces a UI that feels heavy and cluttered rather than rich.
The event is frequent. A button that plays four layers is a button that plays four layers hundreds of times per session. The layers that feel substantial on the first press become fatiguing on the hundredth. The blip-only sound that feels thin in isolation is often the right choice for an event that plays constantly.
The layers are too similar in frequency. A whoosh that sits in the 800 to 2000 Hz range and a blip in the same range will sound like one busy sound rather than two distinct layers. The frequency separation described earlier is what makes the layers readable, and a layered sound without the separation is just a louder single sound.
The layers have similar envelopes. A whoosh that decays over the same time as the blip, and an impact that decays over the same time as the blip, will sound like a single dense sound rather than three layers. The envelope difference is what allows the ear to hear each layer as a separate contribution. The square-wave synthesis guide covers the envelope shapes that work for the blip; the whoosh and impact need different shapes to be distinguishable.
The sub-tone is too loud. The sub-tone is the layer that is most likely to be overused. A sub-tone at the same level as the blip makes the whole sound feel muddy and heavy, because the low-frequency energy dominates the perception. The sub-tone should be the quietest layer, and it should be reserved for the events that genuinely need a sense of aftermath.
The context is a mobile device. Mobile speakers reproduce very little below 200 Hz, which means the impact and the sub-tone will not be audible on a phone's built-in speakers. A layered sound that relies on the impact for its weight will sound thin on mobile, and the extra layers add CPU cost without adding perceived quality. The mobile app blip guide covers the platform-specific considerations; the layering decision should account for the playback environment the game will actually encounter.
The general rule is that layering should be used for the events that deserve to feel significant. A UI that layers every sound is a UI that has no contrast between the routine and the important. A UI that layers only the important sounds has a clear distinction that the player can learn, and the layering becomes a signal rather than a background.
The layered UI sound is a small investment that produces a large improvement in perceived quality. The specific offsets, the frequency separation, and the event selection in this article are the ones that work for most projects, and the code structure is one that extends to any combination of layers. A project that starts with a single blip for every event and adds layers only where the event deserves them will end up with a UI sound set that is both rich and restrained, which is the balance that makes a UI feel polished without feeling heavy.
Generate the Layers Separately and Combine Them
Open the SfxMaker blip generator and create the three layers as separate WAV files: a blip in the 800–2000 Hz range, a whoosh from a filtered noise sweep, and an impact from a low sine with a fast decay. Combine them with the offsets from this article, or use the parameters directly in a runtime generator. The separate layers are what make the layering tunable.
Open Blip Sound Generator →