Spare 眼镜应用开发者指南
给 Spare 智能眼镜写小应用:装到眼镜上就能用,不用刷机。界面、计时、动画都在眼镜本地运行,手机只帮你取声明过的数据。
任何 Spare 账号登录后都可以发布应用,不需要申请。
快速开始
- 登录:在 Spare App「创意工坊」右上角点 +,或在电脑上打开 spare.cool/dev,用 Spare 账号登录。第一次登录会自动成为开发者,handle 取自你的昵称(建应用前可以改),应用 id 是
dev.<handle>.<名字>。 - 复制给你的 AI:点「让 AI 帮我做」→「复制给你的 AI」,粘给 Codex、Claude Code、Cursor 或 ChatGPT。它会装上你的专属开发者 MCP(一个地址,当密码对待)。
- 说出你的想法:例如「给眼镜做一个番茄钟并发布到 Spare 创意工坊」。AI 会建仓库、读模板里的规则、写代码。
- 模拟器预览:AI 调用
simulate,拿回眼镜画面截图,自己检查文字有没有被裁。 - 装到自己的眼镜:AI 调用
install_on_my_glasses,你在 App「创意工坊 › 开发者」里点「安装」(需要打开开发者模式)。 - 提交审核:你说「可以发布了」,AI 调用
submit_for_review。自动检查和 AI 初审几十秒内完成,然后由 Spare 人工终审。 - 上架:通过后所有用户都能在创意工坊看到并安装。
也可以不用 AI:网页控制台新建应用、用 git 或 spare 命令行推代码,或在 App 里「上传应用包 (.spa)」。
应用结构
my-app/
├── app.json 清单 + 界面(必需)
├── main.ss SpareScript 脚本(必需)
├── icon.png 44×44 灰度图标(列表里 2×3 格子用)
├── assets/ 可选图片:PNG,宽为偶数,≤ 128×128
└── scenarios/ 模拟器场景(每次云端构建都会跑)
app.json
| 字段 | 说明 |
|---|---|
id | 平台分配的 dev.<handle>.<slug>,不要改 |
name | 列表里的名字,≤ 23 字节(约 7 个汉字) |
version_name | 展示版本,semver,如 1.0.0 |
version | 不用管:平台按构建号自动写(眼镜要求每次更新变大) |
data_version | 持久数据格式版本;变了,更新时眼镜清掉旧数据 |
description | 商店说明 |
permissions | 权限白名单,见下 |
requests | 让手机代取的数据,见「手机数据桥」 |
ui | 界面元素数组 |
界面元素
最多 48 个。公共字段:id(脚本里直接用这个名字)、type、x y w h、hidden。
| 类型 | 字段 |
|---|---|
text | size 12–96、bold、align(left / center / right)、text(≤ 63 字节)、gray |
rect | radius、gray(填充)、border(> 0 只描边)、children(坐标相对它) |
bar | 进度条:value 0–100、gray、track(底色,默认 55)、radius |
image | src = assets/ 里的文件名;不写 src 是空框,image(el, -1) 放手机传来的图 |
main.ss
SpareScript 写法像 JavaScript,只有 32 位整数 和 短字符串(≤ 63 字节)两种值。
var left = 1500; // 全局变量(≤ 64 个)
persist var done = 0; // 持久变量:关掉、重启后还在;改完 save()
fn fmt(s) { return pad(s / 60, 2) + ":" + pad(s % 60, 2); }
on open() { text(time, fmt(left)); }
on crown(d) { left = clamp(left + d * 60, 60, 3600); text(time, fmt(left)); }
on click() { timer(0, 1000, 1); }
on timer(id) { left -= 1; text(time, fmt(left)); }
事件:open close crown(d) click timer(id) data(seq)。语句:var、赋值、if/else、while、break、continue、return。
| 内建 | 作用 |
|---|---|
text show gray move size value image | 改界面 |
anim_x anim_opa anim_scale | 本地动画(≤ 2000 ms) |
timer(id, ms, repeat) | 计时器 0–3,≥ 100 ms;ms = 0 停止 |
now() clock() seconds() | 毫秒计时 / 当天分钟数 / 当前秒 |
str num len sub pad | 字符串 |
min max clamp abs rand | 数学 |
data request connected | 手机数据桥 |
battery save exit | 电量 / 写盘 / 退出 |
权限白名单
| 权限 | 用途 | 审核 |
|---|---|---|
network:<域名> | http_json 请求的主机;必须是公网域名,URL 必须 https | 人工确认主机 |
location | location / weather 请求 | 必须人工审 |
notifications | notify_count 请求 | — |
microphone spare_notes | 眼镜笔记相关 | 必须人工审 |
只申请真正用到的权限。
眼镜画面与交互规范
- 屏幕:540 × 220,单色,亮度 0–255 显示为绿色。重要内容放在 y ≤ 195(最下面约 10 px 会被裁)。
- 图标:44×44 灰度,出现在眼镜应用列表的 2×3 格子里,用简单、粗线条的形状。
- 手势:转表冠 =
crown(+1 / -1),单击 =click。双击永远是退出应用,长按永远是 AI,应用收不到。 - 一屏一件事:一个大字(64–96 px)+ 一行提示(20–24 px,亮度 100–160)。亮度对比就是层次。
- 对用户安全:用户在走路、说话,不要闪烁,不要需要盯着看的小字。
- 配额:每次事件 ≤ 20,000 条指令、≤ 256 次界面调用;包 ≤ 32 KB;眼镜最多装 8 个应用。超配额会显示「应用出错」。
- 只在打开时运行:关掉后不占电。
手机数据桥
眼镜不联网。应用在 requests 里逐条声明数据,眼镜只说「第几个请求 + ≤ 10 字节参数」,URL 永远来自 app.json。
"permissions": ["network:api.example.com"],
"requests": [{ "name": "quote", "kind": "http_json",
"url": "https://api.example.com/q?s={arg}", "fields": { "px": "price" } }]
on open() { request(quote, "AAPL"); }
on data(seq) {
if (data("_err") != "") { text(px, "--"); return; }
text(px, data("px"));
}
kind | 返回 | 权限 |
|---|---|---|
http_json | fields 映射的键 | network:<主机> |
location | lat lon city | location |
weather | temp text icon | location |
time_sync | tz | — |
notify_count | count | notifications |
失败时只回一个键 _err(bad / kind / perm / auth / net)。手机限频 ≤ 1 次/秒。离线时 data() 是上次的缓存,connected() 为假,记得显示「等待连接」。
调试与模拟器
- 本地编译:
python3 tools/spac.py build . -o /tmp/app.spa,2 秒内报编译错误。 - 云端模拟器:MCP
simulate或spare sim,用眼镜上同一份运行时跑场景,返回 1080×440 截图(2 倍)。 - 场景文件
scenarios/*.txt,每行一条:openclosecrown +1crown -1clicktick <毫秒>connect 0|1clock <分钟>reply k=v ...shot <名字>record <名字> <毫秒>。 - 云端构建(每次
git push自动跑):编译 → 清单与权限检查 → 大小与界面限制 → 眼镜字节码验证 → 你的场景 + 平台压力场景(连按、表冠 ±50、断开重连、加速 30 分钟、每个请求回_err)。0 个 FAULT 才算通过。 - 真机:
install_on_my_glasses后在 App「创意工坊 › 开发者」安装;开发者模式只影响安装没审核过的包,一个开关。
审核规则
上架前都要经过:自动检查 → AI 初审 → Spare 人工终审(通常 1 个工作日)。被打回的意见会写进你的仓库 issue,AI 用 get_review_feedback 就能读到。
常见拒审原因:
- 名字或描述与实际功能不符。
- 申请了用不到的权限,或网络主机不明。
- 冒充 Spare 官方或系统界面(假的系统提示、索要密码或验证码)。
- 违法违规内容(赌博、色情、毒品、诈骗、侵权等),在中国大陆和其他地区都不允许。
- 闪烁、诱导用户走路时盯着屏幕。
- 文字被裁(超出 y 195)或离线时一片空白。
用户可以举报应用;违规应用会被下架。
版本与渠道
| 渠道 | 谁能看到 | 签名 |
|---|---|---|
dev | 只有你自己的手机(开发者区) | 平台开发者密钥 |
beta | 测试者 | 创意工坊密钥(审核通过后) |
stable | 所有人 | 创意工坊密钥(审核通过后) |
- 版本号:平台给每次构建分配递增的构建号,你只写
version_name。 - 晋升:
promotedev → beta → stable;beta → stable 用同一个已签包,不重审。 - 回滚:
rollback用旧版本的源码以新构建号重新签名(眼镜要求版本号变大),不重审。如果data_version变过,用户的持久数据会被清掉。
完整示例:喝水提醒
表冠调目标杯数,单击记一杯,进度条显示完成度,数字关掉也记得;完成目标后再单击从头开始。
app.json:
{
"id": "dev.yourname.water",
"name": "喝水",
"version_name": "1.0.0",
"version": 1,
"data_version": 1,
"description": "单击记一杯水,转表冠调每天目标;完成后再单击从头开始。",
"permissions": [],
"requests": [],
"ui": [
{ "id": "big", "type": "text", "x": 0, "y": 30, "w": 540, "h": 100, "size": 88, "bold": true, "align": "center", "text": "0/8" },
{ "id": "bar", "type": "bar", "x": 70, "y": 140, "w": 400, "h": 10, "radius": 5, "value": 0 },
{ "id": "hint", "type": "text", "x": 0, "y": 160, "w": 540, "h": 30, "size": 22, "align": "center", "gray": 130, "text": "单击记一杯 · 转表冠调目标" }
]
}
main.ss:
persist var cups = 0;
persist var goal = 8;
fn draw() {
text(big, str(cups) + "/" + str(goal));
value(bar, min(100, cups * 100 / goal));
if (cups >= goal) { text(hint, "完成了!单击从头开始"); } else { text(hint, "单击记一杯 · 转表冠调目标"); }
}
on open() { draw(); }
on click() {
if (cups >= goal) { cups = 0; } else { cups += 1; anim_opa(big, 80, 255, 300); }
save();
draw();
}
on crown(d) { goal = clamp(goal + d, 1, 20); save(); draw(); }
scenarios/smoke.txt:
open
shot open
click
click
tick 400
shot two
crown +1
shot goal
常见问题
要申请才能发布吗? 不用。登录 Spare 账号就是开发者。
handle 能改吗? 建第一个应用之前可以(网页控制台或 App 开发者区),之后就固定了,因为应用 id 和仓库地址里用到它。
AI 说调不到 MCP? Claude Code 装好后要新开一个会话(或 /mcp 重连)。地址失效了就再「复制给你的 AI」一次,旧地址会作废。
为什么我的应用在眼镜上「应用出错」? 超了每次事件的指令数或界面调用数。检查循环,不要在一次事件里改太多元素。
能收费吗? 暂时都免费。
有数量限制吗? 每个账号最多 30 个应用,每天新建 5 个、提交审核 10 次,每小时构建 60 次。