Cadence
Designing communication for an unreliable signal.
Role: interaction design, prototyping, design rationale. Made with a working browser prototype, a Figma file, and this writeup.
The short version
Most assistive communication tools assume two things that aren't true for a brain-computer interface. They assume a clean switch on the way in, and they assume the person doesn't much care how they sound on the way out. A BCI user is neither of those. The input is shaky and takes effort, and it misfires. And the voice coming out is supposed to be theirs.
I designed and built a working prototype that takes both problems seriously. The main idea is adaptive confirmation. The interface treats each signal as a probability. It commits right away when it's confident, and asks first when it isn't, so a noisy blip doesn't land in the middle of a word. On the output side, voice and tone are real design choices, not a buried setting.
The piece is interactive. Turn the noise up, watch adaptive confirmation catch the errors, then drag the threshold to zero to feel what it was protecting you from.
▶ Try the prototypeWhy this problem
People with severe motor impairment, like late-stage ALS, locked-in syndrome, or a high spinal cord injury, often can't speak or move but are completely sharp mentally. A BCI can give them a way back to the world. For a lot of them, though, that way back is a single unreliable signal: an intent to "select" that shows up late, fires by accident sometimes, and misses entirely other times.
That changes the whole problem. It isn't "make a nicer keyboard." It's this:
How do you let someone build and speak a sentence when their only input is one noisy click, every selection costs real physical effort, and a wrong one is a pain to undo?
That constraint is the part most accessibility work skips over, and it's exactly where a BCI company has to operate.
What "one slow, noisy signal" actually means
One. The user gets a single command, not a keyboard's worth of them. Think of it as having exactly one button: a "click." You can't move a cursor or aim at a letter. That single signal is the whole reason the interface scans. Since the user can't point to what they want, the software sweeps a highlight across the options, and the user fires their one signal when it lands on the right one.
Slow. Producing that one click takes effort and time. A keystroke is instant and free. A BCI click takes a beat to form, the person tires, and they can't fire quickly. So every selection is expensive. That's why the design works so hard to spend them well: predicting words, putting urgent phrases first, never wasting an input.
Noisy. This is the one most tools ignore. The signal is unreliable. It sometimes fires when the person didn't mean to (a false activation), sometimes fails to fire when they did (a missed click), and it arrives with varying confidence. A mechanical switch never does this. When you press it, you meant it. A brain signal lies, and that's exactly what adaptive confirmation is built to absorb.
Design for a keyboard and you assume the opposite of all three: many keys, instant, reliable. Closing that gap is the whole project.
Who I designed for
Maria, 58, late-stage ALS. Sharp, funny, and dependent on other people for movement and speech. Her BCI gives a binary select signal. She tires fast, so a twenty-minute conversation is genuinely tiring work. What she cares about, in order: being understood, getting urgent things across quickly, and not feeling trapped by the machine.
The care partner. A spouse, nurse, or clinician who reads the screen, handles setup, and is usually in the room. The device is used between people, not alone, so the screen has to be legible across a room and the setup has to be understandable to a non-engineer.
Principles I designed against
These came straight out of the constraint, and I used them as a rubric when I had to make a call.
- Every selection is expensive, so spend them well.
- Never trap the user. Undo and back are always available.
- Treat the signal as a probability, not a fact.
- Errors are normal, so make recovery cheap.
- No time pressure that punishes someone for being slow.
- Always show what the system is doing.
- Make the high-stakes path ("I'm in pain") the fastest one to reach.
- The voice is the person, not a machine reading text aloud. Default to the most natural voice available instead of the robotic one.
What I reused, and what's actually new
Reused on purpose: row-column scanning, word prediction, quick phrases, adjustable dwell speed. Products like Grid 3 and Tobii Dynavox already do these well, and building on them is the right move.
What's actually new is the part I care about:
- Confidence-aware selection. Scanning was built for a mechanical switch that never lies. A neural signal lies all the time. Every click comes with a confidence score, which is how sure the system is that the press was a real, intended click. The prototype shows that score as a "Signal confidence" bar at the top, and it changes what happens next: a confident click goes straight through, a shaky one triggers a confirmation step.
- Treating false activations as normal. Recovery isn't an edge case here. Misfires are routine with a brain signal, so getting back from one has to be easy.
- The output side. Voice identity and tone, handled as design decisions instead of an afterthought.
Existing AAC assumes a clean switch going in and an indifferent speaker coming out, and a BCI user is neither, so I redesigned both ends.
The core flow
Compose and speak a message:
- Scan to a key. A highlight steps through the rows, the user selects a row, then it scans the keys in that row. One action, fired at the right moment. No pointing.
- Prediction scans first. Predicted words sit above the keyboard and are scanned before the letters, so common words cost the fewest selections. It works two ways: matching words that start with what you've typed, and guessing the likely next word once you finish one. The row always stays full so it never looks broken.
- Build with cheap recovery. Delete and Clear live in the scan cycle. The user is never stuck.
- Speak. Text-to-speech, with the message kept large on screen for the care partner.
- Quick phrases. Urgent items first ("I'm in pain," "Please call the nurse"), spoken in one selection.
The key design decisions
Adaptive confirmation
Here's the tension. Committing on every selection is fast but falls apart under noise. Confirming every selection is safe but doubles how long it takes to say anything. Neither one works on its own.
What I landed on was confirming adaptively. Above a confidence threshold, the selection just commits. Below it, you get a two-option confirm, scanned the same way as everything else, with Cancel already highlighted as the default. So if the user does nothing, the safe thing happens. There's also a small "noisy signals caught" counter, which makes the whole thing legible. Every number on it is an error that never made it into the message.
The reason it works is simple. Confirmation takes a single point of failure, where one bad blip corrupts your sentence, and turns it into something that needs two deliberate actions in a row. A random signal almost never manages that.
Confirm should catch accidents, not nag
My first version confirmed both Clear and Speak every time. Once I actually used it, the confirm on Speak felt like nagging, because Speak is the thing you're trying to do. So I changed it. Only Clear always confirms, since it wipes the message and you can't get it back. Speak follows the adaptive rule, so a confident press just speaks and only a weak signal asks first. The lesson I took: put the guard on losing your work, not on doing the thing you came to do.
The threshold belongs to a person, not a default
Confidence threshold and scan speed aren't global settings. They get tuned to the individual. I built a calibration flow with a short practice round and framed it as the setup a therapist would run with the patient. If you drag the threshold to zero, confirmation turns off and the interface gets fragile the moment there's any noise. That contrast says the whole thing in one move.
Voice is identity
A flat robotic voice doesn't only sound bad. It erases the person talking. So I made voice and tone come first instead of last. The prototype surfaces the most natural voices the device has and refuses to default to the robotic one, and it has tone presets (calm, urgent, asking, joking) that actually change how a line is delivered. It can use a real neural voice too. I also dug into Apple's Personal Voice, which is on-device voice banking made for people who are losing their speech. The browser can't touch it, because Apple only lets authorized native apps use it. That limitation is the interesting part. A regulated native device like a BCI is exactly the kind of product that should be building banked, personal voices right into the way someone talks.
Accessibility
The prototype is itself an access tool, so I treated accessibility as part of building it rather than a box to tick at the end: visible keyboard focus on every control, live regions that announce status and the message, labelled controls and toggle states, a confirmation step you can operate from the keyboard, and respect for reduced-motion. A real version in a regulated setting would need to go further, with full screen-reader semantics for the scanning state, support for switch hardware, and formal conformance testing. I'd treat that as a requirement, not a nice-to-have.
Running it against WCAG 2.2
After I settled on the color palette, I audited the interface against WCAG 2.2 AA and found six contrast failures. Every one of them came from the colors, not the structure. That was a useful thing to learn the hard way: a palette can look good and still lock people out, and the only way to know is to actually measure it.
The worst offender was the Confirm button. White text on the bright green came out at 2.3:1, well under the 4.5:1 minimum, and it's the most important "yes" in the whole interface. The "noisy signals caught" counter, which is the number that shows the entire adaptive-confirmation idea working, was green on the purple background at 1.3:1. Anyone with low vision would never see it. The other four were muted labels and status text sitting on mid-tone backgrounds.
| Element | Before | After |
|---|---|---|
| Confirm button (white on green) | 2.3:1 | 6.6:1 |
| "Caught" counter on purple | 1.3:1 | 4.9:1 |
| Status / secondary text | 2.0 to 3.5:1 | 4.5:1 or better |
I fixed all six by darkening the green and the secondary text just enough to pass, keeping the palette's identity, then re-measured every pair. I also wrote the passing values into the design system docs as contrast tokens, so a later color tweak can't quietly bring a failure back. To me that's the part worth keeping: not passing the audit once, but making it harder to break next time.
One thing this audit doesn't claim. It covers measurable contrast and markup, not lived experience. Real screen-reader testing of the scanning announcements and actual switch hardware are still production follow-ups.
What I'd do next
- Swap the simple next-word model (a word-pair table, the kind old phone keyboards used) for an actual language model that predicts from full context and learns the person's own vocabulary. The prediction quality is an engine problem; my part was making predictions cost the fewest selections and putting them first in the scan.
- Build in banked and personal voices natively.
- Test it with real switch users and clinicians, and tune the thresholds against actual signal data instead of my simulation.
What I took from it
The best decisions in this project came from using the thing and running into friction: the Speak confirm that nagged, the robotic voice that flattened the person, the delete button I'd hidden behind a bar. The design that matters here isn't a list of features. It's a few hundred small calls about where effort should and shouldn't land for someone who only has a little to spend. That's the kind of work I want to do at Echo.
Try it for yourself. It takes about a minute to feel the difference.
▶ Open the prototype