Header Logo

Building a Conversational Video Agent in Remix for Users with Low Vision or Motor Impairments

Building a Conversational Video Agent in Remix for Users with Low Vision or Motor Impairments

Build an accessible conversational video agent in Remix with keyboard-first controls, synced avatar speech, and server-side realtime sessions.

Introduction


If you are building a conversational video agent for users with low vision or motor impairments, the hard part is not “adding an avatar.” The hard part is making the interaction model predictable, low-friction, and tolerant of delayed input, partial input, and repeated input.


That means your agent needs more than speech recognition and text-to-speech. It needs a face that stays synchronized with the agent’s turn-taking, a transport that behaves well under network variance, and UI controls that can be operated without precise pointing, dragging, or multi-step gestures.


By the end of this post, you should have a practical mental model for building that experience in Remix: how the realtime pieces fit together, where accessibility usually breaks down, and how to structure the app so keyboard, speech, and assistive-tech users can all complete a conversation without fighting the interface.


Start with the interaction model, not the avatar


For low-vision and motor-impaired users, the avatar is presentation. Accessibility is determined by the conversation flow.


In practice, the flow usually looks like this:


  1. The user lands on a page with a clearly labeled “Start conversation” action.

  2. Your app requests microphone permission only when needed, not on load.

  3. The agent listens, produces text and audio incrementally, and the avatar lip-syncs to the audio stream.

  4. The UI exposes coarse-grained controls: mute, stop, repeat, and end session.

  5. When the user cannot speak, the app supports typed prompts, preset responses, or both.


That last point matters. If you only optimize the “voice-first” path, you still leave out users who can hear but cannot reliably speak, or who need to correct dictation errors by keyboard.


Design the Remix UI for large targets and predictable state


Remix is a good fit here because the server/client boundary is explicit. Use server loaders for session creation and permissions, and keep the client surface minimal: a small set of buttons, a text input, and the video element or embed that renders the agent.


For accessibility, the important part is not fancy layout; it is stable semantics:


  • Use actual <button> elements, not clickable divs.

  • Keep focus order linear and obvious.

  • Expose state changes through visible text, not only color or motion.

  • Allow keyboard activation for every primary action.

  • Make controls large enough that users with tremor or limited dexterity do not need pixel-perfect precision.


In a realtime session, the UI should also avoid “chatty” rerenders. If the transcript is updating every few hundred milliseconds, debounce visual announcements or separate the live transcript region from the main controls so keyboard focus does not jump around.


How realtime avatar sessions actually behave


A conversational video agent usually has three concurrent streams:


  • Audio input from the user to the agent.

  • Agent text/audio generation from the model or voice stack.

  • Video synthesis or avatar playback that tracks the agent’s speech cadence.


The avatar is most useful when it stays synchronized with the agent’s turns, not when it is constantly “playing” independent motion. That means you should treat video as a companion stream to the audio pipeline. When the agent is silent, the avatar should settle. When the agent speaks, the mouth shape and timing should follow the audio as closely as the transport allows.


For accessibility, this has a real side effect: users rely on the agent’s speaking state as a cue. If the avatar keeps moving after audio has stopped, or starts too early, it becomes harder to understand when to interrupt, when to wait, and when the turn is actually complete.


Example: session creation from a Remix action


A common pattern is to create the realtime session on the server, then return only the minimum data the browser needs. Keep your API key on the server; do not expose it in the client bundle.


export async function action() {

}
export async function action() {

}
export async function action() {

}


From there, your client can attach the returned session to the video surface, open the media connection, and render the agent. The exact payload shape will vary by workflow, so treat the docs as the source of truth for fields and lifecycle events.


Make the conversation usable without precise pointer input


Motor accessibility is mostly about removing high-precision interaction requirements. In a conversational agent, the most common mistake is to make the primary action depend on small controls or hover-only affordances.


Prefer these patterns:


  • A single obvious “Start” button.

  • Persistent “Mute” and “End” controls in fixed positions.

  • Keyboard shortcuts for repeat, stop, and transcript focus.

  • A text fallback for users who cannot or do not want to speak.


If you support typed input, keep the submission path simple. Pressing Enter should submit. Shift+Enter can insert a newline only if multiline input is genuinely necessary. For many support and guided-task scenarios, a single-line prompt box plus a set of recommended responses is easier than a large freeform composer.


Also, avoid requiring drag-to-resize, drag-to-seek, or hold-to-talk as the only mode. Those patterns are fragile for users with limited dexterity, and they create unnecessary failure states when the browser loses focus or the pointer slips.


Use a conversational agent pattern that supports interruption


For users who cannot easily click in sync with an agent, interruption support matters. A good voice agent should allow barge-in: if the user starts speaking while the agent is talking, the agent should stop or yield quickly enough to stay usable.


That affects both the audio stack and the UI state machine. A simple implementation usually tracks:


  • idle — waiting for input.

  • listening — microphone active, capturing user speech.

  • thinking — model or backend processing.

  • speaking — agent audio and avatar are active.

  • ending — cleanup and teardown.


When the state changes to speaking, expose that clearly in the DOM for assistive technologies. When the user interrupts, update the state immediately and stop visual motion that implies the agent is still talking. This is not cosmetic; it reduces confusion for screen-reader and low-vision users who depend on state cues.


Where Protoface fits in the stack


This is the point where Protoface is useful: it gives your voice agent a synchronized talking video face without forcing you to build avatar infrastructure yourself. If you are already running a LiveKit-based agent, the LiveKit plugin pattern is often the most direct way to add the avatar layer, because the video face stays coupled to the agent’s speech rather than becoming a separate UI subsystem.


For a Remix app, that matters because you can keep the server-side session logic in Remix, then let the client render the avatar surface as part of the conversation view. The browser never needs your API key, and your accessibility work stays focused on the actual interaction model rather than on low-level media plumbing.


Short curl example for server-side integration


If you want to inspect the REST path from the server side, a minimal request looks like this:


curl -X POST https://api.protoface.com/sessions \
}'
curl -X POST https://api.protoface.com/sessions \
}'
curl -X POST https://api.protoface.com/sessions \
}'


Use this pattern only from trusted backend code. For browser-only embeds, use the customer-managed iframe approach instead of shipping credentials to the client.


Trade-offs and gotchas


There are a few traps that show up repeatedly in accessibility-oriented voice/video agents:


  • Over-animating the avatar. Continuous motion can distract users who already have low vision. Keep idle motion subtle.

  • Voice-only fallback assumptions. Not all users can speak reliably. Always provide a typed path.

  • State hidden in audio. If the only cue is “the agent stopped talking,” screen-reader users and users in noisy environments lose context.

  • Too much client-side session logic. Realtime setup belongs on the server; the browser should only receive session material it can safely use.

  • Small controls and transient UI. Anything critical should remain visible and keyboard-accessible.


Also remember that accessibility and latency interact. A delayed “Stop” button feels like a bug to everyone, but for motor-impaired users it is especially costly because they may need more time to initiate a correction. Keep your controls responsive even if the underlying model response is still winding down.


Conclusion


Building a conversational video agent for users with low vision or motor impairments is mostly about disciplined interaction design: stable focus, large controls, keyboard-first actions, explicit state, and a speech pipeline that can be interrupted and resumed cleanly. The avatar should reinforce the conversation, not complicate it.


If you want to add the video face without taking on avatar transport and synchronization yourself, start with the Protoface docs and the LiveKit plugin or REST workflow that matches your stack. The quickest next step is to prototype the conversation state machine in Remix, then wire in the avatar once the accessibility and turn-taking behavior feel solid. See the docs for the current API shapes and integration details.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.

Add a face to your AI.

No credit card needed.