TL;DR
Notes app to SQLite database to visualization
December 9, 2025 at 11:18 PM
Workout
10/1 – weight: 210 – CGBP - 160 5x12 10/4 – weight: 207.9 – Bench - 190 5x8 – Leg Press - 295 5x12 10/5 – Weight: 208 – narrow grip lat pull down - 135 5x5 10/6 – Weight: 206.8 – squat - 190 5x5 – Barbell shrug 190 5x6 10/7 – weight: 206.6 – Narrow grip lat pull down - 140 5x5 – Bench: 195 5x6 – Machine pec fly: 4x12 115 10/8 – weight: 206.2 – Shoulder press: 95 5x5 10/9 – weight: 207.8 – Squat: 195 5x5 – Bench: 200 5x5 – Machine pec fly: 4x12 120 – Barbell Shrug: 195 5x6 10/15 – weight: 210.5 – Shoulder press 100 5x5 – Leg press 300 5x12 – Narrow grip lat pull down 145 5x5 10/16 – weight:209 – Bench: 205 5x5 – Barbell Shrug: 200 5x6 – EZ barbell curl: 75 3x12 – Rope push down: 47.5 4x12 – Machine pec fly: 4x12 125 10/17 – weight: 208.3 – Squat: 200 5x5 – Narrow grip lat pull down 154 5x5 – Seated leg curl: 100 3x12 – Leg extension: 95 3x12 – Upright supinated row: 85 3x12 10/22 – weight: 210.3 – Bench: 210 5x4 – Narrow grip lat pull down 160 5x5
Sample of raw workout data from Notes app
sqlite> SELECT ec.name, COUNT(*) as sessions FROM workout_exercises we JOIN exercise_catalog ec ON we.exercise_id = ec.id JOIN workouts w ON we.workout_id = w.id WHERE ec.name = 'Bench' AND w.date LIKE '2024%' GROUP BY ec.name; name | sessions ------|---------- Bench | 63
SQLite query results
30-second animated progress video
What We (✨Claude✨) Built — Claude also wrote this summary because I am incapable of writing
Data Pipeline
Two years of gym notes, zero consistency. Some days I'd write Bench - 190 5x8, other days Bench: 5x8 190 with the order flipped. Pull-ups were just a list of reps: 10, 8, 6, 5. And I never once wrote the year.
The parser handles 10+ format variations using sequential regex matching. It tracks context too - when it sees 185 5x5, it knows that's a pyramid set for whatever exercise came before.
Result: 3,112 lines → 421 workouts, 2,305 exercises, normalized SQLite schema
Progress Visualization
With clean data, I used Remotion to generate a 30-second TikTok-style video (1080x1920, 30fps). Built in React with pure SVG - no charting libraries.
The trickiest part was the animated weight chart. Two bugs kept breaking it: the Y-axis would jump as new data appeared (fixed by calculating scale upfront), and layout shifted at frame 60 (fixed by always rendering at least one point).
Features: GitHub-style heatmap, animated weight chart (210→232.5 lbs), travel break highlights, TikTok-safe zones (12% top, 10% bottom)