The Physics Pipeline
CornCast chains seven physical processes together to compute the corn window. Each stage feeds into the next β change one input and the effect ripples downstream. Three modifier layers adjust values mid-chain. Two stages produce time outputs (corn opens, corn closes). The rest are quality and quantity variables that shape those times.
The overnight freeze is the engine of everything. When air temperature drops below 32Β°F, free water at the snow surface refreezes into a continuous ice matrix β the crust the morning sun must melt before corn can form. The colder the night, the thicker and harder this matrix. A 10Β°F night builds something close to reinforced concrete at the surface. A 29Β°F night barely skins it.
Sky clarity matters as much as temperature. On clear nights, the snow surface radiates heat directly to a cold sky and receives very little back β so the snow surface can be 2β5Β°F colder than the air thermometer reads. Clouds reverse this: they act as a warm blanket, radiating heat back down. A clear 22Β°F night builds a meaningfully deeper crust than a cloudy 22Β°F night even though the thermometer reads the same. CornCast applies up to a 2Γ effective freeze bonus for a clear sky versus fully overcast.
Elevation compounds the cold. Air temperature drops roughly 3β4Β°F per 1,000' of elevation gain. The app lapse-corrects all weather data to the peak's actual elevation β a face at 13,500' refreezes harder than one at 12,000' even when the forecast originates from the same grid point.
f_lo = overnightLow + lapseAdj [ski zone temp; lapseAdj = (summit β skiZone)/1000 Γ 3.5Β°F]
rawFQ = (30 β f_lo) / 35 + ccFreezeBonus
ccFreezeBonus: CCCβ₯0.65 β +0.05 Β· CCCβ€0.35 β β0.09 [cold pack amplifies; depleted absorbs]
rawFQ += freezeDurBonus [0 at β€2 hrs below 28Β°F, up to +0.15 at 8+ hrs]
freezeQ = rawFQ Γ (0.50 + 0.50 Γ clearSkyFraction)
effFQ = max(0.03, freezeQ β windScour)
effFQ = max(0.03, effFQ Γ (1 β matPen)) [matPen 0β20%; grain age degrades bonds]
β Colder + clearer + cold-core pack + sustained hours = deeper, harder freeze
Male & Granger (1981), Water Resources Research 17(3) β snow surface energy exchange and longwave radiative balance; Pomeroy & Brun (2001), Snow Ecology, Cambridge β physical properties of snow
β Sets the thermal debt that solar energy must repay before corn can open (Step 4)
β³ Modifier β adjusts Steps 1, 4 & 5
Seasonal Snowpack Maturity
The same overnight cold does not produce the same crust in March and in June. The difference is grain metamorphism β a continuous structural change driven by the repeated daily freeze-thaw cycle.
In March, the snowpack surface is composed of sharp, angular crystals with enormous surface area. They bond tightly when frozen and produce an excellent, hard crust. Over the following months, those crystals round and enlarge through a process called equilibrium metamorphism. Grains grow from 0.1β0.5mm needles into 1β4mm rounded spheres. Rounded grains have far less contact area with their neighbors β they bond weakly when refrozen, producing a thinner, more fragile crust from the same overnight temperature.
There is a second effect: the thermal state of the full snowpack column also degrades through the season. A March snowpack at 12,000' is cold all the way to the bottom β the overnight freeze can penetrate 30β50cm, creating a deep structural crust. By late May or June, the entire column is often isothermal β uniformly at 32Β°F with no cold reserve. The overnight freeze can now only penetrate 5β10cm into the surface, creating a thin veneer regardless of how cold it got. The corn window still opens, but it opens faster and closes sooner.
CornCast applies both effects as graduated monthly penalties.
When live Open-Meteo archive is available (primary model):
packRipeness = surfaceRipeness Γ 0.60 + columnRipeness Γ 0.40 + depthAdj
grainQuality = 0.50 Γ packRipenessGrainCurve(pr) + 0.30 Γ recentCycles + 0.20 Γ min(1, ftCyclesTotal/8)
thermalMass = 0.65 Γ cccComponent + 0.35 Γ sweComponent + collapseAdj
matPen = max(0, min(0.20, (1 β grainQuality) Γ 0.20)) [derived]
Aspect-specific solar pack state (v45) β energy balance model:
solarAbsorbed = solarMorning[W/mΒ²] Γ BASE_RAD[asp] Γ radBoost Γ (1 β 0.55 albedo)
Solar melt fires when solarAbsorbed > 180 W/mΒ² [Male & Granger 1981]
Ambient melt fires when tmax > 36Β°F [same as global model]
Cycle counted when (solar melt OR ambient melt) AND tmin < 28Β°F
Surface ripeness solar heat load = max(0, solarAbsorbed β 180) Γ· 500 per day
SE clear April: absorbed β 280 W/mΒ² β solar melt, heat load 0.20/day
NW any month: absorbed β 68β91 W/mΒ² β no solar melt, 0 solar heat load
NE June clear (radBoost Γ1.50): absorbed β 186 W/mΒ² β solar melt begins
Clouds suppress solar loading naturally via measured solarMorning β no separate cloud term
columnColdContent stays shared β deep column is not aspect-specific
Fallback when archive fails (calendar defaults only):
March April May June
packRipeness: 5% 15% 40% 70%
Colbeck (1987), IAHS 162 β crystal metamorphism in seasonal snow; Armstrong & Brun (2008), Snow and Climate, Cambridge; Clow et al. (2012), JGR Atmospheres β Front Range snowpack trends at elevation
β³ Modifier β adjusts Step 1 & Step 6
Wind Scour
While overnight cold builds the refreeze crust, wind is simultaneously trying to erode it β physically breaking fragile ice bonds before they can consolidate. This effect is most significant on west and northwest-facing terrain, which bears the full brunt of Colorado's prevailing westerly flow. East and southeast faces are typically sheltered by the terrain behind them.
The model applies a wind scour penalty above about 12 mph. That penalty is scaled by two factors: the compass direction of the face (west is most exposed, southeast least) and a per-face micro-terrain rating that distinguishes a sheltered cirque bowl from an exposed ridge crest. The wind threshold is higher when computing window duration (18 mph) than when computing freeze quality (12 mph) β the corn surface, once formed, is less fragile than the crust forming overnight.
Aspect wind exposure: W=1.00 Β· NW=0.90 Β· SW=0.72 Β· N=0.55 Β· S=0.50 Β· NE=0.45 Β· E=0.35 Β· SE=0.28
Wind direction advection (when live wind direction available):
windScour Γ max(0.5, 1 + cos(windAngle β faceAngle) Γ 0.5)
Windward (direct): Γ1.5 Β· Crosswind: Γ1.0 Β· Lee: Γ0.5
β³ Modifier β adjusts Steps 4, 5 & 6
Two-Layer Snowpack Ripeness
The snowpack's readiness to produce corn depends on two physically distinct layers operating on entirely different timescales. Understanding the difference between them explains a lot about why some days produce great corn and others don't β even with similar overnight forecasts.
The surface layer (top ~30cm) responds to the past two weeks of weather. This is the zone that refreezes overnight, thaws each morning, and directly produces the corn surface you ski on. Warm days, above-freezing nights, rain, and solar loading all erode its refreeze potential. Cold nights and fresh snowfall restore it. The surface layer is reactive β a week of warm weather degrades it noticeably, and a cold snap with a storm can restore it within a few days. CornCast scores this layer using the past 14 days of actual weather data pulled from the ERA5 archive.
The column layer (30cm to full depth) responds to the entire season from March 1 onward. The deep snowpack accumulates cold content over months, and it releases that cold slowly β roughly 4.5 times slower than the surface. A cold March and April builds a substantial cold reserve that resists the deep pack going isothermal, even during warm mid-April weeks. Research at Niwot Ridge (11,500', just below the Indian Peaks ski zone) found that non-zero column cold content delayed snowmelt onset by up to 5.7 hours compared to a fully isothermal pack. A deep, cold column is what keeps a corn window open deep into a warm afternoon instead of collapsing to slush by 10 AM.
Why SWE matters here: A high snow-water-equivalent year means a deeper pack. More depth means more total cold stored in the column, and a pack that resists going isothermal longer into the spring. This is why SNOTEL SWE feeds directly into the column calculation β it's a meaningful physical link, not a simple background adjustment.
The two layers combine into a single ripeness score: the surface layer carries 60% of the weight (it governs whether overnight refreeze happens at all) and the column layer carries 40% (it governs how fast the window collapses). This combined score flows through Steps 4, 5, and 6 wherever the isothermal state of the pack matters.
Surface ripeness: scored from 14-day weather history. Warm days erode. Cold nights restore.
Column cold content: scored from full season (Mar 1 β target). Warms ~4.5Γ slower than surface.
Combined ripeness = surface Γ 0.60 + column ripeness Γ 0.40
High surface + cold column β long window, opens on time, slow slush transition
High surface + warm column β good corn, shorter window before slush collapse
Low surface + any column β poor corn regardless β no overnight freeze = no crust
Jennings et al. (2018), The Cryosphere 12 β column cold content and melt onset timing at alpine sites; Fierz (2011), Encyclopedia of Snow, Ice and Glaciers β thermal attenuation of heat waves with snowpack depth; DeWalle & Rango (2008), Principles of Snow Hydrology β cold content definition and seasonal accumulation; Sturm & Holmgren (1998), JGR β thermal conductivity and depth attenuation in natural snowpacks
βΌ
The sun's energy reaches a tilted slope most intensely when its rays strike nearly head-on. A south-facing slope in March catches the low noontime sun almost perpendicularly β maximum energy per square foot. A west face at the same time gets sunlight at a shallow angle, spread across a much larger area, delivering far less energy to the same patch of snow.
This geometry shifts dramatically through the season. In March, the noon sun sits only ~50Β° above the horizon. By June it climbs to ~73Β° β high enough that it actually overshoots south-facing terrain, reducing the SE and S solar advantage. Meanwhile, north and northeast faces gain dramatically in June because the sun rises so far north of east that it can directly illuminate terrain that was almost entirely in shadow all winter. This is the physical reason June NE corn is achievable at all when March NE corn almost never works.
Morning clouds reduce effective radiation proportionally. A 60% cloud-cover morning cuts available melt energy nearly in half.
April radiation multipliers (relative to flat ground):
S: 1.38 Β· SE: 1.25 Β· SW: 1.20 Β· E: 0.88 Β· W: 0.72 Β· NE: 0.55 Β· NW: 0.30 Β· N: 0.18
June shifts: S loses ~18% Β· N and NE gain 50β60% (sun rises far north of east)
Iqbal (1983), An Introduction to Solar Radiation, Academic Press β solar geometry and slope irradiance
β Controls how fast the thermal debt is repaid (Step 4) and how long the window lasts (Step 6)
βΌ
The melt clock doesn't start until direct sunlight reaches the snow surface. An east face gets direct sun as soon as the sun clears the horizon β around 6:45β7:00 AM in April. A south face must wait while the sun rotates around through the northeastern sky; it typically isn't illuminating a south face until around 9:30 AM. A west face waits until early afternoon.
Local terrain introduces an additional delay that pure solar geometry can't predict. A ridge to the east can block morning light on an otherwise east-facing bowl by 20β60 minutes. Apache Peak's northeast bowl, for example, sits behind a ridge crest that delays direct sun until approximately 8:30 AM in April β over 40 minutes later than the solar geometry alone would suggest. These terrain shade delays are hand-coded from field observation for each face in the model.
April sun-hit times at 40Β°N:
E ~6:54 AM Β· NE ~7:48 AM Β· SE ~7:18 AM Β· S ~9:30 AM Β· SW ~12:00 PM Β· W ~1:30 PM
+ per-line terrain shade delay (sh field on each named descent line)
Examples: Isabelle Glacier sh=0.4h Β· Shoshoni Bowl sh=0.3h Β· Apache Couloir sh=0.1h
Derived from field observation and CalTopo terrain analysis for each FRSK line.
β Sets the earliest possible corn open time β the melt clock starts here (Step 4)
βΌ
When the sun hits the face, the surface doesn't immediately become corn β it is still frozen solid. The snow must absorb enough solar energy to melt the overnight ice bonds before the corn state is reached. Think of the overnight freeze as a thermal debt: the colder the night and the harder the freeze, the more energy must be repaid before the surface softens.
The rate at which that debt is repaid depends on two things: how much solar energy is arriving at the surface (driven by aspect, cloud cover, and the radiation calculations in Steps 2β3) and how quickly the morning air is warming (dawn temperature to afternoon high). A bright, sunny aspect on a clear morning with rapidly rising temperatures pays off the debt quickly. A heavily clouded northeast face in March may never pay it off during reasonable skiing hours β the model caps melt delay at 4.5 hours for exactly this reason.
One notable interaction: a snowpack that is already isothermal actually speeds up corn onset. Because the pack had no cold reserve, the overnight crust was thinner to begin with, so the thermal debt is smaller. The corn opens sooner β but the same thin crust means the window will close sooner too.
f_da = dawnTemp + lapseAdj [ski zone dawn temp]
meltDelay = (effFQ Γ max(0, 33 β f_da))
Γ· (effRad Γ max(1.0, morningRise/6) + 0.01)
meltDelay Γ (1 β ripenMeltFactor) [packRipeness>0.50 shrinks delay: thin crust thaws fast]
β Capped at 2.0 hours
β cornOpens = max(sunHitTime, sunHitTime + meltDelay Γ 1.05)
π OUTPUT A: Corn Opens = sun hits face + melt delay
Kustas & Rango (1994), Water Resources Research 30(5) β simplified energy budget for snowmelt onset
β Subtract your approach time from Corn Opens to get your trailhead departure time
βΌ
Two faces can have identical temperatures, sun angles, and cloud cover β but if the snow surfaces are different, the corn quality will be different. Crust quality is determined by how much refreeze material is available and how well it can bond.
Storm snow (less than ~10 days old) is the best raw material. Fresh angular grains have enormous surface area and bond tightly when frozen. This quality fades rapidly β grain rounding begins within hours of deposition, and by day 7 the crust potential has dropped to roughly half of what it was fresh. A 1" dusting ages out within 24β48 hours. A deep 10β12" storm retains useful crust potential for a week or more, because deeper snow takes longer to metamorphose all the way through.
Consolidated spring pack (more than ~10 days since the last storm) behaves differently. Once grains have rounded and stabilized into large melt-freeze polycrystals, the aging process essentially stops β grain size no longer changes. What matters then is whether there is enough surface material to refreeze at all, and whether the seasonal maturity penalties have weakened the bonds. A deep consolidated April pack still produces real corn. A thin consolidated June pack produces marginal corn regardless of how cold the night was.
The model takes whichever score is higher β the fresh storm calculation or the consolidated pack floor.
Storm layer: crustQ = (stormDepthΓ·8) Γ exp(βdaysΓ0.10) Γ (0.70 + grainQualityΓ0.30)
[8" is full potential; halves every 7 days]
Pack floor: crustQ = 0.35 Γ (faceSnwdInΓ·36) Γ (0.60 + grainQualityΓ0.40)
[uses full-pack depth at ski zone from elevation gradient β NOT storm depth]
[faceSnwdIn from SNOTEL+OM regression adjusted for SR wind-loading]
crustQ = max(stormLayer, packFloor, 0.05)
crustQ Γ srPatchFactor [sr=3: 1.00, sr=2: 0.92, sr=1: 0.82 β surface patchiness]
crustQ += sweAdj [β0.12 to +0.07 from absolute SWE inches]
crustQ Γ densityMult [0.85β1.08 from SWEΓ·depth ratio]
Snow Surface % = final crustQ β "how much material is available to refreeze?"
Fierz et al. (2009), UNESCO-IHP β International Classification for Seasonal Snow, melt-freeze grain classification; Colbeck (1986), Acta Metallurgica 34 β grain coarsening in wet snow; Colbeck (1979), J. Colloid Interface Science β ice-to-ice bond strength; Colbeck (1997), CRREL Report 97-10 β sintering and grain equilibrium
β Primary driver of window duration (Step 6) and contributes directly to final score
β³ Modifier β adjusts Steps 5 & 6
Basin Snowpack β Live NRCS SNOTEL SWE
The NRCS SNOTEL network measures total snow water equivalent at stations throughout the range. CornCast uses SWE as a percentage of the 1991β2020 median for that date, because raw SWE numbers vary enormously by elevation and time of year β percent of median is directly comparable across dates and stations.
A below-normal snowpack year means the surface has been through more melt-freeze cycles relative to the calendar date. The snow is more fatigued and coarser than it would be in a normal year. An above-normal year tends to have deeper, fresher surface material and a column with more cold content reserve β because a thicker snowpack stores more cold and yields it more slowly. This is why SWE feeds directly into the column cold content calculation (see Two-Layer Ripeness modifier above) rather than acting as a simple surface modifier.
The effect is intentionally modest. A cold, clear night on a 75% SWE year can still produce excellent corn. SWE is a background nudge, not a threshold. Stations are weighted by elevation proximity to the ~12,000' ski zone.
Stations: Niwot Ridge #663 Β· University Camp #838 Β· Sawtooth #1251 Β· Wild Basin #1042 Β· Bear Lake #322 Β· Joe Wright #551
Elevation weight: closer to 12,000' = more weight
Effect range: roughly Β±10% on crust quality, Β±15 minutes on window duration
USDA Natural Resources Conservation Service β SNOTEL Data & Products; station SWE % of 1991β2020 median
βΌ
Once corn opens, how long does it last? The window closes when free water content in the surface layer exceeds roughly 8β12% by volume β at that point every grain is floating in liquid rather than lightly bonded to its neighbors, and the surface becomes saturated slush. The crust must melt completely through before this happens.
Crust thickness is the dominant term. A deep, hard freeze from a very cold night takes far longer to fully melt through than a thin veneer. This is why a 5Β°F night produces a longer skiing window than a 28Β°F night, even when corn opens at the same time β there is simply more crust thickness to sustain the condition.
Two independent mechanisms close the window. Solar melt rate β absorbed shortwave radiation on this specific aspect β and sensible melt rate β warm air conducting heat into the surface above 36Β°F β both contribute. A warm clear afternoon combines both and closes the window fastest. A warm overcast afternoon has only sensible heat and closes more slowly. This is why cloud cover meaningfully extends the window even when temperatures are unchanged.
Shaded faces (NW, N) have near-zero solar melt rate β they are driven entirely by ambient air temperature. A NW face on a cold afternoon stays in corn longer than an SE face in the same afternoon because the SE face receives direct solar energy the NW face does not. Wind above about 18 mph mechanically disrupts the softened corn surface and shortens the window independently of the energy balance.
Energy balance close time (v46):
solarMeltRate = effRad Γ 1.0 [solar absorbed at this aspect; cloud-attenuated]
sensibleMeltRate = max(0, f_hi β 36) Γ 0.04 [warm air conduction; only mechanism for shaded faces]
totalMeltRate = solarMeltRate + sensibleMeltRate
cornBudget = (crustQ Γ 5.0 + effFQ Γ 10.0) Γ (0.72 + thermalMass Γ 0.48)
rawDur = cornBudget Γ· totalMeltRate + sweDurBonus β windDurPenalty
rawDur Γ apDurFactor [ap=3: 1.00, ap=2: 0.95, ap=1: 0.88]
β Clamped 0.2 β 4.0 hours Β· Ref: Male & Granger (1981)
SE clear warm day: high solar + high sensible β fast close
NW shaded face: near-zero solar β sensible only β slow ambient close
Any face overcast: effRad suppressed by cloud β window extends naturally
β cornCloses = cornOpens + duration
π OUTPUT B: Corn Closes = corn opens + duration
β Corn Opens and Corn Closes together define the window; your arrival must fall between them
βΌ
Two southeast faces at 12,500' with identical forecasts can produce dramatically different corn. One is a clean 35Β° apron with six feet of consolidated snow, sheltered from prevailing winds, and uniform sun exposure across the slope. The other is a rocky broken face with thin patchy coverage, sits on a wind-scoured ridge, and has cliff ribs that keep portions in shadow well into mid-morning. The physics model, run identically on both, gives them the same raw score. The terrain factor is how CornCast accounts for this difference.
Three components rate each face on a 1β3 scale. Snow Retention: does this face reliably hold a deep continuous snowpack through spring, or is it wind-stripped and rocky? Aspect Purity: does the entire face receive uniform solar input at the same time, so the corn window opens consistently across the slope rather than in patchy zones? Wind Shelter: is the refreeze surface protected from overnight scour?
These ratings are based on published route descriptions and first-hand field knowledge β a deliberate human judgment layer on top of the physics, and a known source of subjectivity in the model.
q = (SnowRetention + AspectPurity + WindShelter) / 9 [range: 0.33 β 1.00]
Terrain effects are now embedded directly in physics steps:
sr β srDepthMult (face snow depth) + srPatchFactor (surface quality)
ap β apDurFactor (window duration consistency)
we β ad.wx inside windScour (freeze quality + duration)
No separate terrain multiplier β double-counting eliminated in v44.
Roach (2001), Colorado's Indian Peaks Wilderness, Fulcrum Publishing; frontrangeskimo.com trip reports; first-hand field observation. Not GIS-derived β a known model limitation.
β Final multiplier on the physics score β produces the 0β100 output
βΌ
All pipeline outputs combine into a single score. The raw number is normalized so that a benchmark SE-facing corn objective at 12,500' in March under near-perfect conditions scores 100. The calibration target represents a clean, well-sheltered southeast couloir with reliable coverage and consistent solar exposure from first light through mid-morning β representative of the premier spring corn conditions in the Indian Peaks. A score of 80 means conditions are strongly in your favor. A score of 30 means you might find corn in sheltered pockets but shouldn't plan your day around it.
Score bands:
75β100 Excellent β deep uniform freeze, 2+ hr window, classic spring skiing
50β74 Good β reliable corn, 1β2 hr window, may vary slightly across face
25β49 Marginal β short window, thin crust, or patchy; worth checking
0β24 Poor β theoretical window only; too short to plan around
Scoring components:
fqScore (0β28) β freeze quality Γ grainGateFactor Γ meltMatchFactor
radScore (0β18) β effective radiation Γ 14
cqScore (1β9) β crust quality bell curve, peak at 0.42
durBonus (0β4) β +4 if β₯2h, +2 if β₯1.2h
grainGateFactor = min(1.0, 0.30 + grainQuality Γ 0.70)
March zero cycles (gq=0.20): Γ0.44 β angular grains cannot form corn bonds
Prime April (gq=0.87): Γ0.91 β near-full credit
meltMatchFactor = min(1.0, effRad Γ· (effFQ Γ 1.8 + 0.30))
SE clear April: ratio β₯1 β Γ1.00 β radiation exceeds what's needed
NE March 5Β°F: ratio β0.32 β fqScore cut 68% β sun cannot melt that crust
A cold night only scores fully when grain structure supports corn bonds
AND radiation can complete the melt cycle. Season arc emerges from physics.
Changelog
v49 β Duration fix, auto-compute, chart polish (2026-03-27)
Physics fix and UX polish pass addressing feedback from field use sessions:
- cornBudget effFQ weight 10β5: Eliminates double-counting of cold reserve (CCC was feeding both effFQ and thermalMass multiplier). Pawnee SE 22Β°F overnight / 39Β°F high: 3.7hβ2.6h. Removes systematic 4h cap hits on cold-afternoon clear days.
- Auto-compute on line select: Selecting a descent line now immediately computes the result when weather data is loaded β no manual button press required. Compute button remains for re-running after changing forecast fields.
- Weather strip summit label: Strip header now shows summit elevation so users understand why driver card temperatures differ from tile temperatures.
- Ripeness chart subtitle: Added "14-day trailing window Β· recent days weighted more heavily Β· pan β for earlier history" to clarify the surface freeze quality line is a trailing indicator.
- Warm-day heat ticks: Orange tick marks at base of ripeness chart on days where tmax > 38Β°F β makes the causal connection between warm spells and surface freeze quality dips visually obvious.
- Target date score snap: Daily corn score chart target bar now uses actual result tab score rather than chart estimate when a line is selected. White dot marks the actual score, eliminating the 8-point apparent discrepancy.
v48 β Driver narrative: Inputs / Reasoning / Result (2026-03-22)
Complete rebuild of the driver narrative to communicate physics in plain language rather than model internals.
- Three-line card format: Each step shows Inputs (the facts that went in), Reasoning (what the model did with them and why), and Result (what this means for your day). No coefficients, gates, or factor names visible to the user.
- Colour-coded border: Green left border = favourable conditions, red = unfavourable, neutral = mixed. Scannable at a glance.
- Plain language throughout: Grain gate, meltMatch, thermalMass, crustQ and all other internal variable names removed from user-facing text. Physics explained as cause-and-effect rather than formula output.
- Score bars retained but de-emphasised β shown as a small bar at the bottom of each card for users who want the detail, not as the primary reading.
v47 β Driver card template + v46b content (2026-03-22)
v46 β Energy balance close time (2026-03-22)
Window duration is now derived from a direct energy balance rather than an empirical formula with a temperature penalty. The corn window closes when cumulative absorbed energy exhausts the surface layer's energy budget.
- Two independent melt mechanisms: Solar melt rate (effRad Γ 1.0) and sensible melt rate (max(0, f_hi β 36) Γ 0.04) are additive but physically distinct. Solar dominates SE/S/E faces. Sensible heat is the only mechanism for NW/N faces and for any face on overcast days.
- hiPenalty removed: The temperature-only penalty (f_hi β 46) Γ 0.085 is gone. A warm overcast afternoon and a warm clear afternoon are no longer treated identically β cloud cover suppresses effRad naturally, extending the window on overcast days.
- Crust energy budget: (crustQ Γ 5.0 + effFQ Γ 10.0) Γ thermalMassMult. Deep freezes (high effFQ) produce larger budgets and longer windows. thermalMass multiplies the budget: cold deep packs take more energy to exhaust. Ref: Male & Granger (1981).
- NW/N face windows: With near-zero solar melt rate, shaded faces are driven entirely by sensible heat. On a cold night + warm afternoon (18Β°F/48Β°F), a NW face can produce a genuine 3h window β physically correct, score bounded by grain quality and thermalMass.
v45b β Remove lateOpenPenalty, RAW_MAX 58 (2026-03-22)
Two corrections following v45 benchmarking:
- lateOpenPenalty removed: The Γ0.80/Γ0.90 multiplier for windows opening after 11:30 AM has been removed. Clock time is not a snow quality metric. A NW couloir opening at 2:30 PM after a cold night produces the same quality corn as an SE face opening at 8:30 AM β the hiPenalty and short-window multipliers already account for warm afternoon temperature compressing the window. The late-open penalty was an implicit SE-face-centric bias against geometrically shaded aspects. v46 will replace hiPenalty with a direct solar+sensible energy balance close-time calculation.
- RAW_MAX updated to 58: v45 aspect-solar cycling gives SE/S faces 28+ accumulated cycles by April, pushing grainQuality to 0.98 β higher than the pre-v45 ceiling assumed. Ceiling scenario is S face April 8Β°F summit on prime pack.
v45 β Aspect-specific solar pack state, energy balance model (2026-03-22)
Pack state parameters β surface ripeness, freeze-thaw cycles, grain quality β are now computed per-aspect using a direct snow surface energy balance rather than treating all faces identically from a single grid-point temperature record.
- Two melt mechanisms, physically separated: Solar melt (solarAbsorbed > 180 W/mΒ², from Male & Granger 1981) and ambient melt (tmax > 36Β°F) are counted independently. A freeze-thaw cycle fires when either mechanism was active and the following tmin < 28Β°F.
- Direct energy balance: solarAbsorbed = solarMorning[W/mΒ²] Γ BASE_RAD[asp] Γ radBoost Γ 0.45. Snow albedo 0.55 (spring corn snow). No temperature conversion β solar and ambient are kept as distinct physics.
- Clouds handled correctly: solarMorning is measured attenuation from Open-Meteo β a 75% cloud day produces ~25% of clear-sky solar. Cloud suppression of cycling flows through naturally with no separate term.
- Natural seasonal arc from data: SE crosses the solar melt threshold from March onward on any reasonably clear day. NE crosses it only in June when radBoost Γ1.50 finally compensates for the low BASE_RAD. NW/N never cross it β they cycle only via ambient temperature, which reaches 36Β°F reliably only in late May. This produces the correct field-observed seasonal arc without any calendar forcing.
- Surface ripeness heat load: max(0, solarAbsorbed β 180) / 500 per day β accumulated solar excess above the melt threshold, normalised. SE clear April: +0.20 heat load units/day. NW: zero solar heat load all season.
- Safe architecture: Pre-computed before cb({}) with try/catch. Exceptions silently set aspectPackState to null; cornWindow falls back to global values.
v44b β fqScore grain quality + melt match gates (2026-03-19)
Two physical gates added to fqScore so that a cold overnight freeze only scores fully as corn quality when the snowpack history and radiation balance both support it:
- Grain quality gate (grainGateFactor): fqScore Γ min(1.0, 0.30 + grainQuality Γ 0.70). On March angular grains with zero cycling history (grainQuality=0.20), even a 5Β°F night scores only 44% of freeze quality credit β the hard crust that forms is ice, not corn bonds. Prime April pack (grainQuality=0.87) scores 91% credit. The seasonal arc now emerges from grain development history, not raw freeze depth alone.
- Melt match gate (meltMatchFactor): fqScore Γ min(1.0, effRad Γ· (effFQ Γ 1.8 + 0.30)). A deep freeze on a NE face in March scores well only when solar radiation is sufficient to drive a complete melt-through. SE clear April: ratio exceeds 1 β no penalty. NE March 5Β°F: ratio β 0.32 β fqScore cut 68%.
- RAW_MAX recalibrated to 55. The correct ceiling is now April/May S face ~7Β°F summit on prime pack β not the March benchmark that was used previously. March cold nights are correctly capped below 80 due to grain gate.
v43 β Season Arc + Multi-Line Comparison (2026-03-19)
Two planning features built on the computed corn score trajectory:
- Season Arc Summary: A new card in the Result tab shows the prime window date range (days scoring β₯65), the 7-day trend direction, the season peak score and date, and whether the target date falls within the prime window. Derived from the same daily corn score trajectory that powers the chart.
- Best Lines Today: A sortable table of the top 20 scoring lines across all 155 FRSK descents for the current weather conditions, filterable by aspect group and basin. Departure times are computed using your Plan tab approach inputs. Clicking any row selects that line and re-computes. Appears at the bottom of the Result tab after compute.
v42 β Physics & Safety Inputs (2026-03-19)
Five improvements implemented together β all fail silently if data is unavailable:
- Overnight wind average: Wind scour now uses mean wind speed midnightβ6 AM instead of daily maximum. Freeze quality penalty is now physically correct β afternoon gusts no longer degrade overnight crust calculations. Auto-fills the Plan tab wind field with overnight mean when live data is available.
- Elevation season offset: Isothermal probability now decreases by ~0.04 per 1,000' above 11,500' ski zone elevation. High-elevation terrain (13,000'+) stays cold-core longer than the calendar date alone implies. Consistent with Clow et al. (2012) Front Range snowpack trends.
- 3-point depth gradient: Snow depth regression now uses all available SNOTEL stations per basin (both high and low elevation) rather than just the highest. More anchor points = more accurate ski zone depth extrapolation for the pack floor and isothermal calculations.
- Dust-on-snow toggle: Manual flag in Plan tab applies ~25 min earlier corn onset and ~15 min window compression when active. Links directly to CAIC dust-on-snow report. About tab limitation updated.
- Convective risk flag: When CAPE forecast exceeds 200 J/kg and the window opens after noon, a warning alert appears in the Result tab. High-CAPE (500+ J/kg) late windows show a red alert; moderate CAPE shows orange.
v41 β Physics accuracy audit + full UX/narrative update (2026-03-19)
Comprehensive audit of every physics step shown to the user. All driver rows and About tab formula boxes now accurately reflect the actual model implementation:
- Bug fix:
ad.note undefined in adapter β "Excellent corn β undefined" fixed.
- Lapse correction surfaced: Step 1 and Step 4 drivers now show ski zone temperatures (summit low + lapseAdj), not just the summit forecast value the user entered.
- Step 1: Added ccFreezeBonus (CCC modifies rawFQ Β±0.09) and matPen (cuts effFQ up to 20%) as visible rows. About formula box corrected β elevBonus removed (never existed), ccFreezeBonus/freezeDurBonus/matPen added.
- Step 2β3: aspRadPct now includes monthly radBoost multiplier (was April-only accurate). Live solar path correctly described β cloud attenuation not re-applied when shortwave data is direct from Open-Meteo.
- Step 4: isoPrb melt factor shown β isothermal pack shortens melt delay. About formula box cap corrected from 4.5h to 2.0h; isoMeltFactor added.
- Step 5: Complete rewrite. Driver now shows which mode dominated (storm crust vs consolidated pack floor) and explains that the pack floor uses full snowpack depth from the elevation gradient β not storm snow depth. sweAdj, ftBonus, and densityMult all shown. About formula box corrected β consolidated formula now uses faceSnwdInΓ·36, all modifiers shown.
- Step 6: isoPrb Γ0.25 collapse factor, sweDurBonus (Β±0.30h), and packReadiness multiplier all surfaced. About formula box corrected β threshold fixed (32Β°Fβ46Β°F), coefficient fixed (0.065β0.085), missing terms added.
- Result tab: "All Aspects" table replaced with "All Lines" showing all named descents on the same peak sorted by score.
- About tab: Seasonal Maturity modifier now distinguishes live model (CCC/ftCycles-based) from calendar fallback. Wind Scour shows v40 direction advection formula. Step 3 formula removes hardcoded old peak names. Known Limitations updated for named lines and SRTM elevation data.
v39+v40 β Elevation enrichment + Wind direction advection (2026-03-19)
Two physics improvements implemented together:
- v39 β Open-Meteo elevation enrichment: At app init, batch-queries the Open-Meteo /v1/elevation API (SRTM dataset) for the top and bottom coordinates of every LINES entry. Overwrites hand-estimated
ez (ski floor elevation) and sl (slope degrees) with geodetically correct values. Computed as: ez = bottom point elevation in feet; sl = atan(vertical_drop / hdist) in degrees. Fails silently β hand estimates remain if API is unavailable.
- v40 β Wind direction advection:
weatherData.windDir (already fetched from Open-Meteo) now modifies windScour in cornWindow. Computes the angle between the wind vector and the face normal to determine windward (+1), crosswind (0), or lee (β1) exposure. Windward faces receive up to 1.5Γ scour; lee faces as low as 0.5Γ. Driver narrative now shows wind direction and face alignment context.
v38 β Named Lines data model (2026-03-19)
Replaced the PK[].asp{} model with a flat LINES[] array where each FRSK-named ski descent is its own first-class object. Key changes:
- Data model: 155 named lines across 40 peaks. Each line has: name (from FRSK), peak assignment, aspect, tq, sh, ez, sl, hdist, and route waypoints. Physics unchanged β asp field drives all BASE_RAD/BASE_SUN/WIND_ASP/MONTH_ADJ lookups as before.
- Plan tab: replaced peak+aspect-grid UI with cascading Peak β Line dropdowns. Lines are listed by name with aspect in parentheses for disambiguation. Selecting a line highlights its polyline on the map in teal.
- Map: polyline tooltips now show the FRSK line name (e.g. "Skywalker Couloir") instead of "S. Arapaho Peak Β· SE". Peak markers retain pie chart visual, now built from LINES data aggregated by aspect.
- Popup: lines table replaces aspects table.
- Lines now have correct aspects computed from CalTopo geometry. Ski floor elevation (ez) and slope angle (sl) are computed from SRTM elevation data via Open-Meteo at app launch.
v37d β East Portal / Moffat area peaks (2026-03-19)
Added 11 new peaks covering the South Boulder Creek / Rogers Pass / Rollins Pass / Berthoud Pass corridor, all with FRSK-verified routes:
- Challenger Glacier (12,600'): W (Challenger), SW (Skyscraper), S (King Lake Bowl)
- Rollins Pass (11,671'): E/NW (Corona Pass), SE (Jenny Lake Bowl), S (Forest Lake Bowl)
- Mount Epworth (12,200'): S face
- Radiobeacon (12,400'): N (Northeast Couloir), NE (North Face), E (North Chutes), SE (East Face), NW (Forest Lake Bowl South), SW (Frosty Bowl)
- Crater Peak (12,000'): N/NW/SW (Crater Couloirs Γ3)
- Heartbeat Peak (12,200'): E (Heartbeat Bowls), N (Icebox Express), S (Heart Lake Face)
- James Peak (13,294'): NW (North Slopes), N (Sky Pilot), E (St. Mary's Glacier), SE
- Mount Bancroft (13,250'): S (Bancroft Bowl), E (Ohman Lake), NE, W (Bear Claw), SW
- Mount Eva (13,130'): S (Eva Bowl), SE (South Couloir), N
- Witter Peak (13,018'): S (Welcome Couloir), NW
- Mount Flora (13,132'): NE (Northeast Bowls), N, S (South Chute)
All coordinates from FRSK CalTopo GeoJSON. Basin assignments (South Boulder Creek watershed) updated in getPeakBasin.
v37c β Indian Peaks: missing routes + 6 new peaks (2026-03-19)
Added missing FRSK-verified routes to existing peaks:
- Sawtooth Mtn: NE face (Northeast Face line)
- Red Deer Mtn: E face (East Slope line)
- Ogalalla Peak: SW face (Ogallala Express)
- Pawnee Peak: S face (Keyholes)
- Shoshoni Peak: N face (Pawshoni Bowl) and NW face (North Couloir)
- Lone Eagle Peak: S face (Lone Rabbit)
Added 6 new peaks with FRSK-verified descent routes:
- St. Vrain Mtn: N, SE, S faces (was in basin code but had no asp entries)
- St. Vrain Glacier: NE (The Snake), SW (Vrain Drain), W (Ooh La La Express), S (#3)
- Little Pawnee Peak: N (North Couloir West), NE (North Couloir East), SE (Little Pawnee Headwall), E (Obliquity Couloir)
- Cherokee Peak: NE face above Crater Lake
- Mount Achonee: NW (Achonee Arrow), SE (Northeast Gully), S (Hopi/Peck Glacier)
- Mount George: N (Mount George Couloir), NE (Fair Glacier)
All coordinates sourced from FRSK CalTopo GeoJSON. Basin assignments updated in getPeakBasin.