eclipse-timer is a TypeScript monorepo for an eclipse-focused mobile app and a reusable eclipse computation engine.
It combines:
- A React Native + Expo app for selecting an eclipse, choosing an observer location, and viewing event timings.
- A Besselian-element-driven engine that computes local contact circumstances (
C1/C2/MAX/C3/C4), local eclipse kind, magnitude, and duration. - Catalog tooling for generating typed eclipse datasets and map overlay polygons.
The current MVP is built around a two-screen flow:
- Landing screen
- Loads eclipse records from the local generated catalog.
- Sorts eclipses by date and marks entries as past/upcoming.
- Shows a preview animation URL (NASA animation endpoint per eclipse).
- Timer screen
- Displays a map with observer marker and eclipse overlays (visible band + central band when available).
- Lets the user set location via map tap/drag, GPS, or jump-to-center preset.
- Runs the engine for the selected eclipse at the observer location.
- Shows contact times, next-event countdown, and alarm toggles/test alarm behavior.
apps/mobile- Expo app (navigation, landing flow, timer/map UI, GPS integration, engine trigger).
packages/engine- Eclipse circumstance solver and numeric helpers.
packages/catalog- Generated eclipse catalog + scripts for CSV filtering and overlay generation.
packages/shared- Shared type contracts (
EclipseRecord,Observer,Circumstances, etc.).
- Shared type contracts (
@eclipse-timer/mobile
-> @eclipse-timer/catalog
-> @eclipse-timer/engine
-> @eclipse-timer/shared
@eclipse-timer/engine
-> @eclipse-timer/shared
@eclipse-timer/catalog
-> @eclipse-timer/shared
Catalog build scripts (packages/catalog/scripts/*) use @eclipse-timer/engine as a dev dependency.
@eclipse-timer/mobileloads catalog records throughloadCatalog()from@eclipse-timer/catalog.- Catalog loader merges base eclipse records with generated polygon overlays (visible + central paths) when available.
- User selects an eclipse on the landing screen and moves to the timer screen.
- User chooses observer coordinates (map tap/drag, GPS fix, or center preset).
- App calls
computeCircumstances(eclipse, observer)from@eclipse-timer/engine. - Engine solves eclipse contact timings and derived fields, then returns a typed
Circumstancespayload. - UI renders event timings, countdown state, and per-contact alarm toggles.
At a high level, the engine:
- Evaluates Besselian-element polynomials (
x,y,d,mu,l1,l2) at candidate times. - Solves contact roots for penumbral and umbral/antumbral boundaries.
- Computes local visibility and eclipse kind (
none,partial,total,annular). - Converts TT-relative solved times into UTC ISO strings using record
deltaTSeconds. - Returns additional derived metrics like magnitude and central duration (when applicable).
- Source records are generated in
packages/catalog/generated/catalog.generated.json. - Current filtered range targets years 1900-2100.
- Overlay polygons are generated into
packages/catalog/generated/overlays.generated.json. - Catalog/test integration currently validates a 454-eclipse generated dataset.
- Language: TypeScript
- Monorepo/tooling: pnpm workspaces
- Mobile: Expo SDK 54, React Native 0.81, React Navigation
- Maps/location:
react-native-maps,expo-location - Testing: Vitest
- Data processing: Node scripts +
csv-parse
- Node.js 18+ (LTS recommended)
- pnpm (repo is pinned to
pnpm@9)
Check versions:
node -v
pnpm -vInstall/activate pnpm via Corepack (recommended):
corepack enable
corepack prepare pnpm@9 --activateIf corepack is not found, use a fallback install:
npm install -g pnpm@9- Install Node.js (either method):
- Homebrew:
brew install node
- nvm:
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash nvm install --lts
- Homebrew:
- Enable pnpm with Corepack:
corepack enable corepack prepare pnpm@9 --activate - Install Xcode from the App Store and verify where it is installed:
If nothing is listed, full Xcode is not installed yet (only Command Line Tools are present).
ls -1 /Applications | grep -i xcode - Point
xcode-selectto full Xcode (not Command Line Tools):Verify:# Default App Store path sudo xcode-select -s /Applications/Xcode.app/Contents/Developer # If your app name is different (for example Xcode-beta.app), use that path instead: # sudo xcode-select -s /Applications/<YourXcodeName>.app/Contents/Developer
xcode-select -p xcodebuild -version
- Run first-launch setup:
If you still need to accept the license explicitly:
sudo xcodebuild -runFirstLaunch
sudo xcodebuild -license accept
- Open Xcode once, then install an iOS runtime in
Xcode -> Settings -> Platforms. - Install Android Studio. In
SDK Manager, install:- Android SDK Platform (latest stable)
- Android SDK Build-Tools
- Android SDK Command-line Tools
- Android Emulator
- Create and start an Android Virtual Device (AVD) in
Device Manager.
- Install Node.js LTS (example with
winget):winget install OpenJS.NodeJS.LTS
- Enable pnpm with Corepack:
corepack enable corepack prepare pnpm@9 --activate
- Install Android Studio:
winget install Google.AndroidStudio
- In Android Studio
SDK Manager, install:- Android SDK Platform (latest stable)
- Android SDK Build-Tools
- Android SDK Command-line Tools
- Android Emulator
- Create and start an AVD in
Device Manager. - iOS Simulator is not available on Windows. Use a macOS machine for iOS Simulator runs.
- Install Node.js (nvm recommended):
curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh | bash nvm install --lts nvm use --lts - Enable pnpm with Corepack:
corepack enable corepack prepare pnpm@9 --activate - Install Android Studio (example with Snap):
sudo snap install android-studio --classic
- In Android Studio
SDK Manager, install:- Android SDK Platform (latest stable)
- Android SDK Build-Tools
- Android SDK Command-line Tools
- Android Emulator
- Create and start an AVD in
Device Manager. - iOS Simulator is not available on Linux. Use a macOS machine for iOS Simulator runs.
Set ANDROID_SDK_ROOT and add platform tools to your PATH so CLI launches work reliably:
- macOS:
~/Library/Android/sdk - Linux:
~/Android/Sdk - Windows:
%LOCALAPPDATA%\Android\Sdk
Clone and install:
git clone <your-repo-url>
cd eclipse-timer
pnpm installIf you already have the repo locally, running pnpm install at the root is enough.
Android uses react-native-maps, so a Google Maps Android API key is required.
This repo now reads the key from GOOGLE_MAPS_ANDROID_API_KEY at build/config time.
- Copy the example env file:
On Windows PowerShell:
cp apps/mobile/.env.example apps/mobile/.env.local
Copy-Item apps/mobile/.env.example apps/mobile/.env.local
- Edit
apps/mobile/.env.localand set:GOOGLE_MAPS_ANDROID_API_KEY=your_real_android_maps_key
- Rebuild the Android app after changing the key:
pnpm -C apps/mobile android
- In GitHub, add repository secret:
- Name:
GOOGLE_MAPS_ANDROID_API_KEY - Value: your Android Maps key
- Name:
- The workflow
.github/workflows/eas-build.ymlinjects this secret into the build job. - Android/all builds fail early with a clear message if the secret is missing.
- Builds run on a self-hosted macOS runner with label
eclipse-timer. Runner setup instructions:documents/self-hosted-macos-runner.md.
- Restrict the key in Google Cloud Console to:
- Application restriction:
Android apps - Package:
com.lallimaven.eclipsetimer - SHA-1: your debug/release certificate fingerprints
- Application restriction:
- Restrict API usage to
Maps SDK for Android. - If a key was ever committed, rotate it in Google Cloud and replace it in local/CI secrets.
From the repo root:
pnpm dev:mobileThis starts the Expo dev server for apps/mobile.
For first-time setup, a recommended sequence is:
pnpm install
pnpm typecheck
pnpm test
pnpm dev:mobile- Install Expo Go on your phone.
- Run:
pnpm dev:mobile
- Scan the QR code shown in the terminal/Expo UI.
Use one of:
# Start Expo and press "i" in the interactive terminal
pnpm dev:mobile
# Or run directly
pnpm -C apps/mobile iosUse one of:
# Start Expo and press "a" in the interactive terminal
pnpm dev:mobile
# Or run directly
pnpm -C apps/mobile androidpnpm -C apps/mobile webThe Wear OS companion app is a separate native module (apps/mobile/android/wear) and is not launched by Expo commands above.
Live mode now computes sun/moon geometry on-watch from watch GPS + UTC time, so it works without a connected phone. Phone connectivity is only needed for preview sync mode.
Use the local simulator build/install/run guide in:
- documents/guides/setup-and-development.md#wear-os-companion-on-local-emulator
- documents/guides/windows-disposable-phone-wear-emulator.md for a disposable Windows workflow (
C:\e) that runs phone and watch emulators together and deletes the copy afterward.
From the repo root:
pnpm typecheck
pnpm lint
pnpm testPackage-level examples:
pnpm -C packages/engine test
pnpm -C packages/catalog test
pnpm -C apps/mobile testCurrent test coverage includes:
- Engine math/time/geometry/circumstance behavior
- Full generated-catalog sweeps at greatest-eclipse coordinates
- Catalog script integration checks and generated artifact stability
# Mobile dev server
pnpm dev:mobile
# Workspace-wide checks
pnpm typecheck
pnpm lint
pnpm test
# Engine local dev script
pnpm -C packages/engine dev:one
# Catalog generation pipeline
pnpm -C packages/catalog data:allCatalog tooling lives in packages/catalog.
Useful commands:
pnpm -C packages/catalog data:filter
pnpm -C packages/catalog data:build
pnpm -C packages/catalog data:overlaysRun all steps:
pnpm -C packages/catalog data:allGenerated artifacts are written under packages/catalog/generated/.
apps/
mobile/ Expo app
packages/
engine/ Eclipse computation engine
catalog/ Generated dataset + build scripts
shared/ Shared TypeScript types
documents/
high-level/ Architecture and workflow docs
low-level/ Algorithm/data/internal design docs
documents/README.mddocuments/high-level/system-overview.mddocuments/high-level/development-workflow.mddocuments/high-level/user-flow-and-product-behavior.mddocuments/low-level/engine-algorithm.mddocuments/low-level/mobile-app-internals.mddocuments/low-level/data-contracts.md
- MVP behavior is implemented and usable for local exploration.
- Workspace lint/format tooling is configured with Biome; current codebase still has existing lint warnings to address incrementally.
- Alarm/reminder behavior now uses fixed per-eclipse local reminders (
T-1h,T-10m) plus foreground-only in-app per-eventa1/a2voice alarms from Notification/Alarm Settings. - Product polish and persistence/history features are intentionally limited while core engine/data reliability is prioritized.