the-bar

The Bar — Pull Ups Legend!

Adaptive pull-up trainer. Local-first (everything is saved on the device), with optional Google sign-in + cloud sync via Firebase.

public/            ← everything that gets hosted
  index.html       ← the whole app (React via CDN, no build step)
  sw.js            ← service worker: full offline support after first load
  manifest.webmanifest
  icon.png
firebase.json      ← Firebase Hosting + Firestore config
firestore.rules    ← each user can only touch their own data
.firebaserc        ← put your Firebase project id here

Run locally

python3 -m http.server 8123 -d public

Then open http://localhost:8123. Sync is disabled until you add a Firebase config (the app runs fine without it — data stays in the browser).

Host on Firebase (free) with login + sync

One-time setup, ~10 minutes. Everything fits in Firebase’s free Spark plan.

  1. Create a project at console.firebase.google.com (e.g. the-bar-pullups). No need for Google Analytics.
  2. Enable Google sign-in: Build → Authentication → Get started → Sign-in method → Google → Enable → Save.
  3. Create the database: Build → Firestore Database → Create database → Start in production mode (the rules in this repo take over on deploy).
  4. Register a web app: Project settings (gear icon) → Your apps → Web (</>) → register. Copy the firebaseConfig values it shows.
  5. Paste the config into public/index.html — find FIREBASE_CONFIG near the top of the script and replace the PASTE_... placeholders (apiKey, authDomain, projectId, appId).
  6. Put your project id in .firebaserc (replace the-bar-pullups if you named it differently).
  7. Deploy:
npm install -g firebase-tools
firebase login
firebase deploy

The app goes live at https://<project-id>.web.app and https://<project-id>.firebaseapp.com.

iPhone tip: open the .firebaseapp.com URL in Safari and use Share → Add to Home Screen. Using that domain keeps Google sign-in working in home-screen (standalone) mode, where popups are restricted.

Moving your existing data

localStorage doesn’t transfer between domains. On the old version of the app: History → Export, send the JSON file to yourself, then on the new URL: History → Import. Sessions merge by id, so importing twice is safe. Once you sign in, the same merge keeps every device consistent.

Rest timer & screen lock

The timer is anchored to the clock, not to a running counter — lock the phone mid-rest and it will still be correct when you come back. While resting, the app plays a silent audio loop, which lets iOS keep it alive in the background so the chime can ring the moment rest is over (this also works with the silent switch on, since it plays through the media channel). If iOS still suspends the app, the timer self-corrects the instant you wake the screen.