{
  "schemaVersion": 1,
  "slug": "football-passer-rating-calculator",
  "category": "sports",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "d41f86dca9f6cfbcd0a52fabe9df5da9a0c16cd763c59731ac7e107807cd342a",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/football-passer-rating-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "R = (f1 + f2 + f3 + f4) ÷ 6 × 100; f1 = clamp((C ÷ a − 0.3) × 5), f2 = clamp((Y ÷ a − 3) × 0.25), f3 = clamp(T ÷ a × 20), f4 = clamp(2.375 − I ÷ a × 25); f1, f2, f3, f4 ∈ [0, 2.375]",
    "vars": [
      [
        "a",
        "pass attempts (min 1)"
      ],
      [
        "C",
        "completions"
      ],
      [
        "Y",
        "passing yards"
      ],
      [
        "T",
        "touchdown passes"
      ],
      [
        "I",
        "interceptions"
      ],
      [
        "f1",
        "completion factor"
      ],
      [
        "f2",
        "yards-per-attempt factor"
      ],
      [
        "f3",
        "touchdown factor"
      ],
      [
        "f4",
        "interception factor"
      ],
      [
        "R",
        "NFL passer rating"
      ]
    ],
    "note": "Every factor is clamped to 0–2.375; grades: ≥110 elite, ≥95 excellent, ≥85 above average, ≥75 average, otherwise below average."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "if(![completions,attempts,yards,touchdowns,interceptions].every(Number.isFinite)||![completions,attempts,yards,touchdowns,interceptions].every(Number.isInteger)||attempts<1||completions<0||completions>attempts||yards<0||touchdowns<0||interceptions<0||touchdowns>completions||touchdowns+interceptions>attempts)return{rating:null,compPct:null,yardsPerAttempt:null,tdPct:null,intPct:null,__error:'inputError'};const a=attempts,comp=Math.min(2.375,Math.max(0,(completions/a-0.3)*5)),yds=Math.min(2.375,Math.max(0,(yards/a-3)*0.25)),td=Math.min(2.375,Math.max(0,touchdowns/a*20)),intc=Math.min(2.375,Math.max(0,2.375-interceptions/a*25)),rating=(comp+yds+td+intc)/6*100;return{rating,compPct:completions/a*100,yardsPerAttempt:yards/a,tdPct:touchdowns/a*100,intPct:interceptions/a*100};",
    "inputs": [
      {
        "name": "completions",
        "type": "number",
        "default": 24,
        "min": 0,
        "max": 100,
        "step": 1,
        "slider": true
      },
      {
        "name": "attempts",
        "type": "number",
        "default": 36,
        "min": 0,
        "max": 120,
        "step": 1,
        "slider": true
      },
      {
        "name": "yards",
        "type": "number",
        "default": 285,
        "min": 0,
        "max": 1000,
        "step": 1,
        "slider": true
      },
      {
        "name": "touchdowns",
        "type": "number",
        "default": 3,
        "min": 0,
        "max": 20,
        "step": 1,
        "slider": true
      },
      {
        "name": "interceptions",
        "type": "number",
        "default": 1,
        "min": 0,
        "max": 20,
        "step": 1,
        "slider": true
      }
    ],
    "outputs": [
      {
        "name": "rating",
        "precision": 1,
        "unit": ""
      },
      {
        "name": "compPct",
        "precision": 1,
        "unit": "%"
      },
      {
        "name": "yardsPerAttempt",
        "precision": 2,
        "unit": "yd"
      },
      {
        "name": "tdPct",
        "precision": 2,
        "unit": "%"
      },
      {
        "name": "intPct",
        "precision": 2,
        "unit": "%"
      }
    ],
    "interpret": null
  }
}
