Inspiration
I'm a competitive runner. I track every split, every mile, every calorie. I ignored sleep entirely, and so does every other athlete I know.
Then I found the research. Mah et al. (2011) put Stanford's basketball team through 5–7 weeks of sleep extension and measured the results: sprint times improved 4.4%, reaction time dropped 12%, shooting accuracy jumped 9%. These aren't marginal gains. These are the margins that decide whether you PR or miss a cut. And they came from sleep, not a new training block, not a supplement, not a coach.
The problem isn't that athletes don't care about sleep. It's that no tool exists that takes sleep as seriously as training. Every sleep app tells you to "get 8 hours." None of them know your meet is in 10 days. None of them know you ran a track workout yesterday. None of them do anything about it.
PRform does.
What it does
PRform is a precision sleep coach built specifically for competitive runners and swimmers. You enter your training schedule and meet calendar. PRform computes the exact bedtime you need, every single night, and holds you accountable to it in real time.
Three things make it different from anything else:
1. It plans 5 weeks ahead, not just tonight. For A-priority meets, PRform starts a sleep extension phase 35 days out, progressively adding up to 45 minutes of extra sleep opportunity per night. This is the window Mah et al. identified for performance gains to actually accumulate. By the time your race arrives, your body has had weeks to adapt.
2. It shifts your circadian rhythm before race day. In the 10 days before each meet, PRform gradually moves your bedtime earlier, following the phase response curve established by Burgess et al. (2010). The goal: on race morning, your core body temperature minimum has already passed, your alertness is rising, and your reaction time peaks at the gun. Not at noon. At the gun.
3. It holds you accountable with a live wind-down protocol. Every night, the dashboard runs a 3-hour behavioral countdown, dim lights, night mode, no screens, bed, timed to the research on melatonin suppression (Chang et al., 2015). It's not a notification you swipe away. It's a protocol you follow.
How I built it
The Algorithm
The core is calculateSleepPlan() in lib/sleepAlgorithm.ts , a function that takes your profile, meets, and workouts and returns a day-by-day sleep plan. The dashboard shows a 14-day window, but the algorithm looks up to 35 days ahead.
Every number in it is sourced to a paper:
Base sleep need uses Mah et al.'s actigraphy findings, athletes need 8.5h to satiety, not the 8h flat that most apps assume. Age brackets (9.25h for ≤17, 8.75h for 18–25, 8.25h for 26+) come from AASM guidelines scaled for athletes. A +30 min female modifier is sourced to Burgard & Ailshire (2013).
Training load maps every workout to Seiler's (2010) three-zone lactate model:
- Zone 1 (easy/rest): +0 min
- Zone 2 (tempo):
10 + effort × 3min - Zone 3 (track/long run/race):
20 + effort × 5min
The next night gets a day-after recovery bonus (+10 min for Z2, +20 min for Z3) based on Addleman et al.'s (2024) RMSSD research showing HRV returns to baseline faster after lower-intensity efforts.
Sleep extension phase kicks in 35 days before A meets, 21 days before B meets. A linear ramp increases extra sleep from +20 min at the start to +45 min by day 11, when the circadian ramp takes over. The two phases connect seamlessly, the athlete never drops back to baseline.
Circadian phase advance uses the SHIFT_FRACTIONS lookup table derived from Burgess et al.'s phase response curve. Every inter-day delta stays under 30 min, the behavioral ceiling for advancing the clock without pharmacological intervention. The total advance caps at 90 min for A meets. The target wake time is anchored 3 hours before gun time, so alertness peaks at race start, not at noon.
Circadian correction detects when an athlete's actual sleep phase is delayed (from 3+ consecutive missed nights with logged bedtimes) and adds extra shift on top of the meet ramp to compensate.
Recovery score (0–100) accounts for consecutive hard days, meet proximity, missed sleep, and streak bonuses, modeled on the HRV-proxy framework from Addleman et al.
Wind-down timing is sourced to Chang et al. (2015) and Brainard et al. (2001). Screens off at T−45 (not T−30 — melatonin suppression persists 90 min post-exposure). Lights down at T−120.
Stack
- Next.js 14 (App Router) + TypeScript
- PostgreSQL via Neon + Prisma ORM
- NextAuth.js for authentication
- Strava API : OAuth connect + real-time webhook for automatic workout import
- Framer Motion for animations
- Recharts for sleep trend visualization
- Vercel for deployment
Challenges I ran into
The circadian math is genuinely hard. Phase response curves aren't linear. The advance zone is time-gated to your core body temperature minimum, the response saturates, and the cumulative delay from screen exposure stacks on top of everything else. Getting SHIFT_FRACTIONS right, so the algorithm produces physiologically accurate bedtimes without overcorrecting, meant working through Burgess et al. table by table and validating every inter-day delta against the 30 min/day behavioral ceiling.
Strava webhooks are unreliable. Delivery is best-effort. I had to build a merge layer in getWorkoutsForDateRange that reconciles Strava activities, manual entries, and weekly templates without double-counting or dropping workouts when webhook delivery fails.
Making science feel like a product. The algorithm is correct. Making those outputs feel intuitive to a 16-year-old at 9:45pm, a single bedtime number, a live countdown, one recovery score with a plain-English explanation, required scrapping three dashboard designs before landing on one that respects the user's intelligence without overwhelming them.
Accomplishments that I'm proud of
The algorithm is grounded in 8 peer-reviewed papers, all cited inline in the codebase. This isn't a wellness app with vibes-based recommendations. Every number has a source.
The Strava integration works in both directions: historical activities pull on connect, new activities arrive in real time via webhook. Your training load updates automatically without touching the app.
The wind-down countdown is a new UI pattern, not a notification, not a reminder, but an ambient accountability layer that's just there every night when you open the dashboard.
The recovery score adapts to your history. Miss three nights in a row and it detects your actual circadian phase is delayed and adjusts the plan to compensate.
What I learned
Sleep science is well-established and almost entirely ignored by consumer software. The circadian literature has known for decades that athletes are chronically under-slept and that targeted phase shifting before competition meaningfully improves performance. The gap between what the research says and what athletes actually do is a product problem, not an education problem. Athletes don't need more information. They need a tool that tells them exactly what to do tonight.
I also learned that the hardest part of building something real isn't the code, it's the discipline to keep the scope tight. PRform does one thing. It tells you when to sleep. Everything else, the Strava integration, the recovery score, the wind-down protocol, exists only in service of that one thing.
What's next for PRform
- iOS push notifications for wind-down phases, the web version works, but a native push at T−120 is what closes the loop
- Wearable integration (Garmin, Whoop, Oura) to replace manual sleep confirmation with actual HRV-based recovery data
- Coach dashboard , share your sleep plan with your coach so training load decisions account for circadian readiness, not just mileage
- Multi-sport support for dual-sport athletes and cyclists
Built With
- framer-motion
- neon
- next.js-14
- nextauth.js
- postgresql
- prisma
- recharts
- strava-api
- tailwind
- typescript
- vercel
Log in or sign up for Devpost to join the conversation.