Calculator

Unit Converter

Convert any unit — length, weight, temperature, area, volume, speed, data, time. Live results for all units.

Developer Reference

Core Algorithm & Standalone Script

Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.

const CATEGORIES = {
    length: {
      label: 'Length',
      units: [
        { key: 'mm',    label: 'Millimeter',  symbol: 'mm',     factor: 0.001 },
        { key: 'cm',    label: 'Centimeter',  symbol: 'cm',     factor: 0.01 },
        { key: 'm',     label: 'Meter',       symbol: 'm',      factor: 1 },
        { key: 'km',    label: 'Kilometer',   symbol: 'km',     factor: 1000 },
        { key: 'in',    label: 'Inch',        symbol: 'in',     factor: 0.0254 },
        { key: 'ft',    label: 'Foot',        symbol: 'ft',     factor: 0.3048 },
        { key: 'yd',    label: 'Yard',        symbol: 'yd',     factor: 0.9144 },
        { key: 'mi',    label: 'Mile',        symbol: 'mi',     factor: 1609.344 },
      ]
    },
    weight: {
      label: 'Weight',
      units: [
        { key: 'mg',    label: 'Milligram',   symbol: 'mg',     factor: 0.000001 },
        { key: 'g',     label: 'Gram',        symbol: 'g',      factor: 0.001 },
        { key: 'kg',    label: 'Kilogram',    symbol: 'kg',     factor: 1 },
        { key: 't',     label: 'Tonne',       symbol: 't',      factor: 1000 },
        { key: 'oz',    label: 'Ounce',       symbol: 'oz',     factor: 0.0283495 },
        { key: 'lb',    label: 'Pound',       symbol: 'lb',     factor: 0.453592 },
        { key: 'st',    label: 'Stone',       symbol: 'st',     factor: 6.35029 },
      ]
    },
    temperature: {
      label: 'Temperature',
      special: true,
      units: [
        { key: 'C', label: 'Celsius',    symbol: '°C' },
        { key: 'F', label: 'Fahrenheit', symbol: '°F' },
        { key: 'K', label: 'Kelvin',     symbol: 'K'  },
      ]
    },
    area: {
      label: 'Area',
      units: [
        { key: 'mm2',  label: 'mm²',       symbol: 'mm²',  factor: 0.000001 },
        { key: 'cm2',  label: 'cm²',       symbol: 'cm²',  factor: 0.0001 },
        { key: 'm2',   label: 'm²',        symbol: 'm²',   factor: 1 },
        { key: 'km2',  label: 'km²',       symbol: 'km²',  factor: 1e6 },
        { key: 'in2',  label: 'inch²',     symbol: 'in²',  factor: 0.00064516 },
        { key: 'ft2',  label: 'foot²',     symbol: 'ft²',  factor: 0.092903 },
        { key: 'ac',   label: 'Acre',      symbol: 'ac',   factor: 4046.86 },
        { key: 'ha',   label: 'Hectare',   symbol: 'ha',   factor: 10000 },
      ]
    },
    volume: {
      label: 'Volume',
      units: [
        { key: 'ml',    label: 'Milliliter', symbol: 'ml',   factor: 0.001 },
        { key: 'L',     label: 'Liter',      symbol: 'L',    factor: 1 },
        { key: 'm3',    label: 'm³',         symbol: 'm³',   factor: 1000 },
        { key: 'tsp',   label: 'Teaspoon',   symbol: 'tsp',  factor: 0.00492892 },
        { key: 'tbsp',  label: 'Tablespoon', symbol: 'tbsp', factor: 0.0147868 },
        { key: 'cup',   label: 'Cup',        symbol: 'cup',  factor: 0.236588 },
        { key: 'pt',    label: 'Pint',       symbol: 'pt',   factor: 0.473176 },
        { key: 'qt',    label: 'Quart',      symbol: 'qt',   factor: 0.946353 },
        { key: 'gal',   label: 'Gallon',     symbol: 'gal',  factor: 3.78541 },
      ]
    },
    speed: {
      label: 'Speed',
      units: [
        { key: 'ms',   label: 'm/s',   symbol: 'm/s',   factor: 1 },
        { key: 'kmh',  label: 'km/h',  symbol: 'km/h',  factor: 0.277778 },
        { key: 'mph',  label: 'mph',   symbol: 'mph',   factor: 0.44704 },
        { key: 'kn',   label: 'Knot',  symbol: 'kn',    factor: 0.514444 },
      ]
    },
    data: {
      label: 'Data',
      units: [
        { key: 'bit',  label: 'Bit',      symbol: 'bit', factor: 1 },
        { key: 'B',    label: 'Byte',     symbol: 'B',   factor: 8 },
        { key: 'KB',   label: 'Kilobyte', symbol: 'KB',  factor: 8192 },
        { key: 'MB',   label: 'Megabyte', symbol: 'MB',  factor: 8388608 },
        { key: 'GB',   label: 'Gigabyte', symbol: 'GB',  factor: 8589934592 },
        { key: 'TB',   label: 'Terabyte', symbol: 'TB',  factor: 8796093022208 },
        { key: 'PB',   label: 'Petabyte', symbol: 'PB',  factor: 9007199254740992 },
      ]
    },
    time: {
      label: 'Time',
      units: [
        { key: 'ms',   label: 'Millisecond', symbol: 'ms',   factor: 0.001 },
        { key: 's',    label: 'Second',      symbol: 's',    factor: 1 },
        { key: 'min',  label: 'Minute',      symbol: 'min',  factor: 60 },
        { key: 'hr',   label: 'Hour',        symbol: 'hr',   factor: 3600 },
        { key: 'day',  label: 'Day',         symbol: 'day',  factor: 86400 },
        { key: 'wk',   label: 'Week',        symbol: 'wk',   factor: 604800 },
        { key: 'mo',   label: 'Month',       symbol: 'mo',   factor: 2629746 },
        { key: 'yr',   label: 'Year',        symbol: 'yr',   factor: 31556952 },
      ]
    },
  };

  // Temperature conversions — all via Celsius as pivot
  function toC(val, from) {
    if (from === 'C') return val;
    if (from === 'F') return (val - 32) * 5 / 9;
    if (from === 'K') return val - 273.15;
  }
  function fromC(c, to) {
    if (to === 'C') return c;
    if (to === 'F') return c * 9 / 5 + 32;
    if (to === 'K') return c + 273.15;
  }

  let currentCat = 'length';
  let currentFrom = 'm';

  function buildFromSelect(cat) {
    const sel = document.getElementById('fromUnit');
    sel.innerHTML = CATEGORIES[cat].units.map(u =>
      `<option value="${u.key}">${u.label} (${u.symbol})</option>`
    ).join('');
    // restore previous selection if it exists in new category
    const unit = CATEGORIES[cat].units.find(u => u.key === currentFrom);
    if (unit) sel.value = currentFrom;
    else sel.value = CATEGORIES[cat].units[0].key;
    currentFrom = sel.value;
  }

  function formatNum(n) {
    if (!isFinite(n)) return '—';
    const abs = Math.abs(n);
    if (abs === 0) return '0';
    if (abs >= 1e15) return n.toExponential(4);
    if (abs >= 1000) return +n.toFixed(4) + '';
    if (abs >= 1) return +n.toFixed(6) + '';
    return +n.toPrecision(6) + '';
  }

  function renderResults() {
    const val = parseFloat(document.getElementById('valueInput').value);
    const cat = CATEGORIES[currentCat];
    const fromKey = document.getElementById('fromUnit').value;
    const grid = document.getElementById('resultsGrid');

    if (isNaN(val)) {
      grid.innerHTML = '<div style="color:var(--muted);font-size:13px;">Enter a number to convert.</div>';
      return;
    }

    grid.innerHTML = cat.units.map(u => {
      let result;
      if (cat.special) {
        // temperature
        const pivotC = toC(val, fromKey);
        result = fromC(pivotC, u.key);
      } else {
        const fromUnit = cat.units.find(x => x.key === fromKey);
        const inBase = val * fromUnit.factor;
        result = inBase / u.factor;
      }

      const isFrom = u.key === fromKey;
      const displayVal = formatNum(result);
      return `
        <div class="unit-card ${isFrom ? 'highlighted' : ''}">
          <button class="copy-btn-sm" onclick="copyVal(this, '${displayVal}')">copy</button>
          <div class="unit-name">${u.label}</div>
          <div class="unit-value ${isFrom ? 'accent' : ''}">${displayVal}</div>
          <div class="unit-symbol">${u.symbol}</div>
        </div>
      `;
    }).join('');
  }

  function copyVal(btn, val) {
    navigator.clipboard.writeText(val).then(() => {
      btn.textContent = 'copied!';
      setTimeout(() => btn.textContent = 'copy', 2000);
    });
  }

  document.getElementById('categoryTabs').addEventListener('click', e => {
    const tab = e.target.closest('.tab');
    if (!tab) return;
    document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
    tab.classList.add('active');
    currentCat = tab.dataset.cat;
    buildFromSelect(currentCat);
    renderResults();
  });

  document.getElementById('fromUnit').addEventListener('change', e => {
    currentFrom = e.target.value;
    renderResults();
  });

  document.getElementById('valueInput').addEventListener('input', renderResults);

  // Init
  buildFromSelect(currentCat);
  renderResults();