Mic Preflight
The microphone check that runs before the anonymous demo (M2). It exists because `/interview` asks for the mic mid-flow, with the interviewer already talking — a refusal there strands the visitor inside a voice screen that cannot hear them. Zero of eight mobile visitors reached the interview in the measured window.
Live
The real component, at the width the demo gets in `/setup` (528px). Pressing the mic button raises your browser’s actual permission prompt and the meter reads your actual voice — that is the point of the check, so nothing here is simulated.
Let's check your mic
We need microphone access — tap to allow it
| Prop | Type | Default | Description |
|---|---|---|---|
| language | 'ua' | 'en' | — | Picks the copy from `demoCopy`; the component owns no strings. |
| onReady | () => void | — | The mic works and was heard. Only reachable from the `hearing` state. |
| onSkip | () => void | — | Continue without the demo. Required, not optional — `denied` must never be a dead end. |
States
All six, drawn through `MicPreflightView` — `silent` appears twice, once as it starts and once 4 seconds in once the mute/device tip has appeared. `denied` is the state that matters most and the one nobody with a working microphone can reach on purpose — it must always offer a way onward, which is why `onSkip` is a required prop rather than an optional one.
Let's check your mic
We need microphone access — tap to allow it
Let's check your mic
Waiting for the browser prompt…
Let's check your mic
Say something — we should see the level move
Let's check your mic
Say something — we should see the level move
We can't hear anything — check that your mic isn't muted and the right one is selected.
Let's check your mic
We can hear you
No microphone access
Allow access in your browser settings — or continue without the demo
| Prop | Type | Default | Description |
|---|---|---|---|
| state | 'idle' | 'requesting' | 'silent' | 'hearing' | 'denied' | — | What the browser has answered so far. |
| level | number | — | RMS loudness 0–1. Drives the meter width only; 0.06 is the speech threshold. |
| onRequest | () => void | — | Raise the permission prompt. Wired to the mic button in `idle`. |
| onReady | () => void | — | Continue into the demo. |
| onSkip | () => void | — | Continue without it. |
| silentTooLong | boolean | false | `silent` held for 4s with no `hearing` in between — shows the mute/device tip below the meter. Ignored outside `silent`. |

VoiceMock was built by one designer
I'm Sergiy, a product designer. I built this trainer myself — research, design system, code. On LinkedIn I show how products like this come together, and what it changes in a designer's work.
Product Designer · AI Design Engineer · Designer for Startups
See it on LinkedIn