Pipeline ships. Scrape → transcode → upload to Firebase
Storage → index Firestore. Hybrid GIF source (retained at
sources/) + animated WebP (shipped at
derived/). Idempotent uploads, resumable via
state/manifest.jsonl.
5-exercise pilot proved end-to-end on the canonical hero
set (bench, squat, deadlift, pullup, OHP) before scaling to the long tail.
Primary source: hasaneyldrm/exercises-dataset
(1324 animated GIFs). Stevie explicitly authorised scraping without ToS
concerns — the source GIFs are retained in Firebase Storage so
future re-processing (image transformation, AI regeneration) reads from
a known location.
Fallback source: yuhonas/free-exercise-db
(873 still-image entries) for slugs hasaneyldrm doesn't cover. After
dedup by canonical slug: 2048 unique exercises in total.
Replaces the 40-exercise hand-seeded catalog that used
15 reused Unsplash gym photos (IMG_DUMBBELLS appeared 8×).
Each exercise now shows its actual movement.
The mobile app reads Firestore exercise_catalog and follows
fully-qualified storage.googleapis.com URLs —
no app-side bucket configuration needed. Storage objects ship with
cache-control: max-age=31536000, immutable.