换个吧唧 轻点屏幕试玩 · 右上角切换 APP
今日推荐 · 点选即可试玩
今日推荐
APP 广场按点赞数、评论数依次降序;两项都相同,按应用名首字升序,同首字继续按名称排序。每款应用只入选一次。
广场作品不足三款时,用现有应用补齐三个候选。补位应用显示“精选应用”,不计入社区热度。今天新增的作品和互动会在下次更新时参与排名。
我的设备
每台徽章只记得一个配对的设备;换电脑或手机前,先在徽章上「修复配对」。
开发文档请用电脑打开
开始做应用
- 选电脑
- 下载工具包
- 交给 AI
正在准备开发工具包…
- 准备工具
- 编译
- 试一试
手动开发
1. 准备三样东西
- Python 3.10 以上:运行打包工具。
- Zig 0.13(或能编 wasm32 的 Clang):把 C 编成应用。
- TinyRT SDK:下载本站 S31 SDK和Windows 编译器或Apple 芯片 Mac 编译器(macOS 26.5+),解压到任意目录。
python -m pip install -r requirements.txt
2. 新建一个应用
在 SDK 目录里运行。应用编号可以自由命名;发布时由网站自动检查编号归属和应用内容。
python tools/tinyrt.py new my-game --app-id my-game --title "My game" --template game
会得到一个 my-game 文件夹:main.c 是代码,app.json 是应用的名字、版本和权限。
3. 编译、打包
python tools/tinyrt.py build my-game --cc path/to/zig.exe python tools/tinyrt.py pack my-game --target esp32s31 --wamrc path/to/wamrc.exe
成功后在 my-game/build/ 里有一个 .trpkg 文件,这就是应用包。
4. 在网页里玩
打开模拟器,点「导入应用包」,选刚才的 .trpkg。纯 Wasm 可在模拟器预览;徽章需要包内同时带有预编译版本。上传完整发布包后自动检查,通过即公开。
5. 接下来
读懂第一个应用
一个应用就是三个函数:开始时做什么、有事发生时做什么、画面怎么画。下面这个应用点一下加一,关掉再打开数字还在。
#include "tinyrt.h"
static int32_t count; /* 点了几下 */
int32_t tinyrt_init(int32_t width, int32_t height) {
(void)width; (void)height;
count = kv_get(0, 0); /* 读回上次存的数,没有就是 0 */
return 0;
}
int32_t tinyrt_event(int32_t kind, int32_t x, int32_t y, int32_t arg) {
(void)x; (void)y; (void)arg;
if (kind == TINYRT_TOUCH_RELEASE) { /* 手指抬起算一次点击 */
count++;
kv_set(0, count); /* 存起来,下次打开还在 */
}
return 0;
}
int32_t tinyrt_render(void) {
char text[12];
uint32_t n = 0;
int32_t v = count;
char rev[12];
do { rev[n++] = (char)('0' + v % 10); v /= 10; } while (v > 0 && n < 11);
for (uint32_t i = 0; i < n; i++) text[i] = rev[n - 1 - i];
draw_clear(0x101418); /* 每一帧先清屏 */
draw_round_rect(113, 173, 240, 120, 32, 0xFFC93C); /* 黄色圆角块 */
draw_text_box(113, 173, 240, 120, text, n, 0x151515, 48, 1);
draw_text_box(83, 320, 300, 40, "TAP", 3, 0xC9C7C0, 24, 1);
return 0;
}
三个函数
| 函数 | 什么时候被调用 | 在里面做什么 |
|---|---|---|
tinyrt_init | 应用打开时,一次 | 读存档、设置定时器、订阅按键 |
tinyrt_event | 点击、松手、定时器到点、按键 | 改变状态:加分、移动角色、保存 |
tinyrt_render | 每次事件之后 | 只画画,不改状态。先 draw_clear,再画别的 |
三个函数成功都返回 0。还有一个可选的 tinyrt_stop,应用正常退出前调用一次,用来存档。
屏幕
屏幕是 466×466 的圆。四个角看不见,重要的东西放在中间约 330×330 的区域里(坐标 68 到 397)。颜色写成 0xRRGGBB。
app.json
{
"app_id": "demo.hello",
"title": "Hello",
"version": 1,
"abi_version": 1,
"permissions": 7,
"memory_pages": 2,
"budget": 100000,
"sources": ["main.c"]
}permissions 是用到的能力相加:画面 1、触摸和按键 2、存档 4、定时器 8、声音 16、震动 32。上面的例子用了画面、触摸和存档,所以是 7。每次发新版本,version 加一。
装到徽章
两条路:数据线和蓝牙。已有 community.3 系统的徽章推荐先用 OTA 升级,保留应用。
更新系统
community.3 用户到系统升级页,选择数据线或蓝牙,通过 OTA 更新到 0.1.1,会保留应用。徽章需停在「等待发送固件」页,更新完成后按屏幕提示重启。
系统无法启动时,可展开「恢复出厂系统(整片刷写备用)」。这会清空应用、配对和存档,确认需要恢复后再操作。
用数据线装应用
到装到徽章页选好应用包,或者在社区的作品页点「装到实机」,选数据线。只写应用存储区,其他都不动。
用蓝牙装应用
徽章进「应用大厅」点右上角的 +,屏幕出现 6 位连接码;在作品页点「装到实机」,选蓝牙,浏览器弹出配对框时输入这 6 位。
用命令行
python tools/ble_install.py --scan python tools/ble_install.py --address AA:BB:CC:DD:EE:FF --pair install my-game/build/my-game.trpkg
数据线和蓝牙需要电脑上的 Chrome 或 Edge。
发布包规范
发到社区的作品是一个结构固定的 ZIP。一条命令打出来,网站照着清单逐项检查,通过就能发布。
一条命令
python tools/tinyrt.py release my-game --cc path/to/zig.exe --runner path/to/tinyrt-run.exe --variant wasm-aot
下载 本站 S31 SDK、Windows S31 编译器 / Mac S31 编译器(Apple 芯片、macOS 26.5+)及受信目标契约。从 SDK 根目录执行,将工具路径换成本机实际路径。本站 S31 SDK 发行包提供此命令(见下方下载);设备交付使用固定摘要的 ESP32-S31 AOT 编译器,桌面预览使用真实 WAMR runner。缺少工具时可先用「AI一键部署」提示词让 Agent 准备环境。
命令会编译、执行项目提供的测试、生成运行截图、打包并自检,输出 my-game/release/my-game-v1-wasm.zip。把这个 ZIP 拖进发布页完成在线检查与发布。
你需要准备的
应用目录里放好这几个文件,其余由命令生成:
| 文件 | 内容 |
|---|---|
app.json | 应用名、版本、权限 |
listing.json | 一句话简介、分类、标签、怎么玩、署名、这一版改了什么 |
cover.png | 210×210 的封面 |
README.md | 介绍和玩法 |
CHANGELOG.md | 更新日志,最新的版本写在最前面 |
LICENSES.md | 代码、美术、字体、音效各自的来源和许可 |
events.json | 一段操作脚本,用来自动截图(可选,真机截图放 screenshots/) |
ZIP 里有什么
my-game-v1-wasm.zip release.json 清单:所有文件的大小和摘要、应用信息、构建信息 package.trpkg 应用包,设备只装这个文件 cover.png 210×210 封面,和包内封面是同一张 README.md 介绍 CHANGELOG.md 更新日志 LICENSES.md 来源和许可 screenshots/01.png 466×466 截图,1 到 6 张,编号连续 build/report.json 构建和测试记录(可选)
根目录直接放这些文件,不套文件夹,不能有别的文件。压缩包最大 12 MiB,解压后最大 10 MiB,和 SDK 一致。应用包本身多大能装,由徽章系统决定:安装前网页会先问徽章,再决定能不能装。
release.json
| 字段 | 说明 |
|---|---|
schema_version | 固定为 2 |
app_id title version | 必须和应用包里的一致 |
variant | 新上传使用 wasm,不含预编译机器码 |
summary category tags controls | 一句话简介、分类(game / tool / art)、标签、操作说明 |
release_notes | 这一版改了什么,500 字以内,显示在作品页 |
package cover readme changelog licenses screenshots | 每个文件的路径、大小和 SHA-256 |
screenshots[].capture | wamr-preview(模拟器截图)或 device(真机截图),可加 caption |
requirements | 核心版本和应用实际用到的全部接口 |
build | SDK 版本、编译器、构建时间、所用命令、构建报告 |
signing requested_channel | 作者声明的打包方式和申请频道,不能代替网站自动检查 |
verification rights | 作者自报的测试结果和素材授权状态 |
可下载当前站点的 release-v2.schema.json做机器校验,并参照 SDK 的发布规范。新版官方固件检查文件结构和完整性;应用来源和发布权限由网站自动检查。旧的 v1 发布包仍然接受。
网站怎么检查
- ZIP 结构、文件白名单和大小上限。
- 清单格式,以及每个文件的大小和摘要。
- 图片尺寸:封面 210×210,截图 466×466,不能是动图。
- 应用包的文件结构、内容摘要、权限和接口;加速代码需要重新编译核对。
- 清单和应用包逐项对照:名字、版本、权限、接口列表、封面。
- 应用 ID 是否属于你,这个版本是否已经发过。
不通过时会给出错误码、说明和出错的位置。
更新徽章系统
网页提供官方 0.1.1 主线的源码构建文件,适用于 ESP32-S31 徽章。
community.3 推荐 OTA 升级
现在是 community.3 的徽章,推荐通过 OTA 升级到本站 0.1.1,会保留已安装的应用。
在徽章进入固件升级页,确认屏幕显示「Send firmware / 等待发送固件」。网页选择数据线或蓝牙,按提示更新系统;保持供电和连接,完成后按徽章提示重启,再检查系统版本和原有应用。
整片刷写作为备用
系统无法启动,或确需切换不兼容的固件签发来源时,使用系统升级页中的「恢复出厂系统」。整片刷写会清掉徽章上已经装的应用和存档,刷完后到社区重新安装。
升级后使用应用
在徽章应用大厅点“+”,停在等待接收页面,再从社区安装应用。每装完一个应用,下次安装前重新进入“+”页。
数据线用于安装应用和更新系统,蓝牙用于应用管理。网页读取徽章实际支持的能力,再检查安装条件。
系统文件从哪里来
文件根据官方公开源码构建,由本站固件钥签署,与 community.3 使用同一签发钥,可通过 OTA 升级。它与官方 Releases 签发的文件属于不同签发来源;切换到不兼容的签发来源时需整片刷写。
官方源码 · 构建记录和文件校验值 · 开发与校验合同
接口速查
函数
| 函数 | 需要的权限 | 作用 |
|---|---|---|
draw_clear(rgb) | 画面 | 清屏,每一帧的第一条 |
draw_rect(x,y,w,h,rgb) | 画面 | 矩形 |
draw_round_rect(x,y,w,h,radius,rgb) | 画面 | 圆角矩形 |
draw_arc(cx,cy,radius,thickness,start,end,rgb) | 画面 | 圆弧,0 度朝右,顺时针 |
draw_text(x,y,text,len,rgb) | 画面 | 一行文字,1 到 63 字节 UTF-8 |
draw_text_box(x,y,w,h,text,len,rgb,font_px,align) | 画面 | 框内单行文字;字号 18/24/36/48;0 左 1 中 2 右 |
draw_rgb565(x,y,w,h,pixels,len) | 画面 | 一张图,最大 256×240,每帧一张 |
draw_rgb565_scaled(x,y,dw,dh,sw,sh,pixels,len) | 画面 | 同上,放大到指定尺寸 |
draw_skip() | 画面 | 这一帧不变,保留上一帧 |
input_events(mask) | 输入 | 只在 init 里调用;56 完整触摸,64 按键,120 两者;再加 128 运动,再加 256 手柄(需要新固件) |
clock_interval(ms) | 定时器 | 多久来一次定时事件,1 到 1000 毫秒 |
now_ms() | 定时器 | 当前毫秒数 |
kv_get(key,fallback) / kv_set(key,value) | 存档 | 16 个整数格子,key 为 0 到 15 |
asset_read(offset,dst,len) | 无 | 读包里的资源,每次最多 4096 字节 |
audio_play(offset,len,16000) | 声音 | 播放资源里的一段声音,最长 1 秒 |
runtime_backend() | 无 | 0 解释执行,1 AOT |
haptic_pulse(strength,ms) | 震动 | 0.0.9 新增;强度 1..100、时长 1..2000 ms,限 init/event;0 接受,1 忙或不可用 |
haptic_stop() | 震动 | 停止马达,限 init/event;旧运行时须使用不含震动接口的基础包 |
事件
| kind | 名字 | 含义 |
|---|---|---|
| 1 | TINYRT_TOUCH_RELEASE | 手指抬起,x、y 是位置 |
| 2 | TINYRT_CLOCK_EVENT | 定时器到点 |
| 3 | TINYRT_TOUCH_PRESS | 手指按下 |
| 4 | TINYRT_TOUCH_MOVE | 手指移动 |
| 5 | TINYRT_TOUCH_CANCEL | 触摸被打断,清掉所有按住的状态 |
| 6 | TINYRT_USER_KEY_EVENT | KEY1;y 为 1 按下,0 松开 |
| 8 | TINYRT_EV_GAMEPAD | 手柄(订阅位 256);x 是按键位图,y 是四个摇杆各 1 字节,arg 是扳机和已连接标志;每次都是完整状态 |
不订阅时只会收到 1 和 2。3 到 6 需要在 init 里调用 input_events;8 要在掩码里加 256。模拟器里打开「手柄外设」开关,外框上的按键和键盘都能当手柄;键位可以在「手柄设置」里改,H 回大厅。
哪里能调用
| 函数 | init | event | render |
|---|---|---|---|
| 画图 | ✓ | ||
| 存档、读资源、声音、设置定时器 | ✓ | ✓ | |
| 订阅输入 | ✓ |
代码层级
应用跑在沙箱里,碰不到硬件。从上到下四层,每层只和相邻的一层说话。
| 层 | 是什么 | 在哪里 |
|---|---|---|
| 应用 | 你写的 C,编成 Wasm,打包成 .trpkg | tinyrt-sdk/examples/ |
| TinyRT 核心 | 运行环境、权限、完整性校验、应用存储、生命周期 | esp32/tinyrt/runtime/ |
| 固件服务 | 应用大厅、蓝牙安装、屏幕、触摸、声音、存档 | esp32/components/ |
| 芯片和系统 | ESP32-S31、FreeRTOS、LVGL | ESP-IDF |
仓库
| 仓库 | 内容 |
|---|---|
| EEBadge 固件 | 固件、硬件资料 |
| tinyrt | 核心:runtime/ 源码,specs/ 规格,contracts/ 接口契约 |
| tinyrt-sdk | include/tinyrt.h 头文件,tools/ 工具,templates/ 模板,examples/ 示例 |
应用包
一个 .trpkg 里是:256 字节的头(名字、版本、权限等信息),然后是几段内容:Wasm 程序、AOT 机器码、资源、封面;网站新发布必须包含前两项。官方固件检查格式和完整性;网站自动核实发布账户及程序规则,新发布必须同时带 Wasm 和 S31 预编译版本。字节级的格式见核心仓库的 specs/package.md。
设备上的存储
应用包共用独立分区,S31 可用数据区约 3960 KiB,最多 16 个应用;没有独立的单包 2 MiB 限制,上限和剩余连续空间由徽章系统报告。更新应用时新旧两个版本要同时放得下。存档在另一个分区,按应用分开,更新保留,卸载清除。格式见 specs/store.md。
限制
| 项目 | 上限 |
|---|---|
| 应用包 | 受整个应用数据区约束,S31 约 3960 KiB,含资源和封面;安装前读取徽章报告 |
| 内存 | 最多 16 页(1 MiB),每页 64 KiB |
| 每次回调 | 10 万条指令,超了应用会被关掉;长任务要分几次做 |
| 每帧绘制 | 128 条命令,一张图 |
| 存档 | 16 个整数 |
| 文字 | 单行,1 到 63 字节 |
| 声音 | 16 kHz 单声道,每段最长 1 秒,每次回调最多 4 段 |
| 设备上的应用 | 最多 16 个 |
没有的东西
- 没有文件系统、网络和麦克风接口。IMU 通过订阅事件提供三轴加速度,应用不能直接访问硬件。
- 没有 C 标准库和浮点数,自己写需要的小函数。
- 不能自己忙等;用定时器事件推进时间。
模拟器和真机的差别
- 模拟器不计指令数,真机上会计。
- 字体和速度略有不同。
- 带加速代码(AOT)的包,真机跑加速版,模拟器跑包里的 Wasm,玩法一样,速度不同。