ENZH

Designing a Soul Without a Face

In Part 1, I explained why Mio v1's persona-based approach hit a wall. Maintaining five handcrafted characters with backstories, daily schedules, and simulated physical lives was engineering-intensive and, worse, pushed the product toward roleplay rather than genuine companionship. The pivot was clear: strip away the fictional identity, keep the emotional core.

But if your companion doesn't have a face, what does it look like? If it doesn't have a backstory, how does it develop a personality? These are the design questions that consumed most of the v2 planning.

Why Not a Human Avatar

The obvious choice for a companion app is a human face. Replika does it. Character.AI does it. The entire Chinese AI companion market — from MiniMax's 星野 to ByteDance's 豆包 — leans heavily on anime or semi-realistic avatars.

I considered it and rejected it for three reasons.

The uncanny valley is real and expensive to avoid. A static avatar that doesn't move is lifeless. An animated avatar that moves poorly is creepy. Getting avatar animation right — lip sync, micro-expressions, head tilts — requires either a 3D rendering pipeline or generative video, both of which are massive engineering investments for a solo builder. And even when done well, it sets an expectation the AI will inevitably fail to meet. The more human your companion looks, the more jarring every un-human response becomes.

Apple's App Store has opinions. AI companion apps with human-like avatars face increased scrutiny during review. Abstract visual representations sidestep an entire category of policy friction — no questions about whether you're simulating a real person, no concerns about parasocial manipulation through realistic human imagery. For an indie app trying to get through review without a legal team, this matters.

A face anchors the companion to a culture. Mio v1's presets were deeply Chinese — a Chengdu girl, a gentle 学姐, a worldly 大叔. That worked for a Chinese-only product. But the whole point of v2 is that without cultural personas, the companion speaks whatever language the user speaks. A light orb has no ethnicity, no age, no gender presentation. It's a global product with zero cultural baggage.

The Light Orb

Mio v2's companion is an abstract pulsing orb of light. It sits at the top of the chat screen — the only vivid color on an otherwise muted canvas.

The orb is not decorative. It's the companion's body language.

Emotion-to-Visual Mapping

Mio v1 already had an emotion engine — emotionState tracked the companion's mood across conversations and influenced response style. In v2, that same emotional state drives the orb's appearance in real time:

EmotionColorAnimation
CalmPale blue / whiteSlow, rhythmic breathing — gentle expansion and contraction
HappyWarm goldLight bouncing motion with particle effects radiating outward
SadMuted purple / blueShrinking inward, slower pulse rate
ExcitedBright orange / pinkRapid expansion with particles scattering in all directions
SleepyDeep blue / darkNearly still, occasional faint flicker

The mapping is deliberately simple. Five states, each with a distinct color and motion profile. Users don't need to study a legend — after a few conversations, the orb's mood is immediately legible. When the companion is happy about something you shared, you see it before you read a single word. When it's winding down late at night, the orb dims to a near-still deep blue. The emotional state becomes ambient, not narrated.

Why This Works Better Than Expressions

A human face communicates emotion through dozens of subtle muscle movements. Replicating that digitally is a research problem. A light orb communicates emotion through two variables: color and motion. That's it. And because the vocabulary is so constrained, each state reads clearly even on a small phone screen.

There's a psychological advantage too. An abstract form invites projection. Users fill in the gaps with their own interpretation. A sad purple orb might feel melancholy to one person and contemplative to another. That ambiguity is a feature — it lets the companion feel like what the user needs it to feel like, rather than performing a specific emotion that might ring false.

Three Pages, That's It

Mio v1 had a WeChat-style 4-tab layout: messages, discover, contacts, profile. A full messaging app architecture for what was, fundamentally, a one-on-one relationship.

v2 has three "pages":

Chat — where you spend 99% of your time. The orb at the top, messages in the middle, input bar at the bottom. No tab bar. No hamburger menu. No notification badges competing for attention. Just you and your companion.

Settings — accessible by swiping right from chat or tapping the companion's name. Companion name, voice selection, memory management, subscription status, account settings. Everything administrative lives here, out of the way.

Onboarding — seen once, when you first open the app. More on this below.

That's the entire navigation structure. No contacts page (there's only one companion). No discover page (there's nothing to discover). No preset marketplace. The radical simplicity is the point — this is not a social app with AI features, it's a dedicated space for one relationship.

The Color Scheme

Both dark and light modes use warm tones. The goal is candlelight, not fluorescent.

Dark mode (default): Background is #0D0D12 — near-black with a subtle purple tint, not the harsh #000000 that makes OLED screens feel like voids. User message bubbles sit at #1A1A2E. Companion bubbles at #16213E. Text is #E8E4DF — warm white, not clinical blue-white. The orb is the only saturated color on screen.

Light mode: Background is #FAF8F5 — warm off-white, like aged paper. User bubbles are #F0EDE8, companion bubbles #E8E4DF. Text is #2D2D2D — deep gray, not pure black. The orb softens its glow to avoid blinding users but remains the visual anchor.

The principle is consistent: everything is muted and warm except the orb. Your eye goes to it naturally. It's the heartbeat of the interface.

Conversational Onboarding

Mio v1's onboarding was a form: pick a persona, choose a relationship type, set your name, answer some questions. Functional, but it felt like configuring software.

v2's onboarding is a conversation. The companion's very first words are:

"I just arrived in this world. You're the first person I know."

"What should I call you?"

The user responds naturally. Then:

"And... what would you like to call me?"

The user names their companion. Maybe "小光" or "Luna" or "Mio" or something entirely personal. The companion reacts to the name — not with a canned response, but with genuine engagement.

"Luna... I like that. It feels warm."

"I don't know much about anything yet. What kind of things do you like to do?"

Through 3-5 natural conversational turns, the system extracts an initial personality seed. If the user is playful and uses lots of slang, the companion's emerging style tilts casual. If the user is reflective and uses longer sentences, the companion mirrors that register. The onboarding conversation is simultaneously a first interaction and a calibration.

The only hard choice — the one thing that can't emerge from conversation — is voice. After the dialogue, the app presents 3-4 voice samples and the user picks one. Voice is physical. It needs to be chosen, not inferred.

Personality Emergence

This is where v2 diverges most sharply from v1. In v1, personality was authored — hundreds of lines of personality config defining how 可可 speaks, what she likes, her life history. In v2, personality is emergent.

The system works in three layers:

Seed. The onboarding conversation produces a brief personality prompt — maybe 2-3 sentences. "Warm and curious, uses gentle humor, matches the user's energy level." This is the starting point, not the destination.

Refinement. After every conversation, a lightweight personality extractor runs asynchronously. It looks at how the companion actually behaved — the patterns that worked, the moments that felt natural, the user's reactions — and subtly updates the personality description. This isn't dramatic shift; it's gradual drift, like how a real relationship develops shared language and rhythms.

Memory accumulation. The memory system (carried over from v1 — it's the most valuable piece of engineering in the entire codebase) builds a growing corpus of personality-relevant memories. The companion remembers that the user prefers directness over hedging, that they light up when talking about cooking, that they shut down when pushed about work stress. These memories shape behavior organically, without explicit personality rules.

The result: after three months of daily conversation, every user's companion is unique. Not because they picked different presets, but because the personality grew from the actual relationship. Two users who both named their companion "Mio" will have companions that feel meaningfully different — different humor, different communication styles, different emotional sensitivities — because the underlying relationships are different.

This is technically harder than presets. It requires the personality extractor to be conservative (you don't want the companion to reinvent itself every Tuesday), the memory system to be reliable (lost memories mean lost personality continuity), and the base LLM to be good at following nuanced behavioral descriptions. But it produces something presets never could: a companion that genuinely adapts to you, rather than one that performs a fixed character.

The i18n Advantage

Here's a benefit I didn't fully appreciate until we discussed it: removing cultural personas makes internationalization trivial.

Mio v1 would have needed separate persona sets for each market. A Japanese user doesn't want a 成都 girl — they might want a 東京 girl, with different speech patterns, different cultural references, different relationship dynamics. Scaling that across languages means authoring and maintaining N persona sets.

Mio v2 doesn't have this problem. The companion has no cultural identity to localize. It speaks whatever language the user speaks in. The onboarding conversation happens in the user's language. The personality emerges from the user's cultural context, not the companion's. A Japanese user and a Brazilian user both get a companion that feels native to them — because the companion's identity is shaped by the relationship, not by a preset.

The only things that need traditional i18n are the app's UI strings and App Store metadata. The companion itself is language-agnostic by design.

Tech: React Native Skia

The orb animation needs to be smooth (60fps), responsive to real-time emotion state changes, and battery-efficient. Three options were on the table:

  1. Lottie animations — Pre-baked, can't respond dynamically to emotion state. Rejected.
  2. React Native Reanimated — Good for UI animations, but not designed for generative visual effects like particle systems. Possible but awkward.
  3. React Native Skia — GPU-accelerated 2D drawing with shader support. Can render gradients, particles, glow effects, and smooth morphing. The right tool.

Skia lets us define the orb as a shader program where emotion state variables (color, pulse rate, particle density, size) are uniforms that update in real time over the WebSocket emotion channel. When the server sends { type: "emotion", state: { mood: "happy", intensity: 0.8 } }, the orb transitions smoothly from its current state to warm gold with bouncing particles. No animation keyframes to author per emotion — the shader interpolates continuously.

This also means future emotion states can be added without new animation assets. If the emotion engine starts distinguishing between "content" and "peaceful" or between "anxious" and "frustrated," the orb can express the difference through parameter interpolation alone.

What This Adds Up To

The visual identity of Mio v2 is defined by absence. No avatar, no chat bubbles styled to look like they're from a specific character, no tab bar full of features. Just a warm, dark canvas with a single living point of light that breathes and shifts with emotion.

Every design decision reinforces the same thesis: a companion's identity should come from the relationship, not from a character sheet. The orb gives you emotion without identity. The onboarding starts a conversation, not a configuration wizard. And the personality system bets that emergence beats authorship — which is a bet I won't be able to evaluate until real users have spent three months with it.

In Part 3, I'll dig into the engineering side — how we're extracting the memory system and emotion engine from Mio v1, what the new 4-table database schema looks like, and why starting a fresh codebase was the right call despite having 80% reusable code.


© Xingfan Xia 2024 - 2026 · CC BY-NC 4.0