Native Android stylus note app (built for a Galaxy Tab S9 + S Pen) whose notes are plain .excalidraw files.
- Low-latency ink: Jetpack Ink (
androidx.ink) front-buffered rendering + motion prediction, pressure-sensitive. - Excalidraw-exact strokes: committed strokes use a Kotlin port of perfect-freehand 1.2.0 with Excalidraw's freedraw options, so they look identical on excalidraw.com / Obsidian (verified byte-identical in CI).
- Multiple notes: notes grid with thumbnails; new / rename / duplicate / share / delete / import. Notes live in app storage or in any folder you pick (e.g. an Obsidian vault or a synced folder).
- Pen selection: hold the S Pen side button (or use Select) and lasso strokes/images; drag to move, then Recolor / Duplicate / Delete. Single images get a resize handle.
- Images from the clipboard: Paste button, Ctrl+V, or drag & drop from a split-screen app. Stored as real
Excalidraw image elements (SHA-1 file ids, data URLs in
files); large images are downscaled to 2400 px. - Pen, highlighter, eraser (tool or eraser tip), undo/redo (Ctrl+Z / Ctrl+Y), fingers pan & pinch-zoom.
- Elements and fields the app doesn't understand are preserved on save.
./gradlew assembleRelease (Android SDK 36, JDK 17+). CI (.github/workflows/android.yml) runs the unit tests,
checks the generated fixture file against the real @excalidraw/excalidraw package in headless Chromium
(tools/compat), and uploads the APK as a workflow artifact.
prototype.keystore is a throwaway key so CI builds install over each other; don't use it for a real release.
Shows the note open on the tablet, live, in any browser: tap Live in the editor's top bar, then Start, and open the link (or enter the 5-letter code at the viewer page). Viewers see the strokes as you draw, follow your scrolling (unless they scroll themselves), and see PDF pages. They can't edit anything.
live/relay: Cloudflare worker with one Durable Object per code. It only forwards: the note lives in memory while someone is connected, and nothing is stored.live/viewer: read-only Excalidraw page, published to GitHub Pages at/live/.site: the homepage (GitHub Pages root). Its ink strokes are generated bysite/tools/strokes.mjswith the same perfect-freehand settings as the app; after editingsite/index.src.html, runnode site/tools/strokes.mjs && node site/tools/build.mjs.- Downloads: every build on
mainrefreshes thelatestrelease withinkcalidraw.apkandinkcalidraw-obsidian.zip. - Deploying: add a
CLOUDFLARE_API_TOKENrepository secret (Cloudflare → My Profile → API Tokens → template "Edit Cloudflare Workers"). The Live mirror workflow then deploys the relay and the viewer, and the APK build picks up the relay's address. If the viewer page isn't live after the first run, set Settings → Pages to deploy from thegh-pagesbranch. - Codes: a code is 5 letters, so anyone who knows (or guesses) it can watch while you're live. "New code" in the Live panel retires the old one.