A collection of Rabbit R1 Creations — small static web apps built for the R1’s 240×282 screen. Anyone can fork this and host their own.
Building a new Creation, or modifying one? Read AGENTS.md first — it’s the source of truth for conventions, the full Creations SDK reference, and the gotchas that will bite you.
creations/<name>/ each Creation is a folder with three files:
├── index.html markup + <link>/<script> references
├── styles.css all CSS
└── app.js all JS
lib/fonts/ shared Power Grotesk (WOFF2) — the R1's native typeface, used by every Creation
lib/shared/ shared reset.css + core.js / store.js (R1 namespace: input wiring, toast, storage)
qr-generator/ self-host tool that builds the install QR codes (not a Creation itself)
Current creations: hello-world (SDK demo: scroll counter + PTT-to-speak) and camera (live preview, wheel-driven camera switching, persistent gallery).
python3 -m http.server 8000
Then open a Creation, e.g. http://localhost:8000/creations/hello-world/.
R1 Creations run inside the device WebView. In a desktop browser the hardware/voice bridges don’t exist, so creations detect typeof PluginMessageHandler === 'undefined' and surface on-screen test controls instead. See Testing.
A Creation is just a static web page sized to 240×282 px. It talks to the device through a small set of JavaScript bridges (the Creations SDK): PluginMessageHandler, window.creationStorage, window.creationSensors, plus hardware events (scrollUp / scrollDown / sideClick / longPressStart / longPressEnd). Full API: Creations SDK reference.
There is no SDK channel for the R1’s motorized camera rotation, for WebSockets, or for arbitrary native calls — only the bridges above plus standard web APIs (getUserMedia, etc.).
The R1 installs a Creation by scanning a QR that encodes a JSON object (not a bare URL):
{ "title": "Hello World", "url": "https://<your-domain>/creations/hello-world/",
"description": "my first r1 creation", "iconUrl": "", "themeColor": "#FE5000" }
https://<user>.github.io/<repo>/, or set a custom domain via a CNAME file.qr-generator/index.html locally, enter title + URL (+ description, themeColor), Generate, Download.Every Creation renders in Power Grotesk on a shared dark base. Load the font, then the shared reset, then the Creation’s own styles (in that order):
<link rel="stylesheet" href="../../lib/fonts/fonts.css">
<link rel="stylesheet" href="../../lib/shared/reset.css">
<link rel="stylesheet" href="styles.css">
reset.css provides the box-model reset, the 240×282 dark viewport, the font stack, and the R1 palette tokens (--accent, --bg, --text, …) — so each Creation’s styles.css only holds its own component styles.
core.js exposes a small window.R1 namespace shared by every Creation — SDK detection, a $ shorthand, a transient toast(), and bindControls() which wires the hardware events (and the desktop dev harness when there’s no SDK). store.js attaches R1.store, the creationStorage bridge with a localStorage fallback. Load them as plain <script src> before app.js:
<script src="../../lib/shared/core.js"></script>
<script src="../../lib/shared/store.js"></script> <!-- only if you persist data -->
<script src="app.js"></script>
Only WOFF2 is shipped (smallest payload for limited hardware; supported by the R1’s Chromium WebView), and only the weights actually used: 400 Regular, 700 Bold, 800 Heavy. The browser fetches weights on demand.
qr-generator; whether a given firmware accepts arbitrary non-gallery URLs is confirmed by the scan itself.