- An android app note taking / infinite canvas drawing / vector app with pen & draw support
- Extremely snappy, no-nonsense
- Uses a CRDT (Loro) to sync notes and brush strokes. Full history playback and versioning.
- Uses modern android standards and APIs. research conventions.
- Easy & fast management with folders
- Smart gestures, controls, pen support
- if using a pencil, fingers pan (single finger drag) & undo (double finger tap) & select (single finger hold)
- if using fingers, fingers pan, but user can quickly toggle draw mode
- Manu items have hold & drag interactions for fast gestures
- Simple, clean, minimal UI, a couple of buttons at the buttom:
- Tutorial (starts tutorial, shows UX)
- Color selector (drag, a fan pops up, let go to select color. Tap to go back to previous color)
- Size adjust (same UX: drag & hold to select, tap to go to previous)
- History scrubber. Tap to undo, scrub to navigate history. You can even open "forgotten" branches of undo history, so nothing is ever lost
- New canvas button
- Gallery / back
- Eraser
- Reset view /zoom scrubber (tap to fit all content, or tap again to go back to previous view)
- Place image
This project uses mise to manage the Flutter SDK (Flutter 3.44+, Dart 3.12 — see .mise.toml).
A Makefile wraps dev.sh which sets up a FIFO pipe so you can trigger hot reload from any terminal tab — no need to switch focus or type into the running process.
Run each device in a separate terminal (they share build/, so don't start them simultaneously):
# Terminal 1
make tablet # Samsung SM X810 tablet
# Terminal 2 (after tablet finishes building)
make phone # Pixel phone (456cb10b)
make web # Chrome (separate terminal)Output is captured to logs/<target>.log (truncated on each launch):
grep "error" logs/tablet.log
grep "iroh" logs/phone.logmake reload-tablet # Hot reload
make restart-tablet # Hot restart
make reload-all # Reload all running targets
make restart-allmake analyze # Static analysisTo update the Android device IDs, edit dev.sh (ANDROID1_ID = tablet, ANDROID2_ID = phone).
Devices sync via Iroh (QUIC peer-to-peer, works through NAT).
- Open Settings > Pair with QR Code
- Device A shows its QR code, Device B scans it (or vice versa)
- Sync is bidirectional — both devices exchange data regardless of who initiates
NodeIDs are persistent (stored in the local DB), so a QR code stays valid across app restarts.
| Input | Action |
|---|---|
| Trackpad pinch | Zoom |
| Ctrl + scroll | Zoom |
| Two-finger scroll | Pan |
| Middle mouse drag | Pan |
When a stylus or pen is detected, finger touches pan the canvas instead of drawing. This matches the behaviour of the Kotlin version: use the pen to draw, fingers to navigate.
The Dart client code in lib/atomic/ (AtomicClient, session.dart, FRB bridge) is not canvas-specific — it's a general-purpose Atomic Data SDK wrapping atomic_lib via flutter_rust_bridge. Once the API stabilizes, it should be extracted to atomic-server/dart/ (or sdk/dart/) as a reusable Dart package, keeping this app as a thin UI layer on top.