A calm, local-first calendar for Android (and iOS/web) built with Expo.
No accounts, no sync, no ads: your calendar lives on your phone.
Download the latest Android APK
The 45-second tour (sound on): Quick Add, stamps, pausing a repeat, scheduled Do Not Disturb,
reminders to the minute, calendar defaults and custom colors, all real footage from the app.
opencal-promo.mp4
- Four views: Schedule (agenda), Day, Week and Month. Swipe left/right to move between days, weeks and months, with the next one sliding in under your finger and staying ready for event taps when the slide finishes; Day and Week keep your scroll position. The header tells you where you are ("Tomorrow", "In 3 weeks", "Next month"). Tap the month or year to jump to any month, scrolling year by year.
- Quick Add: type "Lunch with John Fri 1pm at Cafe X" and review the parsed event before saving; go back and edit the text anytime.
- Stamps: save events you repeat (coffee, gym, calls) and drop them on any empty time slot in one tap, with Undo. Hold a stamp in the stamp menu to delete it.
- Birthdays: add a name and date of birth in Settings and it shows up every year as "Dana's 36th birthday", with its own show/hide chip.
- Repeating events with pauses: skip a date range for one event or a whole calendar, and it resumes on its own.
- Calendars with defaults: each calendar has a color plus default reminders, repeat, location and tags that new events inherit.
- Floating or fixed time: a floating event keeps its clock time in any time zone (a 9:00 run stays at 9:00 when you travel), a fixed one keeps the same moment and remembers its time zone, so a repeating 9:00 meeting stays at 9:00 there across daylight-saving changes wherever you are. Set the default for new events in Settings and change it on any event; all-day events always float. This follows the iCalendar / JSCalendar (RFC 8984) model used by Google and Apple.
- Reminders down to the minute, with presets and custom values; all-day reminders fire at a time you choose.
- Quiet time and Do Not Disturb scheduled like events (e.g. every Monday 17:00–18:00): quiet delivers reminders silently, DND skips them.
- Multi-select in Day and Week view: long-press events, then drag them together (in Week view sideways to another day too) or nudge by 15 minutes / 1 hour / 1 day, and tap Done to save. Moving one day of a repeating event splits it off into its own event. You can also delete everything selected at once, with Undo. For each repeating event it asks whether to delete only that occurrence, it and the following ones, or the whole series.
- Colors: 20 named swatches, a color wheel, hex input, and your own saved colors by name.
- Color rules: color every event whose title contains a word (all your "Break" events amber, all "Gym" green) in Settings → Color rules. Events are drawn in solid colors, and short events stay readable and never share a row with the event that follows them.
- Multi-day events run as one long bar across the days they cover in Month and Week view (Day view adds a 2/3-style counter), and month cells fit as many events as their height allows.
- Icons instead of emoji for events and stamps, dark mode (System / Light / Dark), smooth animations.
- Import & export: back up everything (calendars, events, stamps, birthdays, settings) to one file and restore or merge it on another phone, or move events to and from Google Calendar, Apple Calendar and Outlook with standard .ics files (a whole calendar, or any filtered set of events).
- Private by design: everything is stored locally (SQLite on device, localStorage on web).
- Open the latest release on your phone and download the
.apk. - Open it and allow installing from your browser when Android asks.
- The app updates itself over the air: when a new version is published it shows "A new version of OpenCal is ready" with a Restart button.
Releases that change native parts of the app (icons, splash, new native modules) need a new APK from the Releases page; everything else arrives automatically.
Requirements: Node 22+ and npm.
npm install
npx expo start # press "w" for web, or scan the QR code with Expo Go
npx tsc --noEmit # typecheck
npx expo lint # lintBuild an installable Android APK in the cloud with EAS:
npx eas-cli@latest build -p android --profile previewEvery push to main runs the typecheck and lint, then publishes an over-the-air update to installed preview builds (.github/workflows/eas-update.yml). The release rules (when a version bump and a new build are required) are documented in AGENTS.md.
- Expo SDK 57, React Native, TypeScript
- React Navigation (native stack)
- expo-sqlite for storage, expo-notifications for reminders, expo-updates for over-the-air updates
- expo-document-picker, expo-file-system and expo-sharing for importing and exporting files
- rrule for recurrence, chrono-node for natural-language parsing, date-fns
- react-native-svg + lucide icons, Fraunces display font
App.tsx navigation, theme and providers
src/screens/ screens (calendar, editors, settings, notifications…)
src/views/ schedule, day, week and month views
src/components/ shared UI (pickers, sheets, toast, logo…)
src/context/ app state (CalendarContext)
src/services/ database, occurrences/recurrence, notifications, focus windows
src/models/ data types
src/navigation/ route and param types
src/utils/ dates, recurrence, colors, formatting helpers
scripts/make-logo.js generates the app icon, splash and favicon
docs/screenshots/ README screenshots
promo/ renders the promo video from code (see promo/README.md)
MIT © Boaz Cohen





