{
  "schemaVersion": 1,
  "slug": "projectile-motion-calculator",
  "category": "science",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "0d26dd3eebf8ad3a6236a927edb44effcd522b2e8ac2508cad34f5959a3ed0a0",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/projectile-motion-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 = v cosθ × (v sinθ + √(v² sin²θ + 2gh₀)) ÷ g; t = (v sinθ + √(v² sin²θ + 2gh₀)) ÷ g",
    "vars": [
      [
        "v",
        "Launch speed"
      ],
      [
        "θ",
        "Launch angle (°)"
      ],
      [
        "h₀",
        "Initial height"
      ],
      [
        "g",
        "Gravity"
      ],
      [
        "t",
        "Flight time"
      ],
      [
        "R",
        "Horizontal range"
      ]
    ],
    "note": "Assumes ideal projectile motion with constant gravity, no air resistance, and level landing surface except for entered launch height. At zero launch speed, an optimal-angle result is undefined."
  },
  "externalEvidence": {
    "reviewedAt": "2026-10-04",
    "sources": [
      {
        "name": "OpenStax — Projectile motion",
        "url": "https://openstax.org/books/university-physics-volume-1/pages/4-3-projectile-motion"
      }
    ],
    "basis": "The page resolves launch speed into horizontal and vertical components and solves height + vertical velocity × time − gravity × time² / 2 = 0 for landing time.",
    "limitations": "Assumes constant gravity, a ground-level landing plane and no air resistance. Launch height is above the landing plane. Gravity is clamped to at least 0.1 m/s² by this implementation.",
    "implementationHash": "0d26dd3eebf8ad3a6236a927edb44effcd522b2e8ac2508cad34f5959a3ed0a0"
  },
  "contract": {
    "compute": "const rad = angle*Math.PI/180; const g = Math.max(0.1, gravity); const vx = velocity*Math.cos(rad); const vy = velocity*Math.sin(rad); const apexT = vy/g; const maxH = height + vy*vy/(2*g); const disc = vy*vy + 2*g*height; const flight = (vy + Math.sqrt(Math.max(0, disc)))/g; const range = vx*flight; const vImpactY = -Math.sqrt(Math.max(0, disc)); const vImpact = Math.sqrt(vx*vx + vImpactY*vImpactY); const optimal = velocity===0 ? null : height > 0 ? Math.asin(1/Math.sqrt(2 + 2*g*height/(velocity*velocity || 1)))*180/Math.PI : 45; return { range: range, maxHeight: maxH, flightTime: flight, apexTime: apexT, impactVelocity: vImpact, impactAngle: Math.atan2(-vImpactY, vx || 1)*180/Math.PI, optimalAngle: optimal };",
    "inputs": [
      {
        "name": "velocity",
        "type": "number",
        "default": 25,
        "min": 0,
        "max": 100000,
        "step": 0.1
      },
      {
        "name": "angle",
        "type": "number",
        "default": 45,
        "min": 0,
        "max": 90,
        "step": 0.1,
        "slider": true
      },
      {
        "name": "height",
        "type": "number",
        "default": 0,
        "min": 0,
        "max": 100000,
        "step": 0.1
      },
      {
        "name": "gravity",
        "type": "number",
        "default": 9.81,
        "min": 0.1,
        "max": 100,
        "step": 0.01
      }
    ],
    "outputs": [
      {
        "name": "range",
        "precision": 3,
        "unit": "m"
      },
      {
        "name": "maxHeight",
        "precision": 3,
        "unit": "m"
      },
      {
        "name": "flightTime",
        "precision": 3,
        "unit": "s"
      },
      {
        "name": "apexTime",
        "precision": 3,
        "unit": "s"
      },
      {
        "name": "impactVelocity",
        "precision": 3,
        "unit": "m/s"
      },
      {
        "name": "impactAngle",
        "precision": 2,
        "unit": "degrees"
      },
      {
        "name": "optimalAngle",
        "precision": 1,
        "unit": "degrees",
        "optional": true
      }
    ],
    "interpret": null
  }
}
