feat(conditions): heat, humidity & altitude race day calculator - #80
Open
aleexwong wants to merge 1 commit into
Open
feat(conditions): heat, humidity & altitude race day calculator#80aleexwong wants to merge 1 commit into
aleexwong wants to merge 1 commit into
Conversation
Adds /conditions — a tool that answers the two questions runners actually have on race week: "it's going to be 28°C and humid, what's my realistic finish time?" and "what pace should I run today's workout at?" Two penalties are modelled independently and composed: - Heat is keyed on the sum of air temperature and dew point (°F) rather than on temperature or relative humidity alone, since dew point is what caps evaporative cooling — 20°C/90% RH and 30°C/40% RH are very different runs despite both reading as "warm". The penalty is scaled by race duration, so a 5K and a marathon in the same forecast get different costs (~2% vs ~4.8% at 24°C/75%) instead of one flat number. - Altitude is applied at the fitness level: VDOT is scaled by the retained VO2max fraction (~1.8% lost per 300m above 300m, partially recovered when acclimatised) and the race is re-predicted through the existing Daniels engine, so the altitude cost grows with distance without any distance-specific rules. The reported effective VDOT is back-solved from the final adjusted time, giving a single "what would this equate to at sea level in perfect weather" number. Beyond the race prediction the page shows re-targeted training paces for all five Daniels zones — each evaluated at its own realistic session duration, because a 90-minute long run and a set of 400m reps are not equally exposed to heat — and a temperature sensitivity curve with the user's forecast marked, which is what makes the case for an early start. Also: - Slider gains an optional thumbLabel; the thumb is the element that receives focus and carries role="slider", so an aria-label on the root left it announced as an unnamed control. - Route, side nav, prerender list and sitemap wired up. The page accepts the same ?d=&t= share params the VDOT calculator emits. Verified with tsc, eslint (no new warnings), a production build, and a browser pass covering both breakpoints: dew points match the Magnus formula, altitude retention matches published acute-exposure figures, and no horizontal overflow at 390px. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WER1sSjDfXQunuP45nVShs
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
✅ Deploy Preview for trainpace ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| UnusedCode | 4 medium |
| BestPractice | 1 medium |
| ErrorProne | 7 medium 75 high |
| Security | 2 high |
| CodeStyle | 2 minor |
| Complexity | 9 medium |
🟢 Metrics 155 complexity · 4 duplication
Metric Results Complexity 155 Duplication 4
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
aleexwong
force-pushed
the
claude/something-cool-428xv1
branch
from
August 7, 2026 15:02
a2da2b5 to
e8db628
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Adds
/conditions, a tool that answers the two questions runners actually have on race week:There was no weather-aware tool in the app — no mention of heat, humidity, dew point, or altitude anywhere in the codebase — so this fills a real gap rather than restating what the pace/VDOT calculators already do. It builds on the existing Daniels engine instead of duplicating it.
The model
Two penalties, modelled independently and then composed.
Heat keys on the sum of air temperature and dew point (°F) rather than on temperature or relative humidity alone. Dew point is what caps evaporative cooling, so 20°C/90% RH and 30°C/40% RH are very different runs despite both reading as "warm". The penalty is then scaled by race duration — at 24°C/75% a 5K costs ~2% and a marathon ~4.8%. Most hot-weather pace tables apply one flat percentage across all distances, which is why they tend to feel wrong to experienced runners.
Altitude is applied at the fitness level instead of the pace level: VDOT is scaled by the retained VO₂max fraction (~1.8% lost per 300 m above 300 m, partially recovered when acclimatised) and the race is re-predicted through the existing engine. The altitude cost then grows with race distance on its own, with no distance-specific rules.
The reported effective VDOT is back-solved from the final adjusted time, giving a single "what would this equate to at sea level in perfect weather" number.
What the page shows
Cold is deliberately not modelled as a bonus; the FAQ says so rather than leaving it unexplained.
Notable changes outside the feature
Slidergains an optionalthumbLabel. The Radix thumb is the element that receives focus and carriesrole="slider", so anaria-labelon the root left it announced as an unnamed control. The shared component is only consumed by this new code today, and the prop is optional and additive.?d=&t=share params the VDOT calculator emits, so you can go from "here's my fitness" to "here's what race day looks like" without retyping.Verification
Numbers were checked, not just the build:
tscclean; ESLint 0 errors and 0 new warnings; production build passes;/conditionsprerenders into its own 35 kB chunkThe browser pass caught two bugs static checks would have missed: the global
#root { text-align: center }from the Vite template was centering copy meant to be left-aligned, and the mobile stack buried the answer below the training-paces table. Both fixed.Notes for review
🤖 Generated with Claude Code
https://claude.ai/code/session_01WER1sSjDfXQunuP45nVShs
Generated by Claude Code