一、缘起
家里电视的机顶盒当年带了一堆小游戏,我玩得最久的就是推箱子。一个小人,几个箱子,几个目标点,遥控器方向键一下一下挪。那会儿盒子里的小游戏就那几个,推箱子是唯一一个我能坐那儿玩一整个下午的。后来拿到 Rokid Glasses,翻配置表看到它带陀螺仪(姿态传感器),脑子里的第一个想法就是推箱子。
如果小人的方向不是用手按出来的,而是用头转出来的呢?
推箱子的操作就四个方向,上下左右。脑袋转起来呢,也就是这四个方向。所以做的时候没想什么"老游戏移植"的事,单纯觉得合适,就做了。
更实在的原因是脖子。天天对着屏幕,脖子常年是僵的。戴上眼镜玩两把,左右转头抬头低头,几关下来颈椎就顺带活动开了。就当带游戏皮的颈椎操吧,累了来两关,比干做拉伸好坚持。
语音也加上了。喊「上」「下」「左」「右」小人就走一步,「撤销」「重来」「选择关卡」也都认。脖子不想动的时候就躺着,动动嘴也能玩。

二、AIUI 是什么
AIUI 全称 AI 原生用户界面。名字听着唬人,其实理解起来不复杂:给大模型时代用的 UI 框架,开发者跟 AI 协同搭界面,让 AI 的能力从纯文字变成用户能点、能看、能交互的东西。我第一次接触时就是这么理解的。
一个 AIUI 应用的文件结构是这样的:
bash
sokoban/
AGENTS.md # 智能体清单:名字、描述、需要的权限
app.json # 页面路由
app.js # 应用入口
pages/game/index.ink # 页面(单件组件)
assets/ # 图片、音频
AGENTS.md 里写的是小助手该怎么被唤起、需要哪些权限。刚看到这文件名的时候我还愣了一下,跟 AGENT 有关但多了一个 S。
markdown
## Identity
- **Name**: 推箱子
- **Description**: 运行在 Rokid Glasses 上的头控加语音推箱子游戏......
## Capabilities
- **Permissions**:
- motion-sensor
- microphone
- audio
页面用 .ink 单文件组件,四段结构,写过小程序的人几乎零成本:
html
<script def>
{ "navigationBarTitleText": "推箱子" }
</script>
<script setup>
import wx from 'wx';
export default {
data: { levelNo: '01' },
onLoad(query) { /* 初始化 */ },
onKeyUp(event) { /* 镜腿按键 */ },
}
</script>
<page>
<view class="stage">
<text class="hud">第 {{ levelNo }} 关</text>
</view>
</page>
<style>
.stage { display: flex; flex-direction: column; }
</style>
需要注意的是,它的运行时是 Ink(Skia 渲染 + Taffy 布局),不是浏览器。样式和模板支持的是 WXSS/WXML 的一个子集。
这个项目用到了 AIUI 的哪些能力
| 能力 | 用在哪 |
|---|---|
AbsoluteOrientationSensor |
读头部姿态四元数,做头控移动 |
SpeechRecognition |
语音说「上/下/左/右」控制小人 |
Sound |
箱子入位、过关、撞墙、死锁的事件音效 |
wx.setStorageSync |
关卡进度、解锁记录、每关最佳步数、方向校准结果 |
页面级按键事件 onKeyUp |
镜腿单击/前滑/后滑,以及拦截系统默认行为 |
页面生命周期 onShow/onHide |
切后台自动暂停传感器和语音 |
| 沉浸式页面承载 | 被唤起后直接全屏,不走对话卡片 |
三、开发过程
整个项目是用 Claude Code 做的。AIUI 我之前没碰过,所以流程很土:先喂资料让它学,学完再提需求。
第 1 步:先把官方资料喂进去
第一天一行代码没写,全在装官方 skill 和丢资料:
bash
npx skills add https://github.com/jsar-project/AIUI/tree/main/skills/aiui-dev
这一步回头看是关键。AIUI 太新,模型那套"通用前端经验"一半是错的,浏览器里合法的样式它写得可自然了,Ink 根本不认。

第 2 步:把想法说清楚
学完之后我只说了一句大白话:
我想做一个能在 Rokid Glasses 上面运行的推箱子游戏,推箱子的小人上下左右行走的方向能根据头部控制上下左右。这个可以做吗?
问完这句我还真有点怕它回一句"做不了"。
它先回了可行性判断和方案,接着把骨架搭了出来:游戏引擎、头控模块、页面、关卡,连测试都有一套。有一点我一开始没注意,后来才发现它把逻辑和 UI 拆开了------引擎全是纯函数,头控也是纯模块,页面只管渲染和接事件。后面改起来顺,就是靠这个分层。

第 3 步:上真机,坑一个个冒出来
代码能跑不代表能用。真正的开发是从第一次戴上眼镜开始的。第一次戴上真机,第一感受是晕:单绿屏就在眼前亮着,转头的时候画面跟着动,还没开始玩游戏,先适应了十来分钟。这之后,我把真机上看到的现象一条条描述给它,它来定位和修。挑几个最有代表性的:
第一个坑:左右能走,抬头低头不灵
传感器给的是四元数,大家一般解成欧拉角 yaw、pitch、roll 来用。左右转头用 yaw,一次就准。抬头低头用 pitch,就时灵时不灵了,把我整不会了。
后来才搞明白,欧拉角分解依赖旋转顺序,有些姿态下 pitch 和 roll 会互相串。眼镜本身又有个固定的俯仰安装角,两件事叠一起,问题被放大了。我当时还以为是阈值的事,越调越乱。
最后干脆绕开角分解,直接从四元数求「参考系竖直轴在设备坐标系里的方向向量」,也就是旋转矩阵第三行那三个数:
js
// 左右转头时,这个向量数学上保持不变;抬头低头必然让它偏转
const up = {
x: 2 * (x * z - y * w),
y: 2 * (y * z + x * w),
z: 1 - 2 * (x * x + y * y),
};
以校准那一刻记下的 uRef 为基准,算一个带符号的偏角:
js
verticalRaw(pose) {
const u = normVec(pose.up);
const c = crossVec(ctl.uRef, u); // 叉积拿旋转轴
const sinp = clamp(dotVec(c, ctl.rAxis), -1, 1); // 投影到俯仰轴,剔除歪头
return (Math.asin(sinp) * 180) / Math.PI;
}
这么一改,怎么戴都不影响了,歪头那部分被投影直接滤掉。当天换上就通了。
上下的正负号我也不猜了:第一次进游戏让用户低一次头,用实际动作确定符号并本地记住,只做一次。用户的动作永远比我的假设可靠。
第二个坑:头一歪就停不下来
最早一版写的规则是"偏转超过阈值走一步,一直偏着就一直走",写的时候觉得挺合理。真机一戴,不到一分钟我就否了,那感觉跟油门踩死一样,小人直接往墙里冲。后来改成偏转、走一步、锁住。锁住之后怎么解锁,这才是麻烦的,我先试的是"回正到中立区",结果戴着眼镜的人根本不知道"正"在哪,头越摆越偏,越急越回不去。最后定的方案:头停稳大约一秒,就把当前姿态当成新零点,自动解锁。不用回任何特定位置,停一下就行,这个"停"字是关键。
这个改动还白捡一个好处:坐姿变了、传感器漂了,它自己就吸收了,手动校准彻底不用。阈值都集中放一张表里,想调哪个改哪个,不用翻代码:
js
export const HEAD_TUNING = {
yawTrigger: 10, // 左右转头超过 10° 触发
pitchTrigger: 8, // 抬头低头超过 8° 触发
alpha: 0.45, // EMA 平滑系数,抗抖动
rescueAfterMs: 1000, // 停稳 1 秒 → 自动重新定零并解锁
driftAdaptRate: 0.008,// 中立区内基准缓慢跟随,吸收漂移
};
四、成品什么样
创建 Rokid AIUI 项目一共有三种方式。我们是用 claude code 开发的,所以就选了本地导入,把本地项目导入到 Rokid AIUI 里面。

测试的时候可以选真机模拟。

项目测试没问题后,可以点击构建与提审,然后就可以等待官方人员审核啦,审核通过的话就会上架到智能体商店,失败的话官方人员也会告诉你哪点需要改善,改善完成后重新提交即可。

15 个关卡,最少推箱数从 1 到 36 递增,每关都过了一遍 BFS 求解器确认可解。头控是左右转头走左右、抬头低头走上下,走一步锁定,头停稳一秒自动重新定零。语音可以喊「上」「下」「左」「右」,撤销、重来、选关也都能说。进游戏零点击,进度自动存,重进接着玩,切后台自动暂停。

五、总结
AIUI 上手难度不高。会写小程序的话,写 .ink 几乎没门槛,我第一天就把第一个页面跑在眼镜上了。从第一个页面跑到眼镜上,到 15 关全部做完,前后大概花了两周,大头都花在调头控手感上。
回头想,跟它配合有三条经验。头一条,资料先喂够再提需求。官方 skill、文档、示例仓库、设计规范一次给足,等它学完,这一步省下的返工比花的时间多得多。第二条,报问题要具体。跟它说"不好用"没信息量;说"只能左右走,抬头低头没反应""说一次就报语音识别失败"这种,它基本一次就能定位到根因,真机上碰到的每个异常都值得原样复述。第三条,把逻辑挪出 UI。引擎、头控、页面逻辑都能在 Node 里跑,它就能自己写测试、自己发现回归。
工作日晚上写累了,我会真戴上眼镜推两关。左右转头、抬头低头,几分钟下来脖子松快不少。童年那个机顶盒游戏,就这么回到我日常里了,有点意外。
AIUI Studio(中国站):aiui.rokid.com/
AIUI GitHub项目地址:github.com/jsar-projec...
AIUI Gitee项目地址:gitee.com/jsar-projec...
AIUI Skil:github.com/jsar-projec...
AIUI Demo案例:github.com/jsar-projec...