{
  "schemaVersion": 1,
  "slug": "swimming-split-calculator",
  "category": "sports",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "52e29c03bc1a23b15a9af5d24c9dde9816a0a00bcde1fcbeef18dd0ee3c5b7af",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/swimming-split-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": "L = ⌈d ÷ p⌉; t = (60m + s) ÷ L",
    "vars": [
      [
        "d",
        "Total distance (m)"
      ],
      [
        "p",
        "Pool length (m)"
      ],
      [
        "m",
        "Minutes"
      ],
      [
        "s",
        "Seconds"
      ],
      [
        "L",
        "Number of lengths"
      ],
      [
        "t",
        "Time per length (s)"
      ]
    ],
    "note": "Average full-length split = total time × pool length ÷ distance; per 100 m = total time × 100 ÷ distance. The last partial length is prorated to its remaining distance. Scenario factors adjust only the displayed first/last splits (fast start: 0.96/1.04; negative: 1.02/0.98); they are illustrative and do not form a complete schedule."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const total = minutes*60+seconds; if (!Number.isFinite(total) || total <= 0 || !Number.isFinite(distance) || distance <= 0 || ![25,50].includes(poolLength)) return { perLength: null, per100: null, lengths: null, firstLength: null, lastLength: null, __error: 'inputError' }; const lengths = Math.ceil(distance/poolLength); const finalDistance = distance-(lengths-1)*poolLength; const fmt = (s) => { if (!Number.isFinite(s) || s <= 0) return '—'; const m = Math.floor(s/60); const sec = Math.round(s-m*60); return m+':'+String(sec).padStart(2, '0'); }; const perMeter=total/distance; const perLength=perMeter*poolLength; const finalTarget=perMeter*finalDistance; const startF = strategy === 'fastStart' ? 0.96 : strategy === 'negative' ? 1.02 : 1; const endF = strategy === 'fastStart' ? 1.04 : strategy === 'negative' ? 0.98 : 1; return { perLength: fmt(perLength), per100: fmt(perMeter*100), lengths, firstLength: fmt(perMeter*Math.min(distance,poolLength)*startF), lastLength: fmt(finalTarget*endF) };",
    "inputs": [
      {
        "name": "distance",
        "type": "number",
        "default": 400,
        "min": 25,
        "max": 10000,
        "step": 25,
        "slider": true
      },
      {
        "name": "minutes",
        "type": "number",
        "default": 6,
        "min": 0,
        "max": 300,
        "step": 1,
        "slider": true
      },
      {
        "name": "seconds",
        "type": "number",
        "default": 0,
        "min": 0,
        "max": 59,
        "step": 1,
        "slider": true
      },
      {
        "name": "poolLength",
        "type": "number",
        "default": 25,
        "min": 25,
        "max": 50,
        "step": 25
      },
      {
        "name": "strategy",
        "type": "select",
        "default": "even",
        "options": [
          {
            "value": "even"
          },
          {
            "value": "negative"
          },
          {
            "value": "fastStart"
          }
        ]
      }
    ],
    "outputs": [
      {
        "name": "perLength",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "per100",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "lengths",
        "precision": 0,
        "unit": ""
      },
      {
        "name": "firstLength",
        "precision": 0,
        "unit": "",
        "type": "text"
      },
      {
        "name": "lastLength",
        "precision": 0,
        "unit": "",
        "type": "text"
      }
    ],
    "interpret": null
  }
}
