周五晚上的客厅,电视开着,五六个人窝在沙发上,有人从果盘里抓起一把瓜子,有人翻找手机的遥控App。朋友说想唱周杰伦,但遥控器在隔壁人手里,搜索框里刚打出“七里香”,YouTube自动播放了一段15秒的广告;另一个人等不及插播了林俊杰,原唱者的嗓音猛然压过对话声。“下一首是什么?”没人知道。队列在哪?也没有。客厅乱成一片。那个想唱歌的周末,最后变成一场传递手机、协商歌单、反复道歉“我按错了”的混乱剧本。这种场景我太熟悉了——不是因为作为客人抱怨过,而是为了让这些瞬间不再发生,我自己动手写了一个应用,还给GitHub的Finish-Up-A-Thon挑战赛提交了上去。
应用叫VKara,是个完全跑在浏览器里的卡拉OK房间。它没有试图取代YouTube:YouTube在播放视频这件事上已经做到极致,几乎能搜到所有我们想唱的伴奏。可YouTube的设计初衷,并不是让一屋子人同时点歌、排队、切歌、暂停。K歌夜需要的不是一台视频播放器,而是一个能容纳多人同时操控的遥控系统。VKara恰好补上了这个缺口。用法很简单:把电视或笔记本打开,作为主播放屏幕,其他人用自己的手机,输入4位数房间码或者扫一下二维码,就能进入同一个房间。接下来,每个人都能搜索歌曲、把歌加入播放队列、暂停、恢复甚至跳过当前曲目。电视只负责播放,所有人的手机都成了专属遥控器。
想法一句话就能讲清楚:让手机变遥控器。但把这件“简单的事”落地,花了远超一个周末的时间。我在2025年初第一次动手写原型。当时的动机非常个人——只想有个更顺畅的方式,喊朋友来家里合唱,不用再烦恼原始的那套流程:电视打开YouTube,搜索伴奏,手机传来传去。那套流程技术上也能用,却总透着笨拙。一个人搜索歌曲时,另一个人可能误触立刻播放;有人想知道下一首是什么,却找不到队列;投屏通常还得所有人连在同一个WiFi下。这些细碎的不适感叠加起来,就是一场夜晚的体验塌方。
第一版原型跑通的那刻,我有种危险的满足感:它确实证明了这个想法可行,却还不足以支撑一个真正的K歌之夜。产品的问题非常具体:前端和后端对房间状态、队列内容、视频元数据、播放器命令以及WebSocket消息的认知必须完全同步,如果这些“契约”散落在不同仓库的不同角落,每一次改动都像在钢丝上调整重心。VKara是个实时应用,前后端的合拍程度直接决定了当有人点歌时,另外五部手机上的显示会不会同步更新,会不会出现歌曲被吞掉、排队混乱的尴尬。契约不一致的时候,任何小修改都能引发潜在地雷。于是,我停了工。不是因为想法不好,而是项目变得难以修改。每改一行代码,心跳都快半拍,这种状态没法持续。
今年再捡起这个项目时,我憋住了所有想加新功能的冲动,决定先让整个项目“安全可改”。做出的第一个大动作,是把原先各自独立的前端仓库和后端仓库塞进一套Bun工作区单体仓库里。现在的结构是这样的:apps/web是基于Next.js的前端,apps/api是基于Elysia和WebSocket搭建的后端,而packages/shared-types负责存放共享的API及WebSocket通信契约,packages/shared-utils收纳那些共用的辅助函数。这一调整的意义,远比整理文件夹深远。原先前后端各自为政时,改一个接口参数往往要在两个仓库间来回核对、小心翼翼地手改两边,生怕某处的类型定义对不上;而现在,共享类型包成了唯一的真相源,前端和后端同时引用同一份定义,契约不再需要靠人脑记忆来对齐。这项改动直接重塑了开发节奏——不再一碰代码就担心敲断什么隐蔽的连接,调试时看到的异常信息也终于指向真正出错的地方,而不是契约不匹配带来的假警报。
重构带来的松弛感,或许才是开发这类实时协作应用真正的门票。VKara做的是让一群人同时操控一个屏幕,背后依赖的WebSocket连接、房间状态广播、队列原子化更新,每一项都要求前后端行为像同一个人写的。把项目结构理顺,不是为了代码的洁癖,而是为了下一次朋友聚会前,当你想加一个“降低伴奏音量保留原唱”的小功能时,不用再犹豫半天,最后把代码搁回原处。现在,虽然演示版还跑在非常有限的资源上,但点歌流程干净得只剩:加入房间、搜索歌曲、选择动作、控制播放。手机上的界面不再像被硬塞进卡拉OK场景的视频App,而像一个专门为“多人同时点歌”设计的遥控器。
在线下聚会逐渐回归的当下,许多人重新体会了共享屏幕的别扭感。投屏需要统一WiFi、蓝牙连接不稳定、排队全靠口头协商,这些槽点没人想忍受第二遍。VKara无意去替代拥有海量曲库的YouTube,但它抓住了一个被长期忽视的细节:在一群人面前,视频播放器缺的,是一套能被每个人平等使用的控制权分发机制。把房间码贴在茶几上,每个人扫一下,所有手机就变身为共同的播放遥控器,歌单透明,排队有序,切歌也不用起身抢遥控。这个逻辑不复杂,却需要极稳定的实时同步来兜底,而这就是那个“After the”之后的沉默地带里,重新铺下的工程基石。
热门跟贴