Kotonia
ログイン今すぐ始める

Kotonia Articles

号称 voice-first,就别在屏幕中央放『开始录音』按钮

我的 AI 角色聊天应用号称 voice-first,但手机屏幕底部正中央却横亘着一个巨大的录音按钮。一个 CSS bug 报告,最终变成了一场关于产品理念与 UI 一致性的拷问。

作者 3分钟阅读
#用户体验#独立开发#移动端#产品设计#语音UI
其他语言日语英语

TL;DR

我做的 AI 角色聊天应用 (Kotonia) 号称是 voice-first (语音优先)。结果手机打开一看,屏幕底部正中央横亘着一个 96 像素的巨大麦克风按钮,配文「点击开始对话」。

这不是 bug,是结构性的自我矛盾。一个号称 voice-first 的产品,把「进入语音模式」的按钮摆在屏幕中央,UI 就在暗中宣告:「语音其实是个可选项」。

这篇记录从用户的一句「手机端界面坏了」开始的 bug 调查,最终如何演变成一场关于产品理念与 UI 一致性的拷问。

起点只是一个普通的 mobile CSS bug

第一条报告就这么一句:

角色聊天页面在带头像的时候,移动端布局坏了。查一下。

定位下去发现 .voice-grid 在移动端是单列布局,两个子元素 (头像区和聊天区) 都设了 height: 100%。CSS Grid 默认 align-content: stretch,于是高度直接被五五分:

  • 头像区 → 全身只能看到上半截,脸被挤在正中间显得很小
  • 聊天区 → transcript 设了 flex: 1,但底部 mic 按钮 (96px) + composer + 状态文字 + hint 占了约 250px,留给文字阅读的空间只剩 90px

两边都没法用。

第一步结构修复: B 方案 (Reels 语法)

懒省事的话用 grid-template-rows: minmax(40vh, 45vh) 1fr 就行——头像上面,聊天下面 (A 方案)。但我同时抛出了 B 方案:

头像做满屏背景,transcript / 控件作为半透明 overlay 叠在上面。Reels / TikTok 那套竖屏视频语法。

用户选了 B。我实现完发了截图,回信是这样:

屏幕 80% 都被对话和 overlay 占了的话,可爱的头像就算努力跟你说话也没法专心欣赏。

也就是说,即使切到 B 布局,主角应该是语音 + 头像,但屏幕的主角依然是文字信息——又一层矛盾。话题从物理 UI 切到了产品哲学。

巨型麦克风按钮的可疑性

用户的下一句话是决定性的 (原文几乎照搬):

底部那个按钮做这么大,目的不就是让"开始对话"看起来很显眼吗?要是一开始就处于待命状态启动,这个按钮和"点击开始对话"的文字和那些无用空间都能省掉。

翻译成产品语言: 一个号称 voice-first 的产品,把「进入语音模式」的按钮放在屏幕中央,就是在自相矛盾

因为:

  • voice-first 意味着语音是默认状态,而不是选项
  • 既然是默认状态,「进入语音模式」这个动作根本不该存在
  • 屏幕中央的巨型按钮其实在宣告:「语音是只有按下这个按钮才会运作的副功能」
  • 这不是 voice-first,这是 voice-as-feature (语音作为附加功能)

Pi.ai 和 Sesame 的沉浸式体验之所以成功,正是因为「上来就 voice on、UI 极简」。Kotonia 想往那个方向靠,就得先把大按钮干掉。

三项重设计决策

跟用户来回交换意见之后,定下了下面这套方案:

1. 完全砍掉巨型麦克风按钮

底部的 MicButton、状态文字 (<p>tapToStart</p>)、hint (<p>VAD 自动监听中</p>) 全部删除。底部只留 composer (文本输入框) 和发送按钮。

2. 状态 + 开始/停止 整合到右上角 (statusPill)

<button onClick={handleSessionToggle} className="voice-statusPill">
  <span className="voice-statusPill-dot" />
  <span>{voiceState === "stopped" ? "START" : voiceState.toUpperCase()}</span>
</button>

一个 pill 同时承担三件事:

  • 显示状态 (LISTENING / THINKING / SPEAKING 用脉动小点表示)
  • 点击启动 / 停止
  • 之前头像右上的「状态 badge」原本就是重复的,现在一并合并

3. cinema / chat 双模切换

localStorage 持久化,右上角 🎬 / 💬 切换按钮:

  • cinema (默认): 不显示 transcript。头像占屏幕 9 成。底部只有 composer + 必要时显示的 chip
  • chat: transcript 以 max-height: 48vh + backdrop-blur 叠在底部。用于想回看对话的时候

「想读对话内容的人」和「想专注于头像的人」用同一个 UI 同时服务,双模切换是最直接的解法 (也考虑过用透明渐变让中央透明,但这会把可读性变成二值化体验,所以否决)。

4. 启动触发器是「用户表达意愿的那一刻」

大按钮砍了,那么 session 什么时候启动?答案是:

  • 点 suggestion chip → 自动 startSession()
  • composer 提交 → 自动 startSession()
  • 点击右上 statusPill → 直接进入 voice (适合不想点 chip 的人)

把「表达意愿」和「启动 session」压缩到一个动作里。「为了进入语音模式而点的前置按钮」彻底消失了。

最终成品

cinema 模式显示。头像占屏幕 9 成,右上角有 START pill 和模式切换,底部是 composer 和 chip 的细条

右上是 START pill (停止时是橙色小点,运行中根据状态在蓝/紫/橙之间脉动) 和 🎬 ⇄ 💬 的模式切换。底部是 chip + composer 的细条。中央 9 成是头像,完全不被打扰。

「voice-first 产品」这个说法,终于和 UI 一致了。

学到了什么

"voice-first" 不是技术栈选择,而是 UI 空间分配的问题

用 Whisper、关心 TTS 质量、调 LLM 延迟——这些是支撑 voice-first 的技术,但不是 voice-first 本身

真正决定能否自称 voice-first 的,是 UI 上语音是否占据画面中央,文本输入是否被作为「辅助手段」缩小处理。这个空间分配决策才是名号的资格证。

如果有「进入语音模式」的按钮,那这个主张就是假的

这套测试在 voice 之外也适用:

  • AI 聊天产品里如果有大大的「向 AI 提问」按钮,那不是 AI-first,是 AI-as-feature
  • 实时产品里如果有「开启实时」按钮,那不是 realtime-first
  • 协作产品里如果有「切换到协作模式」按钮,那不是 collab-first

凡是号称自己是「产品核心」的东西,根本不该需要被开启。它本来就应该已经在那儿

Bug 报告是产品哲学的试金石

整件事最开始就是一个普通的 CSS bug 报告。但是抽象层级一级一级往上爬:「移动端 CSS 坏了」→「B 布局」→「依然占了 8 成」→「巨型按钮疑案」→「voice-first 到底是个啥?」

一个人做产品,很少有机会自问「这个 UI 元素现在还配得上它占据的空间吗」。用户的 bug 报告里,除了表面的 UI 问题,有时会夹带一种「UI 正在背叛产品本意」的隐性信号。如果能听到那个信号,判断可能会比原始工单往上跳三个抽象层级。

每次自查「产品理念和 UI 一致吗」的时候,能怀疑掉一个巨型按钮,自称 voice-first 这件事就能从场面话变成认真说得出口的承诺,大概吧。


Kotonia 可以在 kotonia.ai 体验。手机上打开 /chat/voice,巨型按钮已经消失,头像应该占了屏幕 9 成。

Kotonia 将语音 AI、AI 聊天、图像生成和团队协作整合到一个 AI 工作区中。

试用 Kotonia