A companion as an interface

Anori is a voice-first AI companion built around a full-screen anime VRM character. The avatar is not a video placed beside a chat box: it is the main interface, with conversation history, captions, text input and configuration kept available without pulling attention away from the character.

The interaction has to communicate more than whether a request succeeded. Idle, listening, thinking, speaking and interrupted states each affect the controls, status copy and avatar motion, so the user can understand what the system is doing before a reply appears.

One voice pipeline

OpenRouter is the only inference gateway. Recorded audio is transcribed through the configured speech-to-text model, the conversation reply streams back as text, and the completed response is rendered through the configured text-to-speech model. Browser speech recognition and browser speech synthesis are deliberately not used.

That gives the administrator one place to change chat, transcription and voice models. It also keeps the failure states honest: without a configured key the avatar and local tools still work, while anything that would call a provider is visibly unavailable.

Motion tied to conversation state

The Three.js stage loads a bundled VRM character with breathing, blinking and gaze during idle time. Listening changes the character's posture; speaking uses the generated audio signal for mouth movement; gesture hints attached to a reply drive small emotional reactions without turning every message into a large canned animation.

Motion respects reduced-motion preferences, and the interface remains usable with text input when microphone access is unavailable. On mobile, the controls move into the lower thumb zone while the character keeps the visual focus.

Memory that survives the session

Conversations, messages and memories live in Turso rather than inside browser storage or a temporary server process. The prompt pipeline selects enabled memories for the current character and keeps them separate from the visible transcript, so a companion can remember useful details without forcing every old conversation into each request.

Users can revisit or archive conversations. The admin console can inspect and edit memories directly, which makes persistence understandable and reversible instead of presenting it as invisible model behaviour.

Administration is part of the product

The /admin console manages characters, prompts, VRM URLs, voices, model selection, conversation records, memories, retention and sanitized inference telemetry. The OpenRouter credential is write-only at the HTTP boundary and is stored through the database; there is no OPENROUTER_API_KEY environment fallback.

Administrator passwords use a salted password hash, sessions store only token hashes, and destructive data actions stay behind authenticated routes. Privacy exports omit provider credentials and raw inference payloads.

Shipping the complete loop

The React and Vite client is deployed with a Hono function on Vercel. A Turso database provides durable SQLite-compatible storage, and the private GitHub repository is connected to production so every push to main creates a new deployment. The custom domain and HTTPS complete the same-origin path required for secure microphone access and admin cookies.

The avatar is the largest asset in the experience, so the rest of the interface stays intentionally restrained: no animated background, no decorative panels around the character, and no duplicate visualizer competing with facial motion.

Explore the live build at anori.worksonmy.dev.