A lifting log for iPhone that works like a paper notebook: type a movement, type your sets, and it quietly tells you what you did last time.
I got tired of bloated fitness apps. Most want an account, a profile and a tour before you can log one set. I wanted something about as fast as writing it down, and nothing else.
So the rule is "as simple as a notebook": black and white, a handwritten font, ruled lines, and as little as possible between you and the next set. It was also my first app to make it all the way into the App Store.
A lift is a notebook page: a date, a title like "Push Day," and movements with sets of weight × reps. All the typing happens in one footer that rides on the keyboard and changes mode as you go. There's no save button; every submit writes through.
There's no exercise database. Titles predict your rotation: after Push, Pull, Legs, Push, it suggests Pull. Movements come from the last time you did that same day, and matching is by word prefix, so "inc pr" finds Incline Press.
Sets get no suggestions, just a line under the input: last time: 135x8, 140x6. That replaced something cleverer. The app used to find the tightest cluster of your working sets from last time, to filter out warmups and drop sets, and suggest weights around it. The plain note took its place when the charts landed.
Every lift lives on the device as one JSON blob in AsyncStorage. No accounts, no server. liftStore.ts reads it once per launch, serves everything from memory, and writes back through a serialized queue so fast edits can't interleave.
That makes the phone the only copy, so the store is paranoid. A corrupt blob gets copied to a backup key before starting fresh, and if the backup or the read itself fails, the app runs in memory for that session and refuses to write.
The App Store screenshots. Yes, the font is the whole personality.
A clustering algorithm for predicting weights lost to one line of text.
The keyboard flickered on every mode switch because Fabric skips a reloadInputViews call, so I patched it back in.
Collapsing the editor's focus logic into one descriptor deleted a pile of timers and race conditions.
With no server copy, the store would rather not write than overwrite something it can't read.