A fast, local-first hybrid note-taking application for Android that seamlessly combines Markdown text editing with a freehand drawing canvas.
| Main Dashboard | Combined Markdown + Drawings |
|---|---|
![]() |
![]() |
LocalNotes is an offline-first mobile app designed for seamless note-taking. It bridges the gap between structured text and visual sketching by letting you write raw Markdown while sketching, diagramming, or handwriting directly on top of the same page.
All data is kept strictly on your local device for maximum speed and privacy.
- Hybrid Canvas Rendering: The workspace functions as an interactive canvas. You can type standard Markdown syntax (
# headers,**bold**, bullet points) while overlaying vector strokes anywhere on the page[cite: 1]. - Inking & Canvas Controls: Use the top toolbar to switch between pen input, precision eraser, canvas locking (to prevent stray marks while scrolling), and multi-page additions.
- Local File Management: Notes are indexed and stored on device, providing rapid search filtering directly from the main grid dashboard.
- PDF Generation: Documents, including both text and active ink layers, are compiled into vector-rendered PDF files for sharing or archiving[cite: 1].
You can review a full document generated directly from the app:
- Export File:
LocalNotes_Export.pdf
- Kotlin: 100% Kotlin codebase leveraging Coroutines and
StateFlow/SharedFlowfor asynchronous thread handling and reactive UI state management. - MVVM Architecture: Strict separation of concerns between reactive UI states, canvas input event handlers, and offline local persistence layers.
- Jetpack Compose: Modern Android UI framework handling dynamic layouts, dark theme styling, and state-driven UI updates.
- Vector Drawing Engine:
- Built using
androidx.compose.foundation.Canvascombined with low-levelandroid.graphics.Pathdata models. - Pointer Event Pipeline: Uses
pointerInputanddetectDragGesturesto sample stylus and touch inputs with minimal input latency. - Precision Eraser: Executes real-time path collision testing or offscreen compositing using
PorterDuff.Mode.CLEAR/BlendMode.Clearto strip drawn paths cleanly. - Coordinate Normalization: Stroke points are stored as normalized vector coordinates so drawings remain pin-sharp across viewport scaling (
100%, step zoom) and varying screen densities.
- Built using
- AnnotatedString Formatting: Real-time text parser converting raw Markdown tokens (
#,**,*, list identifiers) into ComposeAnnotatedStringinstances with rich typography styling embedded inside the editing canvas.
Instead of taking dirty bitmap screenshots of the screen, PDF export compiles a clean, vector-rendered document from scratch using native Android graphics pipelines:
- Document Setup: Instantiates an
android.graphics.pdf.PdfDocumentinstance. - Multi-Page Allocation: Iterates through document pages and configures
PdfDocument.PageInfotargets matching target paper dimensions at high DPI. - Canvas Surface Acquisition: Calls
pdfDocument.startPage(pageInfo)to receive a hardware-acceleratedandroid.graphics.Canvasinstance representing the PDF page surface. - Text Layer Pass: Formatted Markdown strings are rendered onto the PDF canvas using
android.text.TextPaintandandroid.text.StaticLayoutto guarantee exact line wrapping, typography scaling, and margin constraints. - Vector Ink Replay Pass: The engine iterates through the saved
Pathstroke array and re-draws every gesture line directly onto the PDFCanvasusing customandroid.graphics.Paintconfigurations (Paint.Style.STROKE,Paint.Cap.ROUND,Paint.Join.ROUND). - Disk I/O & Native Sharing:
- Finalizes the page using
pdfDocument.finishPage(). - Streams the raw binary payload to local device storage using
java.io.FileOutputStream. - Wraps the local output file in an Android
FileProvider(androidx.core.content.FileProvider) URI for instant, zero-copy sharing to external apps.
- Finalizes the page using
- Offline Storage: Raw note data (Markdown content and serialized coordinate arrays for vector ink paths) is saved locally via Android File System APIs and internal app storage without cloud dependencies.
This project is licensed under the MIT License. See the LICENSE file for details.

