When the assistant says "OK, I'm looking" before answering
Until 12 May, between the moment you released the button and the moment the voice replied, the screen showed nothing. Five, ten, sometimes fifteen seconds without a sign, and the app looked broken. That day went to those silences: halos that react to the voice, a "thinking" state that keeps the orb lit, a bubble removed, and a short sentence, "OK, I'm looking into it", that the assistant says right away when the answer is going to take a while.
A screen whose only job is to reassure
The app has one screen, and on that screen, an orb. When we designed this interface not to be seen, we accepted a trade: everything the app does has to be readable on that orb, or nowhere. An ordinary app has a spinner, a progress bar, a greyed-out button. Here there is only the movement of a shape, and a voice.
As long as the conversation was a short exchange, that was enough. You hold the button, you speak, you release, the answer arrives a second or two later. But as soon as a request needed a search, a recipe, a place, a breakdown to diagnose, the answer took five to seven seconds to start. And when transcription, the model and speech synthesis added up, you could wait fifteen seconds without a pixel moving. The screen went back to rest the instant your finger left the button, exactly as if nothing had been heard.
The question the first tests raised fit in one line: "is it stuck or is it working?" People tapped the screen, closed a card, repeated the request. And sometimes the answer arrived while they were repeating it.
So 12 May, between two attempts at photos for the cards, went to those silences. Four changes, two on the screen, two in the voice, and a fifth for the case where there is truly nothing to say.
Late morning: edges that light up with the voice
The first missing sign was the simplest. While you speak, nothing showed that the microphone was hearing you. The orb pulsed at its own pace, the same as at rest.
Late in the morning, two bands of light appeared along the left and right edges of the screen. They are blue while the user speaks, and their intensity is not an animation: it comes from the sound level measured by the microphone, several times a second, converted from a decibel reading into a value between zero and one, then smoothed so the halo breathes instead of flickering. Raise your voice and the edges brighten. Fall silent while you look for a word and they settle without going out. The held button and the edges following your voice say the same thing: I hear you, go on.
For the assistant's voice, the same data is not available. The audio player that plays the reply does not report amplitude in real time. Rather than invent a fake level, the halos use a stylised oscillation, a rhythm close to speech, about three cycles a second, in a different colour. The effect says "it's talking" without pretending to measure volume. It is a deliberate compromise: a halo beating to a real voice would be truer, but a halo beating at the pace of a voice is already honest.
One piece of plumbing mattered for the effect to hold. The microphone reading does not travel through the app's code on every sample: it is dropped into a shared value that the animation engine reads directly on the display thread. Without that shortcut, every sample would have made one more round trip, and a halo that follows the voice with a delay no longer follows anything.
Noon: blue rectangles instead of halos
The first test on a phone showed something other than halos. Two blue rectangles, solid, opaque, overlapping in the middle of the screen. The conversation was unreadable behind them.
The cause was the gradient. The first version drew the halos with a vector radial gradient whose horizontal and vertical radii were given as percentages of the area. On Android, that way of writing the radii is not understood: the library gives up on the gradient and fills the whole rectangle with the starting colour. Same code, and the result was a slab.
The halos were rebuilt in the drawing engine that already renders the orb. It only knows circular radial gradients; to get an ellipse, you apply a transform to the gradient itself that stretches it vertically, without touching the geometry of the rectangle carrying it. What comes out is an elliptical fade, reliable on the phones we tried, at the mockup's dimensions: each halo takes a little over half the screen width and spills past the top and bottom, so the glow seems to come from behind the edge rather than from an object laid on top of it. Volume does not change the halo's size, only its opacity: resizing a shape on every sample would have been expensive and produced an unpleasant pumping effect.
The palette was revised while we were at it. Blue remains the user's colour. For the assistant, the original cyan gave way to a warmer glow, the same one the orb's own halo takes when it speaks, so that the orb and the edges tell the same phase together.
The state that did not exist: "thinking"
The longest silence was not during speech. It began when the button was released.
The screen knew four states: rest, listening, the assistant speaking, and typing on the keyboard. Between listening and speaking, nothing. Your finger leaves the button, the recording is sent, the transcript comes back, the model reasons, calls its tools, speech synthesis produces the audio, and throughout all of that the state was "rest". The orb rose back to the centre and pulsed quietly, as it did before you spoke to it. Five to fifteen seconds of perfect calm, precisely when the app was working hardest.
A fifth state was added: "thinking". It kicks in the instant the user's message lands in the thread, whether it came from the voice or the keyboard. The orb drops to the bottom of the screen, to the place it takes when the assistant speaks, with a caption underneath: "thinking…". The side halos stay lit, in the assistant's warm tint, and keep breathing slowly. The keyboard folds away if it was open, so the orb stays visible. And a tap on the orb interrupts, the same gesture as in the middle of a spoken reply, so the user keeps control at every moment.
Two transition details mattered. First, "thinking" is only entered from rest or listening: if a late transcript arrives while the assistant is already speaking, it must not overwrite that phase. Second, the state is left as soon as the reply's text arrives, not when the audio starts. If sound is on, playback takes over immediately and the orb switches to "speaking" without a visible seam. If sound is muted, there is no playback, and without that exit the orb would have stayed at the bottom, thinking forever.
Afternoon: one bubble too many
The early afternoon went to the cards and their pictures. Coming back to the conversation, one thing stood out: during dictation, a small bubble under the orb said "listening". It had been placed there when it was the only sign that the microphone was running. Since the morning, the edges of the screen had been saying the same thing, better, because they followed the voice.
Two signals for one piece of information is one too many. The bubble was removed. The partial transcript that fed it is still computed, in case it is useful elsewhere one day, but it is no longer displayed. It is the reverse lesson of the rest of the day: saying what you are doing does not mean saying it twice.
"OK, I'm looking into it": the holding word
That left the most awkward silence, the one the screen alone could not fill.
When a request needs a web search, the model chains several tools before writing: it first queries the memory, runs the search, often saves the result into a card, and only then writes its reply, which then goes to speech synthesis. Five to seven seconds between the end of the user's sentence and the assistant's first word. The "thinking" state shows something is running, but in a conversation, seven seconds of silence are still long. Between people, nobody stays quiet for seven seconds before answering: you say "hang on, let me look".
That is what the assistant has done since that afternoon. The conductor on the server side, the one that runs the model and executes its tools, watches the model's first decision. If that first decision includes a web search, the only tool in the chain that consistently takes more than a second, it immediately fires a short sentence: "OK, I'm looking into it, give me a moment." Five variants exist, drawn at random each time, "One second, I'm searching", "On it, two seconds", so you don't hear the same line on every search. They are short on purpose: all the user needs is to know that it is moving.
The important point is that this sentence costs no time. The server does not wait for it: it starts synthesising the sentence and, in parallel, runs the tools. The text reaches the phone immediately, the audio follows half a second later, and meanwhile the search is already under way. When the real answer arrives, it arrives at the same moment it would have before; only the silence that preceded it has been filled. To stay quick, the holding sentence uses the voice the phone asked for without going back to read the preferences in the database, unlike the final reply. And if the user has muted the sound, they see the sentence in the thread without any audio being produced for nothing.
We could have fired this holding word on every request. We did not: a single tool answers in under half a second, and a holding sentence before an immediate answer would have made the assistant chatty. The holding word is reserved for the case where the wait exists.
And when there is truly nothing to say
One last silence was handled the same morning, a few minutes before the halos, because it belonged to the same family: the one where the model does not answer at all.
Three situations produced it. The model crashes midway, a network error or a remote server refusing. The model loops, calls tools again and again, and hits the iteration limit without ever closing with text. Or the model returns an empty string, which happens more often than you would think. In all three cases the orb stayed mute, and the user had no way to tell a failure from a wait.
Now each of these cases produces a spoken sentence, distinct according to the cause: a technical hiccup on our side, an error while trying to do what was asked, or a reply that could not be completed, each time with an invitation to try again or rephrase. If a tool failed but the model itself explained the problem, we keep its explanation, always more precise than a canned line. The fallback reply is not there to look nice: it is there so the orb never goes quiet without a stated reason.
What the day taught
An app with no navigation screen cannot afford silence. Every second where nothing moves is a second where the user wonders whether to start over, and starting over is the worst scenario: two requests in flight, two replies, a duplicate card.
That 12 May split the answer between the screen and the voice. The screen says the phase: listening, with edges that follow the voice; thinking, with an orb that stays lit; speaking, with a warm glow. The voice says the wait when it is going to be long, and it says the failure when it happens. None of these signals adds latency, and none of them lies: the assistant's halo does not pretend to measure its voice, the holding sentence promises nothing more than a search in progress.
It is the rule we have kept since for everything that touches voice and conversation: an assistant that is working must show it, an assistant that is waiting must say it, and an assistant that fails must say that too. The rest, the memory, the cards, the searches, is only worth something if you have not closed the app in the meantime, believing it dead.
