Milestone-first

Passing a step used to feel like a bonus. You'd finish a session, a small toast would slide up, and 4 seconds later it was gone. "Oh, cool, I guess I passed something."

That's not right. When you crush a rung you've been aiming at for 6 sessions, that's an identity moment. You earned it. It should feel like it.

v1.38 rewires how celebrations work — before, during, and after.

Named before it happens

Every skill has a roadmap. Every roadmap has a next step. You should never have to open Stats to know what you're working toward.

Working toward — a persistent row on Home, right above your Next Workout card. It reads your picked focus skill's roadmap, resolves the next step, estimates "about N sessions away" from your recent training pace.

You see it every time you open the app. When you finally hit it, you were aiming at it.

Named as it happens

The old rung-bump toast is gone for skill-family bumps (planche, front lever, muscle-up, etc). In its place: a full-screen celebration sheet.

  • Big movement name — "Pseudo Planche Push-Up"
  • Identity framing — "You're now a Pseudo Planche athlete"
  • What comes next — "Next milestone: Tuck Planche · about 8 sessions"
  • Share-card action for the calisthenics-community share reflex

Universal-family bumps (push/pull/squat/hinge/core) still use the fast toast — those don't have per-rung display names authored yet, so the identity framing doesn't have material to work with. That's follow-up work.

One sheet at a time

Building milestone celebrations exposed an older UX problem: post-workout could throw up 3–5 sheets in sequence (achievements, rung bumps, graduation, session insight, stack suggestion). Users tapped through frantically without absorbing any of them.

v1.38 introduces a queue: max one sheet per Home visit. Everything else waits.

You finish a workout, one sheet appears — the highest-priority one for that moment. You dismiss it, close the workout, land on Home. Next time you open Home, the next queued sheet appears. And so on until the queue drains.

Milestones jump to the front — an identity event never waits behind a collection event. But nothing ever stacks. If you background the app mid-queue, the queue survives and drains on your next Home appear.

Save-fail decode fix

While diagnosing analytics for this release we found a chronic bug hiding under "save didn't complete" reports. On pre-v1.38 builds, iOS was failing to decode the /complete response any time it contained a skill-family rung bump — the response format changed when we shipped skill ladders, iOS's model didn't match, decode threw, and the save-success toast never fired.

The catch: the server had the session the entire time. DB row created, achievements evaluated, everything. iOS just never got confirmation.

v1.38's decode fix (technically shipped in the milestone-plumbing work anyway) resolves it. Users on v1.38+ will see save conversion jump — expect the "Continue your workout" banner and pending-save toast to nearly disappear.

Other polish

  • SkillPathSheet — the "here's how ZenMotion builds toward your focus" sheet shown once post-onboarding now fills the full screen instead of leaving a strip of Home peeking below the CTAs.

What's next

v1.39+ will focus on:

  • Skill picker rendering first-milestone as a concrete promise per card (currently only on the selected card)
  • Activity archive — browsable historical milestone celebrations so users can revisit the identity moments
  • CaliSheet content-height auto-sizing so no future sheet leaves a bottom gap

Available in v1.38.0 on TestFlight now. Rolling out to the App Store this week.