Wins worth sharing.
The old Achievements tab had fifteen badges — one per elite calisthenics skill program: Pull-Up, Muscle-Up, Planche, Front Lever, Hefesto. Each unlocked only when you'd completed every level of the program it represented. For most users that meant fifteen progress rings ticking up from 0 % to maybe 15 %, with the actual unlock six months away on the optimistic end.
It was the wrong shape of incentive. You can't celebrate Planche on day one. You can celebrate your first strict pull-up.
v1.6.6 rewrites the whole tab around milestones — 22 unlocks split across bodyweight reps, holds, skill firsts, consistency, and calibration. Most users will unlock four or five immediately from existing history. And every unlock is shareable as a branded image, with one tap to Instagram Stories.
A milestone catalogue, not an elite trophy case
The 22 cover five categories:
- Bodyweight milestones — First Pull-Up · 5 / 10 / 15 Strict Pull-Ups · First Push-Up · 10 / 25 / 50 Push-Ups
- Holds — 30s and 60s Dead Hang · 60s Plank
- Skill firsts — First Muscle-Up · First Wall Handstand Push-Up · First 5-Second Handstand
- Consistency — First Workout · 10 Workouts · 50 Workouts · 7-Day Streak · 30-Day Streak
- Calibration — First Calibration · Three Skills Calibrated · Fully Calibrated
Each one has its own description, target threshold, and rarity estimate ("Top 5 % in the world"). Tap an unlocked badge and you get the full detail card: when you unlocked it, what specifically counts, and which program drives the next one up.
Per-movement matching is also broader than it sounds. "First Pull-Up" doesn't require the exact "Strict Pull-Up" exercise — it counts any real pull-up variant in the catalogue (strict, weighted, chest-to-bar, L-sit, archer, typewriter, explosive, plus another twenty). What it doesn't count: regression variants (negative, assisted, jumping). The copy is honest about it — the achievement description says "log a strict pull-up" and means it.
Calibration data counts, too
If you've passed a calibration test, those reps now count toward the matching achievements. A 13-rep result on the pull-up calibration unlocks First Pull-Up, 5 Pull-Ups, and 10 Pull-Ups instantly — even if you've never logged a session of strict pull-ups in a regular workout. Same for push-ups, dead hangs, and (where calibration tests exist) every other rep-based milestone.
This was the one piece of feedback during the build week that mattered most: "I have 13 pull-ups in calibration — why is First Pull-Up locked?" Now it isn't.
A redesigned tab that motivates instead of taunts
Old behaviour: open the tab, see fifteen badges at 0 %, close the tab. New layout has a deliberate ordering:
- Header strip — "X / 22 unlocked" with a progress bar and a meta line ("5 in progress · 3 locked"). Big mono number to anchor.
- Filter chips — All · Recent · Strength · Skills · Holds · Consistency
- Almost there (≥ 70 % progress) — hero cards with a ring badge, the exact "8 / 10 reps" label, and a Continue CTA into the program that gets you there
- Unlocked — full-width rows with the gold accent, sorted newest first
- In progress — 3-column grid with progress rings
- Locked — collapsed by default ("Show N locked"); expand if you want to see the road ahead
The accent system is two colours: teal for "in progress / chasing", gold for "unlocked / permanent". Locked stays neutral white-on-dim. You can read across the tab in two seconds and know where you stand.
The empty state actually motivates
A brand-new user used to open Achievements and see fifteen 0 % badges. v1.6.6's empty state replaces that with a hero illustration, a count pill ("0 / 22 unlocked"), three preview rows of what's waiting (First Pull-Up, First Workout, 7-Day Streak), and one Start a workout CTA. The pitch is "here's what you can chase" — not "look at all these things you haven't done".
Sharing built into the celebration
The bigger second half of this release: every unlocked achievement is shareable as a branded image, with three clear paths.
One-tap Instagram Stories. The most-viral surface. Tap the Stories button in the detail sheet or the post-workout toast, iOS shows its "ZenMotion wants to open Instagram" prompt, and Instagram opens with the achievement card pre-loaded as a Story background. Same flow Strava, Duolingo, Whoop use.
System share sheet. For iMessage, WhatsApp, Twitter, AirDrop, anyone in your contacts. The image plus a caption ("Just unlocked: 10 Strict Pull-Ups — Top 5 % in the world. My training is in ZenMotion: [link]") goes through whichever app you pick.
Save to Photos. Backup path for Instagram Feed (which has a known quirk with image extensions), and useful for anyone who wants the asset for elsewhere. Saved with a clean filename so it's not a UUID in your camera roll.
The share image itself is rendered on-device — square 1080×1080 for feeds and a portrait 1080×1920 for Stories. Big gold-haloed badge, achievement name in heavy weight, the "Top X %" rarity pill, and a small ZenMotion + app-icon footer. Designed to be screenshot-worthy on its own; brand sits at the bottom and lets the prestation lead.
Celebration toast after every workout
Tied together with the share flow: when a workout's /complete returns newly unlocked achievements, Home shows a celebration sheet on next render. Stories button is the primary CTA (full-width gradient), system share + Not now sit on the row below. "+ N more unlocks this session" tagline if you crossed multiple at once.
The toast disappears as soon as you share or tap Not now, so it never blocks the rest of the app. Future workouts that don't trigger any new unlocks skip the toast entirely.
Retroactive unlocks for everyone
When you open the Achievements tab for the first time on v1.6.6, the backend re-evaluates your entire history against the new milestone catalogue and unlocks everything you've already earned. Most active users will see four to ten unlocks pop in immediately. Subsequent opens are read-only — the unique constraint on the unlock table makes it idempotent.
If you've trained for a while in ZenMotion, this might be the most satisfying tab-open of the year.
Smaller fixes
/v1/api/achievementsperformance — One round-trip per tab open. The evaluator batches every input (UEP rows, run dates, UserMax keys, calibration counts) into ~six queries and dispatches strategies in-memory. Performance is constant regardless of catalogue size; the next batch of milestones won't slow anything down.movementIdsarray on Achievement — Replaces the singular FK from the initial schema. Lets one achievement match across multiple movement variants without a join table.
The thread tying this release together: achievements should mean something the day you install. Not six months out. Not behind elite skills. Right now, today, the milestones in front of you — and a clean way to celebrate when you cross them.
Email me if anything feels off — support@zenmotion.app. Every message still reaches the person who wrote the code.
— Jacob