一副每天戴在耳朵里的耳机,除了播放声音,还能做什么?
当我们转头时,AirPods 里的声音会跟着空间改变。这让我产生了一个好奇的念头:既然耳机知道头正在移动,它能不能把这种理解交给电脑?也许我们不必再增加一个新设备,只要轻轻抬头、低头或转头,就能表达自己的意图。
于是我们做了一个实验。它没有从代码开始,而是从一连串问题开始:耳机究竟知道什么?Apple 愿意向第三方开放什么?别人做到过什么?我们又能把它变成怎样的新体验?
借助 VibeCoding,这些问题一步步变成了可以亲手体验的软件。本文要分享的不是一堆技术名词,而是这段从好奇、调研到真实产品的过程,以及一套零基础用户也能复用的方法:
产生创意 → 调研硬件与开源项目 → 制定阶段目标 → 目标、AI 实现、灰测 → 根据真实反馈进入下一轮。
读完后,你不一定会立刻变成程序员,但应该能够带着一副兼容的 AirPods 和一台 Mac,指挥 AI 复刻出同类项目。
一、最后做出了什么
我们把它叫作“头部鼠标”。
戴上 AirPods,打开 Mac 上的应用,屏幕中央会出现一个十字和一颗小球。你向哪边转头,小球就向哪边移动;动作幅度还可以按照自己的习惯调节。轻轻打开一个开关,小球的控制就会延伸到整个电脑:你的头部开始带动鼠标光标,回到正前方,光标便安静地停下来。摘下耳机,控制会自动关闭。
它不要求用户再购买一件陌生的外设,也不要求先学会一种复杂的操作语言。戴上原本就在使用的耳机,头部就多了一种与电脑交流的能力。
今天,它还是一个内部测试原型;但我们已经能看到它可能走向的地方。
在游戏里,转头不再只是现实中的动作:它可以让玩家探身观察、操纵飞行,或与视线和手柄协作,创造前所未有的游戏体验。在日常工作中,它可以和语音、眼动或 AI 助手配合,用一个很轻的动作完成选择与确认。对于瘫痪、上肢活动受限,或难以长期使用传统鼠标的人,它也可能成为另一条操作电脑的通道。
这让项目同时拥有两种价值:在技术上,它探索一种随身、自然的新输入方式;在社会层面,它让“操作电脑”这件事有机会适应更多不同的身体,而不是要求所有人都去适应同一种鼠标和键盘。
当前版本已经可以显示头部响应、调节灵敏度、控制系统光标、在耳机断开时安全停止,并打包给其他 Mac 用户测试。它还没有完成点击、离散点头和摇头指令,也不是医疗器械,但最关键的一步已经发生:一个好奇的想法,真的变成了可以体验的产品。
二、方法的外环:从创意走到阶段路线
整个项目有一个外层流程,也有一个不断重复的内层循环。
- 创意:耳机能否成为 AI 输入设备?
- 硬件与平台能力调研
- 行业与开源项目调研
- 制定分阶段目标
- 目标
- AI 实现
- 真实硬件灰测
↻ 反馈形成下一轮目标
外环负责避免方向错误:这个创意是否可行,硬件到底有什么,公开软件接口允许做什么,别人已经走到哪里。
内环负责让产品真正长出来:每一轮只确定一个可观察目标,让 AI 做出最小版本,再用真实硬件和真实用户去灰测。
没有外环,AI 很可能迅速实现一个建立在错误假设上的产品;没有内环,调研就会变成一堆永远不会运行的文档。
三、创意阶段:先问“为什么”,不要先问“怎么写代码”
AirPods 支线来自“手柄 VB”项目的第一性原理:我们希望提高人与 AI 之间的交互效率。PS5 手柄是一种输入设备,耳机同样也可能成为输入设备。真正重要的不是把功能绑定在哪个按钮或动作上,而是能否降低用户表达意图、确认操作和感知 AI 状态的成本。
所以最初的问题不是:
“请帮我写一个读取陀螺仪的 Swift 程序。”
而是:
“我可不可以写一个第三方 Mac 程序,捕捉 AirPods 的摇头动作?如果可行,它是否能成为一种更高效的人机交互方式?”
这两个问题看起来接近,方向却完全不同。第一个问题已经默认了技术方案和数据一定存在;第二个问题先允许答案是“不行”,也允许调研后改变实现路线。
对零基础用户来说,这是第一条重要经验:
你不需要先知道技术答案,但要先说清楚自己想改变哪一种用户体验。
四、调研阶段:硬件存在,不等于第三方程序能够读取
硬件项目最容易掉进一个陷阱:产品页面写着“有传感器”,我们就自然认为程序可以读取它。
实际至少要连续问四个问题:
- 这项硬件能力是否真的存在?
- 操作系统是否使用了它?
- Apple 是否提供第三方公开接口?
- 公开接口给的是原始数据、处理后的数据,还是只有系统内部功能?
围绕这四个问题,我们先做了一轮硬件、平台接口与开源项目调研。
4.1 我们真正确认了什么
Apple 提供了公开的 CMHeadphoneMotionManager。对于支持动态头部追踪的耳机,macOS 14 及以后可以取得经过 Core Motion 处理的运动对象。应用可以关注姿态、旋转速率、重力、用户加速度和数据来源等信息。
但我们没有把它描述成“读取 AirPods 全部传感器”。原因很简单:
- 姿态和角速度输出不等于直接读到了某个陀螺仪芯片的原始寄存器。
- 耳机里的皮肤检测、光学检测、触控、麦克风和其他部件,并不都向第三方开放原始数据。
- Apple 系统能够识别某些点头、摇头交互,不代表存在一个通用的第三方“摇头事件”接口。
- 公开接口一次表现为一条运动数据流;左右耳由系统选择,并通过数据帧中的位置标记告诉应用当前来源。
这一步让项目从“我要读取所有传感器”收敛成一个可以验证的目标:
先取得公开运动数据,再判断它是否足以支撑头部交互。
4.2 心率支线为什么没有硬塞进 Mac 版本
后来我们发现新款 AirPods 具备心率能力,于是自然产生了新需求:“把心率也读出来。”
调研后的结论不是继续向当前 Mac 程序堆代码,而是先停下来确认平台边界:心率面向 iPhone/iPad 的 HealthKit 训练场景,Apple 的 HealthKit 设置文档明确标注该框架不适用于 macOS。于是我们只开始了 iPhone/iPad 伴侣应用原型,设想在移动端取得心率后通过本地连接发送给 Mac;它目前还没有完成真机集成,也没有进入 v0.2.0。
这个看似“没有完成”的结果,恰好体现了方法论:
调研的价值不只是证明能做,也包括及时证明当前路线不该继续做。
五、开源项目调研:不是找一个仓库照抄
我们使用的关键词不是一个,而是按问题分组组合:
CMHeadphoneMotionManager macOS
AirPods head motion macOS
AirPods motion sensor GitHub
AirPods head tracker open source
CMDeviceMotion headphone sample
AirPods gesture recognition
head motion control desktop macOS
搜索结果中,最有价值的项目包括:
左右滑动查看完整表格
| 项目 | 它证明了什么 | 我们怎样使用 |
|---|---|---|
| AirPodsPro-Motion-Sampler | 运动数据可以展示、驱动界面并导出 | 下载源码,学习 API 生命周期和字段基线 |
| HeadphoneMotion | 最小的耳机运动采集链路可以成立 | 用来理解最小结构 |
| AirPosture | 运动数据可以进一步转化为行为判断和反馈 | 学习“数据→判断→反馈”的产品闭环 |
| airtracker | macOS 头部追踪可以桥接给其他应用 | 参考桌面事件桥接方向,不直接假设许可证和兼容性 |
我们最终实际下载并阅读了 AirPodsPro-Motion-Sampler。它帮助 AI 核实 CMHeadphoneMotionManager 的启动、权限说明、数据字段和用运动数据驱动 UI 的方式,但 EXP-004 的 macOS 界面、相对姿态、灵敏度、连接恢复和打包流程仍然重新实现。
开源调研的正确目标不是“找到代码复制”,而是回答三件事:
- 这条路是否已经有人走通?
- 哪些接口和工程结构可以复用认知?
- 我们真正要解决的空白是什么?
对本项目来说,开源项目证明了采集可行;我们的空白是把它变成一个普通用户能看懂、能调节、能灰测并能真正控制电脑的头部输入工具。
六、把远目标拆成看得见的阶段目标
“用 AirPods 提高人与 AI 的交互效率”太大,不能直接交给 AI 一次完成。我们把它拆成五个阶段,每个阶段只回答一个主要问题。
左右滑动查看完整表格
| 阶段 | 当时的目标 | 用户能看到的验收结果 |
|---|---|---|
| 0. 可行性调研 | 确认公开接口、硬件边界和开源参考 | 得到有来源、有边界的调研结论 |
| 1. 数据可见 | 读取运动数据,并映射到十字靶小球 | 转头时数字刷新,小球跟着移动 |
| 2. 输入可用 | 修正方向、灵敏度、窗口布局和左右耳切换 | 动作方向符合直觉,小动作可调,窗口可用 |
| 3. 系统控制 | 增加“头部鼠标” | 开关打开后能用头部移动系统光标 |
| 4. 内部交付 | 让同事能解压、打开、测试并反馈 | Universal 2 ZIP、测试说明、真实解压复验 |
我们还没有进入的下一阶段,是录制动作样本、识别离散点头/摇头、建立置信度和冷却机制,再把经过验证的动作接入 AI 意图层。
阶段目标有一个共同特点:它们都能被普通用户直接观察。不要写“完成运动数据抽象层”,而要写“我向右转头时,小球向右走”;不要写“建立分发链路”,而要写“同事在另一台电脑解压后,能看到窗口并按说明反馈”。
七、方法的内环:目标、AI 实现、灰测
项目真正推进,靠的是不断重复下面三件事。
7.1 目标:每次只定义一个可观察结果
目标不是功能名,而是用户动作和系统结果。
一个合格的目标可以写成:
当我佩戴 AirPods 并启动程序时,屏幕显示实时运动数据。
以当前姿态归零后,向右转头时小球向右移动,抬头时小球向上移动。
X、Y 灵敏度可以分别调整,小幅动作也能让小球移动到十字边沿。
它同时包含了前提、动作、结果和验收方式。AI 不必猜“做完”是什么意思。
7.2 AI 实现:不只是生成代码,还要启动和验证
在我们的项目里,“AI 实现”至少包括:
- 阅读项目日志和已有文件。
- 根据目标提出最小技术方案。
- 参考官方接口和合适的开源项目。
- 修改代码和文档。
- 编译、启动程序。
- 检查窗口、关键控件、设备状态和实时数据。
- 增加能够防止问题复发的自动测试。
- 把真实结果和未完成事项写入项目日志。
如果 AI 只说“代码已经写好”,却没有启动、没有真实设备状态、没有窗口证据,那还不能算完成。
7.3 灰测:把真实人的一句话当成下一轮输入
灰测不是等所有功能完成后才进行的大测试。它发生在每一轮,而且往往只需要一句非常具体的反馈:
我向右转头,小球却向左移动。
好的灰测反馈最好包含四项:
我的动作:向右转头。
我预期看到:小球向右移动。
实际看到:小球向左移动。
环境:真实 AirPods 已连接,数据约 50 Hz,其他数值持续刷新。
这比“程序不好用”更能帮助 AI 定位问题。AI 可以据此判断是耳机坐标系与屏幕坐标方向相反,而不是传感器断开或界面卡住。
灰测不是项目的最后一道门;灰测是下一轮需求的生成器。
八、六次真实反馈,软件是怎样长出来的
下面这些不是虚构的产品故事,而是项目中实际发生过的反馈。它们展示了 VibeCoding 最有临场感的部分:用户说出现象,AI 根据证据修改,下一版立刻运行。
第一次:传感器真的有数据吗?
目标: 先看到数据,不先做动作分类模型。
AI 实现: 构建原生 macOS 应用,显示姿态、四元数、角速度、重力、用户加速度和十字靶;加入当前姿态归零与 X/Y 灵敏度。
灰测: 真实 AirPods 持续输出约 50 Hz 数据。X 轴灵敏度调到 8× 后,大约 2.2° 的小幅偏转就能让圆球接近边沿。
结论: 第一阶段最重要的假设成立——公开运动流足以支撑连续头部控制。此时没有必要先训练机器学习模型。
第二次:“左右是反的”
用户反馈非常直接:
“我向右转头的时候,小球却往左侧移动。”
AI 检查后确认,当前 AirPods 的 yaw 符号与屏幕 X 方向相反。下一版只修改映射方向,并增加回归测试:AirPods 的负 yaw 应该变成屏幕正 X。
这一轮没有大改架构,却极其重要。硬件坐标系没有“符合人类直觉”的义务,方向必须通过真实动作校准。
第三次:“窗口放大,组件没有跟着放大”
程序能运行,不代表界面已经可用。用户把窗口放大后发现,左侧十字靶仍然维持固定大小。
AI 把固定高度改成响应式布局:左侧主要交互区域跟随窗口扩大,右侧数据和底部控制保持原尺寸。然后实际检查默认窗口和放大窗口,不只看代码约束。
这一轮说明,灰测不仅验证“功能有没有”,也验证信息是否以用户期望的方式呈现。
第四次:“为什么只采一只耳朵?左耳单独戴不能控制”
最初我们以为程序似乎只用了右耳。检查代码和数据后才发现,应用没有固定选择右耳;公开接口本来就只给出一条系统当前运动流,并在每一帧标记数据来自左耳还是右耳。
于是 AI 增加了耳侧显示和切换自动归零。但继续灰测时,只戴左耳仍然不能控制。真实界面显示系统仍把右耳当作当前来源。最终结论不是“继续写代码强制左耳”,因为公开 API 没有这个能力;正确恢复方法是开启 AirPods 自动入耳检测,把右耳放回充电盒并合盖,让系统把运动流切到左耳。
这是一轮非常典型的边界判断:有些问题应该改代码,有些问题应该修改设备设置,还有些问题公开接口根本不能绕过。
第五次:“同事电脑有进程,但没有窗口”
同事发来的 Console 日志里没有崩溃、权限拒绝或签名错误,反而显示进程已经运行、WindowServer 已建立绘制状态,但随后变成不可见状态。
AI 没有继续把问题归因于“同事不会打开”,而是回到窗口生命周期:旧版只在启动完成时显示一次窗口,没有处理重复打开、点击 Dock、最小化恢复、隐藏状态和不同桌面空间。
下一版统一了窗口显示流程,并为 Console 增加 EXP004_WINDOW_PRESENTED 诊断记录。真实界面检查确认窗口获得焦点,而不是只根据进程存在就宣布成功。
第六次:从“会动的小球”到“头部鼠标”
当连续二维控制稳定后,目标自然升级:增加一个开关,真正用头部移动鼠标。
AI 没有把头部角度直接硬映射到屏幕绝对位置,而是采用更容易控制的速率方式:回正停止,偏转越大移动越快;加入死区抑制自然抖动;每次开启自动归零;耳机断开时自动关闭。
测试不只检查开关文字。我们在正常用户会话里让光标移动 4 px,确认它到达目标后再恢复原位置;最终 ZIP 解压出的 Universal 2 应用又重复了一次测试。
随后 AI 生成原创图标、写入 .icns、构建 arm64 + x86_64 应用、打包 ZIP、重新解压并验证窗口、图标、数据、签名结构和测试说明。
九、一张“失败状态”截图,为什么也值得放进文章
分享项目时,人们很容易只保留最漂亮、最成功的画面。但真实项目的可信度,往往来自它怎样处理失败:断开是否可见,危险功能是否自动停止,用户是否知道下一步做什么。
十、零基础复刻路线
下面的路线不要求你先学会 Objective-C。你需要做的是准备环境、把目标说清楚、允许 AI 操作项目文件,并亲自完成真实耳机测试。
10.1 准备条件
- 一台运行 macOS 14 或更高版本的 Mac。
- 一副支持动态头部追踪、能够连接这台 Mac 的 AirPods 或兼容 Beats 耳机。
- Xcode Command Line Tools,或完整 Xcode。
- 一个能够读取和修改本地项目、执行终端命令的 AI 编程工具。
- 一个独立项目目录,以及持续记录过程的项目日志。
不要在一开始要求 AI 使用蓝牙逆向或私有协议。先坚持公开 Core Motion 路线,这更稳定,也更容易让其他人复刻。
如果 Mac 尚未安装 Command Line Tools,可以先在“终端”中执行:
xcode-select --install系统会弹出安装窗口。你不需要理解编译器的细节,只需要知道后面的 AI 会用这些官方工具把源码构建成 .app。
10.2 第一步:让 AI 先调研,不写代码
可以直接使用下面的提示词:
我想探索:能否在 macOS 上读取已佩戴 Apple 耳机的运动数据,识别头部动作,
并把它发展为控制鼠标或与 AI 交互的输入方式。
本轮只调研,不写程序。请完成:
1. 调研 Apple 耳机公开的硬件传感器和不同型号差异。
2. 区分“硬件存在”“系统内部使用”“第三方公开接口可读取”三种状态。
3. 核实 macOS 的公开 API、最低系统版本、权限和数据字段。
4. 搜索类似开源项目,记录平台、许可证、可复用部分和风险。
5. 明确哪些是处理后的运动数据,哪些原始数据拿不到。
6. 给出分阶段实验路线、成功标准和停止条件。
要求优先引用 Apple 官方资料和原始开源仓库,不要把推测写成事实。
10.3 第二步:只做第一阶段可视化原型
根据已经完成的调研,制作第一阶段 macOS 原型。
目标:佩戴兼容 AirPods 后,窗口实时显示 Core Motion 提供的姿态、旋转速率、
重力、用户加速度、数据来源和采样率。屏幕中央显示十字靶和圆球:左右转头控制 X,
抬头低头控制 Y;X/Y 灵敏度可以分别调整,并支持以当前姿态归零。
约束:
1. 使用 Apple 公开 API,不使用私有蓝牙协议。
2. 第一阶段不做机器学习和离散动作分类。
3. 必须包含 NSMotionUsageDescription、连接/断开状态和无设备提示。
4. 完成后自动编译、启动并检查真实窗口,不得只说代码已生成。
5. 增加方向、灵敏度和角度环绕的自动测试。
6. 区分自动测试结果与真实 AirPods 实测结果。
如果你想严格复刻本项目,可让 AI 采用原生 AppKit + Core Motion;但对初学者来说,技术名不是重点,重点是不要扩大第一阶段范围。
10.4 第三步:使用统一灰测反馈模板
每次体验后,把反馈写成下面的形式:
测试环境:Mac 型号、macOS 版本、耳机型号、连接方式。
我的动作:我实际做了什么。
预期结果:我认为软件应该怎样反应。
实际结果:屏幕、鼠标或耳机实际发生了什么。
可见证据:界面状态、数据来源、采样率、截图或日志。
请先判断根因,再决定需要改代码、改设备设置,还是接受平台边界;
修复后增加回归测试并重新启动让我验证。
不要只说“有 Bug”。真实动作和实际结果,是你提供给 AI 最有价值的数据。
10.5 第四步:再增加头部鼠标
在连续头部姿态控制已经稳定后,增加开关型“头部鼠标”。
要求:
1. 默认关闭,不保存开启状态。
2. 开启时按当前头部姿态自动归零。
3. 回正停止,偏转越大鼠标移动越快,并设置死区避免自然抖动造成漂移。
4. 左右和上下方向必须符合用户直觉。
5. AirPods 断开、重新检测或移动失败时自动关闭。
6. 不模拟点击,只使用公开接口移动光标。
7. 用数学单元测试验证死区、速度和方向;再做一次小距离真实光标移动并恢复原位的烟雾测试。
10.6 第五步:让 AI 按同事真实路径打包测试
完成代码后制作内部 macOS 测试包。
要求:
1. 同时构建 arm64 和 x86_64,生成 Universal 2 应用。
2. 生成原创应用图标并写入应用包。
3. ZIP 内同时放入应用和零基础同事测试说明。
4. 打包后重新解压到新目录,不要只验证打包前的应用。
5. 检查 ZIP 完整性、Info.plist、图标、两种架构、签名结构和内置测试。
6. 从解压目录实际启动应用,确认窗口、设备状态、关键控件和断开保护。
7. 明确区分 ad-hoc 内部签名与 Developer ID / Apple 公证;不要声称未公证应用可以普通双击无警告分发。
8. 输出 ZIP 路径、大小、SHA-256、已验证结果和未解决边界。
10.7 你怎样判断自己真的复刻成功
不要用“AI 说完成了”作为标准。至少亲自检查:
10.8 如果你直接拿到本项目源码
当前实验已经把构建和测试收敛成两个脚本。进入实验目录后执行:
cd "$PROJECT_DIR"
./tests/run_tests.sh
./build.sh --zip第一个命令会编译程序并检查姿态映射、头部鼠标曲线、图标、两种 Mac 架构和签名结构;第二个命令生成内部测试 ZIP。
脚本通过仍然不能替代佩戴测试。构建完成后,继续按照上一节的清单戴上耳机、检查方向、开关、断开保护和解压后的程序。
十一、零基础用户在 VibeCoding 中真正负责什么
完全没有编程基础,不意味着你在项目里没有不可替代的职责。恰恰相反,你负责的几件事决定了项目会不会走向正确方向。
1. 定义体验,而不是假装懂技术
你可以不知道 yaw、四元数或 Core Graphics,但你知道“向右转头,鼠标应该向右”。把这个体验讲清楚,比随便指定一个技术方案更重要。
2. 提供真实世界
AI 能写测试,却不能替你戴上耳机。单耳佩戴、摘下、重新连接、窗口放大、换一台同事电脑,这些都属于真实世界输入。
3. 要求证据层级
同一句“通过”,可能代表完全不同的事情:
官方文档说明支持
≠ 开源项目代码看起来可行
≠ 自动测试通过
≠ 本机真实硬件通过
≠ 同事电脑解压后通过
≠ 可以正式公开分发
让 AI 每次说明证据来自哪一层,可以显著减少“看起来已经完成”的错觉。
4. 决定什么时候停止扩展
心率能力没有因为“耳机里有传感器”就被硬塞进 Mac 版本;离散动作识别没有因为“听起来更 AI”就抢在稳定运动采集之前实现。每轮只解决一个主要假设,项目反而走得更快。
十二、把这套方法带到其他硬件项目
AirPods 只是一个例子。这套方法同样适用于手柄、摄像头、麦克风、智能戒指、手表、机器人或任何新型输入设备:
- 从用户体验创意出发。
- 调研硬件能力、平台接口和开源行业现状。
- 把“存在”“可访问”“已验证”分开。
- 制定每轮都能被普通用户观察的阶段目标。
- 让 AI 完成实现、启动、自动检查和记录。
- 用真实硬件和真实用户灰测。
- 把反馈变成下一轮目标,而不是一次性堆功能。
最终,我们的方法可以再次压缩成一句话:
先产生创意,用调研把创意变成正确的阶段路线;再在每一个阶段里重复“目标、AI 实现、灰测”,直到真实世界愿意承认它可用。
这就是我们做出“头部鼠标”的过程。代码当然重要,但真正让项目从想法走到可运行软件的,是目标、证据和一轮又一轮真实反馈。
