Expo React Native (TypeScript), Firebase Auth + Firestore, web-first. Simple metronome with deterministic timing via the Web Audio API.
-
Install dependencies
cd rhythm-app && npm install
-
Firebase
- Create a project at Firebase Console.
- Enable Authentication → Anonymous (for “Continue as guest”) and Email/Password (for sign-in and sign-up).
- Create a Firestore database (test mode is fine for MVP).
- Project settings → General → Your apps → Add web app → copy the config.
-
Environment (no secrets in code)
- Copy
.env.exampleto.envin the project root. - Fill in each
EXPO_PUBLIC_FIREBASE_*in.envwith values from Firebase Console → Project settings → Your apps → Web app config. - Do not commit
.env.
- Copy
-
Run (web)
npm run web
Open the URL in the browser. Use Start on the Practice tab (first tap resumes the audio context).
app/— Expo Router screens:index,(tabs)/home,(tabs)/practice.contexts/AuthContext.tsx—useAuth()(user, loading); signs in anonymously on app load.lib/firebase.ts— Firebase init (Auth + Firestore). Config from env; see file comment for where to add values.lib/metronome.ts— Timing logic: Web Audio scheduling and visual beat callbacks (see comments in file).lib/userProgress.ts— Firestore read/write for last BPM (one doc per user).
- Audio: Beats are scheduled at exact
AudioContext.currentTimevalues in a small lookahead window; nosetInterval/setTimeoutfor playback, so no drift. - Visual: A
requestAnimationFrameloop reads the same scheduler state and updates the beat indicator; one-frame latency is acceptable for MVP. - Platform: Metronome is web-only in this MVP (Web Audio API). Native would need expo-av or a native module and a different timing approach.
- Simple, readable code; no heavy abstractions.
- Deterministic timing where possible (audio clock on web).
- No premature optimization.
- No class-heavy design; hooks and plain functions.
- Timing logic commented in
lib/metronome.ts.