{
  "version": "1",
  "siteUrl": "https://velograde.com",
  "constants": {
    "gravity": 9.81,
    "airDensity": 1.225,
    "defaultRider": {
      "riderKg": 75,
      "bikeKg": 10,
      "cda": 0.35,
      "crr": 0.004
    },
    "surfacePresets": {
      "road": {
        "cda": 0.32,
        "crr": 0.004,
        "label": "Road"
      },
      "gravel": {
        "cda": 0.38,
        "crr": 0.006,
        "label": "Gravel"
      },
      "mtb": {
        "cda": 0.42,
        "crr": 0.008,
        "label": "Mountain"
      }
    },
    "wheelPresets": [
      {
        "bsdMm": 622,
        "label": "700c / 29\""
      },
      {
        "bsdMm": 584,
        "label": "650b / 27.5\""
      },
      {
        "bsdMm": 559,
        "label": "26\""
      },
      {
        "bsdMm": 686,
        "label": "32\""
      }
    ]
  },
  "formulas": {
    "wheelCircumferenceM": "π × (wheelBsdMm + 2 × tireWidthMm) / 1000",
    "speedKmh": "circumferenceM × cadenceRpm × 60 × (frontTeeth / rearTeeth) / 1000",
    "powerWatts": "(gravityForce + rollingForce + aeroForce) × speedMs; see docs/PHYSICS.md"
  },
  "challengeEvaluation": {
    "lowestGear": "min(frontTeeth) / max(cogs) at given cadence",
    "statusBands": {
      "ok": "ftpW - requiredPowerW >= 30",
      "marginal": "margin 0–29 W",
      "insufficient": "margin < 0"
    }
  },
  "functions": [
    "wheelCircumferenceM(wheelBsdMm, tireWidthMm)",
    "speedKmh({ circumferenceM, cadenceRpm, frontTeeth, rearTeeth })",
    "powerWatts({ speedKmh, gradientPct, rider? })",
    "evaluateChallenge({ frontTeeth, cogs, circumferenceM, cadenceRpm, targetGradientPct, ftpW, rider? })",
    "lowestGearSpeed({ frontTeeth, cogs, circumferenceM, cadenceRpm })"
  ],
  "goldenCases": [
    {
      "label": "700c×28 mm, 50/11, 90 rpm",
      "wheelBsdMm": 622,
      "tireWidthMm": 28,
      "frontTeeth": 50,
      "rearTeeth": 11,
      "cadenceRpm": 90,
      "expectedSpeedKmh": 52.3,
      "tolerance": 0.5,
      "computedSpeedKmh": 52.3
    },
    {
      "label": "700c×28 mm, 34/28, 90 rpm",
      "wheelBsdMm": 622,
      "tireWidthMm": 28,
      "frontTeeth": 34,
      "rearTeeth": 28,
      "cadenceRpm": 90,
      "expectedSpeedKmh": 14,
      "tolerance": 0.5,
      "computedSpeedKmh": 14
    }
  ],
  "sampleChallenge": {
    "description": "34-50 / 11-30 cassette, 90 rpm, 8% target climb, 250 W FTP",
    "status": "insufficient",
    "lowestSpeedKmh": 13,
    "requiredPowerW": 263,
    "marginW": -13
  }
}