Keel Snack
Status: scaffold shipped; cloud-streamed runtime planned for later.
Browser playground for Keel React Native snippets — paste TS in the left pane, see it running on a real emulator streamed back to your tab. Or scan a QR with Keel Go to preview on your phone.
Two preview surfaces, one session
┌──────────────────────────────────┐
│ Browser │
│ ┌──────────┐ ┌────────────────┐ │
│ │ Monaco │ │ <video> tag │ │
│ │ editor │ │ ← WebRTC │ │
│ │ │ │ │ │
│ └─────┬────┘ └────────────────┘ │
│ │ │
│ save │ ▲ QR code │
└────────┼────────────┼─────────────┘
│ │
▼ │
┌──────────────────────────────────────────┐
│ Snack session server │
│ ┌────────────────────────────────────┐ │
│ │ Emulator pool (iOS / Android) │ │
│ │ + Snack Runtime app pre-installed │ │
│ │ + ffmpeg → WebRTC peer connection │ │
│ └────────────────────────────────────┘ │
│ ▲ │
│ reload on │ code save │
│ │ │
│ Snack Runtime app (Keel-built): │
│ - subscribes to /api/session/{id}/feed │
│ - hot-reloads bundle on every change │
└──────────────────────────────────────────┘
│
│ same /api/session/{id} URL
▼
┌──────────────────────────────────┐
│ Phone (Keel Go scans QR) │
│ → loads the same Snack Runtime │
│ bundle directly on device │
└──────────────────────────────────┘
What you get
| Surface | Use case | Fidelity |
|---|---|---|
| In-browser emulator (WebRTC video) | Quick share — colleague opens URL, sees the app running in seconds without installing anything | 1:1 with real iOS Simulator / Android Emulator (it IS one, streamed) |
| Keel Go real-device (QR scan) | “Show it on my phone” — touch + sensors + push + WeChat-pay flows that emulators don’t fake well | Real device, real OS |
Both surfaces share the same session ID: type code once, watch it reload on the emulator video, hand someone the QR and they see the same thing on their phone within seconds.
Snack Runtime
A specialized Keel app pre-loaded into every emulator + downloadable into Keel Go. It:
- Subscribes to
/api/session/{id}/feed(SSE) on boot - On every code save, fetches the rebuilt bundle from
build-serverand hot-reloads viaKeelView.loadBundle(uri) - Reports back errors / console.log lines so the Snack browser UI can show them next to the editor
Built from keel/snack/runtime-app/ and shipped as a Keel bundle
that runs inside Keel Go (no separate install for QR-scan users).
How a session works
- User opens
snack.keel.appunvs.com→ Next.js app loads Monaco - User types or pastes code, hits Save
- Frontend:
POST /api/sessionwith the source tree - Snack session server:
- Allocates an emulator from the pool (iOS or Android per user pref)
- Starts a WebRTC peer connection back to the browser
- Generates a short URL (
snack.keel.appunvs.com/s/<id>) + QR code
- build-server compiles the source to a Keel bundle, drops the URL into
the session’s
feedchannel - Snack Runtime app inside the emulator picks up the new bundle,
loadBundle()swaps the running tree → screen updates → ffmpeg captures → WebRTC stream → browser<video>shows the change - If anyone scans the QR with Keel Go, that device subscribes to the same feed and gets the same bundle
Production deploy
| Component | Where it lives |
|---|---|
| Browser frontend (Next.js static export) | 阿里云 OSS + CDN → snack.keel.appunvs.com |
| Session orchestrator (Go) | 阿里云 ECS pool — one orchestrator per region |
| Android emulator hosts | 阿里云 ECS with KVM + GPU — pool by traffic |
| iOS Simulator hosts | macOS mac1/mac2 instances — pool by traffic |
| WebRTC TURN servers | 自建 coturn on cloud edge |
| build-server | Shared with the rest of Keel Cloud Build |
See deployment-sop.md for the Caddy + TLS setup
that fronts the orchestrator.
Limits + pricing
- Free tier sessions: 3-minute video stream cap, then “open in Keel Go” prompt with the QR
- Pro tier: 30-minute sessions, multi-file projects, npm dep install
- See
pricing.md
Local dev
The Next.js frontend lives at keel/snack/. From that dir:
npm install
npm run dev # → http://localhost:3000
Optional — point at a local build-server + session orchestrator:
KEEL_BUILD_ENDPOINT=http://localhost:8082 \
KEEL_SNACK_SESSION_HOST=http://localhost:8090 \
npm run dev
Single-machine local dev runs an Android emulator via adb; iOS
preview defers to a phone via QR + Keel Go (iOS Simulator needs macOS).