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.
