# formulab

> Industrial & manufacturing calculation library for engineers

[![npm version](https://img.shields.io/npm/v/formulab.svg)](https://www.npmjs.com/package/formulab)
[![CI](https://github.com/iyulab/formulab/actions/workflows/ci.yml/badge.svg)](https://github.com/iyulab/formulab/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)

A comprehensive collection of engineering formulas and calculations for manufacturing, quality control, logistics, and industrial applications. Zero dependencies, fully typed, tree-shakeable.

## Features

- **203 industrial calculations + 8 type guards** — OEE, Cpk, SPC control charts, Gage R&R, Weibull, metal weight, CNC machining, GD&T, pipe flow, CBM, NIOSH lifting, PMV/PPD, arc flash, battery SOH, GHG emissions, PID tuning, and more
- **15 specialized domains** — Quality, Metal, Chemical, Electronics, Construction, Automotive, Logistics, Energy, Safety, Food, Utility, Battery, Environmental, Machining, Industrial Engineering
- **Zero dependencies** — Lightweight and fast
- **TypeScript first** — Full type definitions included
- **Tree-shakeable** — Import only what you need
- **3,042 tests** — Coverage thresholds: 90% lines, 95% functions, 85% branches ([CI pipeline](https://github.com/iyulab/formulab/actions/workflows/ci.yml))
- **Research-based** — Golden reference tests verified against NIOSH 94-110, AIAG/ASTM E2587, JIPM, ASME B16.5, ISO 22514-2, and more

## Verification Status

> **Functions** counts primary calculation functions only — type guards (8 total, listed
> separately above) and helper accessor/lookup functions (`getX`) and exported constants
> (`ALL_CAPS`) are not counted here. Verified against the codebase by
> `pnpm check:function-counts` (`scripts/count-functions.mjs`).

| Domain | Functions | Golden Tests | Key References |
|--------|-----------|-------------|----------------|
| Quality | 21 | oee, cpk, controlChart, gageRR | ISO 22400-2, AIAG/ASTM E2587, JIPM, AIAG MSA |
| Metal | 32 | metalWeight, flangeSpec, pipeSpec, pressFit, spring, weldStrength, tolerance, welding | Machinery's Handbook, ASME B36.10/B16.5, ISO 286, AWS A5 series |
| Logistics | 17 | cbm | Physical formula |
| Safety | 14 | nioshLifting | NIOSH 94-110, ISO 7730, IEEE 1584, OSHA |
| Chemical | 12 | pid, reliefValve | Darcy-Weisbach, Fourier, API 520, ISA |
| Electronics | 11 | awgProperties, resistorDecode | IPC-2221, IEC 60062 |
| Construction | 13 | momentOfInertia | AISC, Timoshenko, Roark's (momentOfInertia only — see note) |
| Automotive | 9 | chargingLoss | AASHTO, SAE J1772 |
| Energy | 15 | degreeDay, windOutput | NREL PVWatts, ISO 50001 |
| Food | 6 | waterActivity, stabilityStudy | HACCP, ICH Q1A |
| Utility | 16 | — | — |
| Battery | 10 | stateOfHealth, thermalRunaway | IEEE 1188, IEC 62620, Battery University |
| Environmental | 10 | gwpCalculator | GHG Protocol, IPCC AR6, IEA 2023 |
| Machining | 12 | all 12 functions — truePosition, gaugeBlockStack, boltCircle, sineBarHeight, effectiveDiameter, radialChipThinning, cuspHeight, boringBarDeflection, toolDeflection, cycleTimeEstimator, threadOverWires, triangleSolver | Machinery's Handbook, ASME Y14.5/B1.2, Sandvik Coromant |
| IE | 5 | — | MTM/MOST, Wright's learning curve |

> Functions with golden reference tests have been verified against authoritative engineering sources.
> See each function's JSDoc for specific references.
>
> **Construction note**: only `momentOfInertia()` cites AISC/Timoshenko/Roark's directly; the
> domain's other 14 functions are self-evident geometry/statics (no external standard needed) or
> already carry their own "convention, not a code limit" disclosure (`concreteMix`, `stair`) —
> the "Key References" column above described the whole domain, not each function.

## Numerical Accuracy & Testing

### Floating-Point Handling

All calculations use a sign-aware `roundTo()` utility with epsilon correction to avoid IEEE 754 rounding artifacts:

```typescript
roundTo(0.615, 2)   // → 0.62  (not 0.61)
roundTo(-2.555, 2)  // → -2.56 (sign-aware)
```

Non-finite values (`NaN`, `Infinity`) pass through unchanged. All validation errors throw `RangeError` — no function returns NaN or Infinity for invalid inputs. Each function's JSDoc specifies output precision (typically 2-4 decimal places) and `@throws` conditions.

### Golden Reference Tests

The following functions include tests verified against published reference values:

| Function | Standard / Source | What is verified |
|----------|-------------------|------------------|
| `nioshLifting()` | NIOSH Publication 94-110 | LC=23kg ideal, FM/CM table values, RWL calculation |
| `oee()` | JIPM TPM Handbook | World-class OEE (A≥90%, P≥95%, Q≥99.9%), perfect 100% |
| `cpk()` | ISO 22514-2 | Six Sigma Cpk=2.0, minimum capable Cpk≈1.33, off-center penalty |
| `controlChart()` | AIAG/ASTM E2587-16 | A2, D3, D4, d2 constants for n=2, 3, 5 |
| `cbm()` | Physical formula | 20ft container 33.2m³, 1m³ cube reference |
| `metalWeight()` | Machinery's Handbook | Steel plate density 7.85 g/cm³ |
| `flangeSpec()` | ASME B16.5 | Class 150/300/600 flange dimensions |
| `pipeSpec()` | ASME B36.10 | SCH40/80/160 wall thickness |
| `awgProperties()` | ANSI/AWG | AWG 0-40 diameter, resistance |
| `pressFit()` | Shigley's Mechanical Engineering Design | Same-material solid-shaft interface pressure (39.36 MPa), nu-independence |
| `spring()` | Shigley's Mechanical Engineering Design | Spring rate (Eq. 10-9), Wahl factor (Eq. 10-5), corrected shear stress (Eq. 10-7) |
| `weldStrength()` | AISC 360 ASD / AWS D1.1 | Equal-leg fillet: throat 0.707·leg, allowable shear 0.30·FEXX (E70=144.9 MPa), capacity/utilization |
| `pid()` | Ziegler-Nichols (1942), Cohen-Coon (1953) | Cohen-Coon P/PI/PID gains at r=L/T=0.1 (Kp, Ti, Td, derived Ki/Kd) against the published coefficient table |
| `reliefValve()` | API 520 Part I | Critical-flow coefficient C(k=1.4)=356.06 vs. C(k=1.3), cross-checked via the steam/gas required-area ratio |
| `momentOfInertia()` | Timoshenko / Roark's Formulas for Stress and Strain, 7th Ed. | Closed-form Ix/Iy/Sx/Sy/rx/ry pinned for all 7 shapes, including the T-section and C-channel parallel-axis (component-method) derivations, not just the elementary rectangle/circle cases |
| `truePosition()` | ASME Y14.5-2018 | Diametral true-position formula TP = 2 x radial deviation, MMC bonus tolerance |
| `gaugeBlockStack()` | Mitutoyo Series 516 / DIN EN ISO 3650 catalog composition | The 47-piece set's real 46-block composition (no half-mm series — that belongs only to the 87/88-piece set); regression-pins that a sub-1mm target correctly fails on the 47-piece set |
| `resistorDecode()` | IEC 60062 | Digit/multiplier/tolerance color-band decoding for canonical 4/5/6-band values (e.g. brown-black-red-gold = 1kΩ ±5%); the 6-band temperature-coefficient table's brown/red/blue entries only — see the JSDoc note on the rest |

### Edge Case Handling

Functions validate or handle these boundary conditions:

- **Division by zero**: `cpk()` with zero standard deviation, `oee()` with zero planned time
- **Out-of-range inputs**: `tolerance()` rejects invalid IT grades, `aql()` validates lot sizes
- **Physical impossibility**: `pressFit()` rejects negative interference, `nioshLifting()` clamps multipliers to [0, 1]
- **Extreme values**: `aql()` handles 1M-unit lots, `awgProperties()` covers AWG 0-40

### Optimization Functions — Algorithms & Limitations

Three functions solve NP-hard combinatorial problems using **heuristic** algorithms. They provide good practical results but **do not guarantee optimal solutions**:

| Function | Algorithm | Complexity | Optimality |
|----------|-----------|-----------|-----------|
| `tsp()` | Nearest Neighbor + 2-Opt local search; brute force for n ≤ 10 | O(n²) per NN start, O(n!) exact for n ≤ 10 | **Heuristic** — no approximation ratio guarantee; exact only for n ≤ 10 |
| `pallet3d()` | Bottom-Left-Fill + First Fit Decreasing with AABB collision & stability checks | O(m² × n) where m = placed boxes | **Heuristic** — greedy placement; enforces physical constraints (80% support, weight limit) |
| `cuttingStock()` | First Fit Decreasing (FFD) or Best Fit Decreasing (BFD), user-selectable | O(q²) worst case | **FFD: ≤ 11/9 × OPT + 1** (proven bound); not optimal |

> For mission-critical optimization requiring proven-optimal solutions, use dedicated solvers (e.g., OR-Tools, Gurobi). These functions are designed for quick shop-floor estimates.

### CI Pipeline

GitHub Actions runs on every push to `main` and every pull request:

- **Matrix**: Node.js 24, 26
- **Steps**: `pnpm install` → `tsc` (type check) → `vitest run --coverage`
- **Coverage enforcement**: Fails if below thresholds (lines 90%, functions 95%, branches 85%, statements 90%)

```bash
# Run tests locally
pnpm test

# Run with coverage report
pnpm test:coverage
```

## Installation

```bash
npm install formulab
```

```bash
pnpm add formulab
```

## Quick Start

```typescript
import { oee, metalWeight, cbm } from 'formulab';

// Calculate OEE (Overall Equipment Effectiveness)
const result = oee({
  rawData: {
    plannedTime: 480,      // minutes (8 hours)
    runTime: 432,          // minutes (90% availability)
    totalCount: 1000,
    goodCount: 990,        // 99% quality
    idealCycleTime: 0.456, // minutes per piece (95% performance)
  },
});
console.log(result.percentages.oee); // 84.6%

// Calculate metal weight
const weight = metalWeight({
  shape: 'plate',
  materialName: 'steel',
  length: 1000,    // mm
  width: 500,      // mm
  thickness: 10,   // mm
});
console.log(weight.weight); // 39.25 kg

// Calculate CBM (Cubic Meter)
const volume = cbm({
  length: 120,
  width: 80,
  height: 100,
  quantity: 1,
  unit: 'cm',
});
console.log(volume.totalCbm); // 0.96 m³
```

## Domains

### Quality & Production (21 functions)

```typescript
import { oee, cpk, taktTime, dpmo, controlChart, gageRR, weibull } from 'formulab/quality';
```

| Function | Description |
|----------|-------------|
| `oee()` | Overall Equipment Effectiveness |
| `cpk()` | Process Capability Index |
| `controlChart()` | SPC X-bar/R and X-bar/S charts |
| `cycleTime()` | Cycle Time analysis |
| `taktTime()` | Takt Time calculation |
| `aql()` | AQL sampling inspection |
| `downtime()` | Downtime analysis |
| `dpmo()` | Defects Per Million Opportunities |
| `lineBalancing()` | Line balancing optimization |
| `mtbf()` | Mean Time Between Failures |
| `ppk()` | Process Performance Index |
| `ppm()` | Parts Per Million conversion |
| `rpn()` | Risk Priority Number (FMEA) |
| `yieldCalc()` | First Pass Yield / RTY |
| `gageRR()` | Gage R&R (AIAG MSA Average & Range) |
| `cmk()` | Machine capability index Cm/Cmk |
| `weibull()` | Weibull reliability analysis |
| `paretoAnalysis()` | Pareto 80/20 ABC classification |
| `actionPriority()` | AIAG-VDA 2019 Action Priority (AP) matrix — table exported as `AP_TABLE` + `AP_*_BANDS` |
| `cpkToOccurrence()` | Cpk → FMEA occurrence rating mapping |
| `nelsonRules()` | SPC Nelson rules (8 control-chart tests) |

### Metal & Machining (34 functions)

```typescript
import { metalWeight, bendAllowance, cutting, bearing } from 'formulab/metal';
```

| Function | Description |
|----------|-------------|
| `metalWeight()` | Weight calculation for various shapes |
| `bendAllowance()` | Sheet metal bend allowance |
| `springback()` | Sheet metal springback / overbend compensation |
| `flatPattern()` | Flat pattern length calculation |
| `kFactorReverse()` | K-factor reverse engineering |
| `pressTonnage()` | Press brake tonnage |
| `bearing()` | L10 bearing life calculation |
| `bolt()` | Bolt torque and preload |
| `cutting()` | Cutting speed, feed rate, RPM |
| `cuttingStock()` | 1D cutting stock heuristic (FFD/BFD) |
| `gear()` | Gear module calculation |
| `hardness()` | Hardness conversion (HRC, HB, HV) |
| `material()` | Material properties lookup |
| `pressFit()` | Press fit interference |
| `roughness()` | Surface roughness conversion |
| `screw()` | Screw specification |
| `spring()` | Spring design calculation |
| `tap()` | Tap drill size |
| `thread()` | Thread dimensions |
| `tolerance()` | ISO tolerance (IT grades) |
| `fit()` | ISO 286 hole/shaft fit — clearance, interference, fit class |
| `vibration()` | Natural frequency analysis |
| `weldHeat()` | Weld heat input calculation |
| `welding()` | Welding parameters |
| `weldStrength()` | Fillet weld strength / capacity (AISC ASD) |
| `materialGradeConverter()` | ASTM/EN/JIS/GB/KS grade cross-reference |
| `pipeSpec()` | ANSI/ASME pipe dimensions lookup |
| `flangeSpec()` | ASME B16.5 flange dimensions lookup |
| `getKFactor()` | Bolt torque K-factor by lubrication condition |
| `getStandardPitch()` | ISO metric standard thread pitch lookup |
| `getCategories()` | Material category list |
| `getGrades()` | Material grades for a category |
| `getDesignations()` | Screw thread designation list |
| `getMetricSizes()` | Metric thread size list |
| `getUnifiedSizes()` | Unified (UNC/UNF) thread size list |

### Chemical & Process (15 functions)

```typescript
import { dilution, concentration, ph, reactor, pipeFlow, heatTransfer, flowControl, pid } from 'formulab/chemical';
```

| Function | Description |
|----------|-------------|
| `batch()` | Batch scaling calculation |
| `concentration()` | Concentration conversion |
| `dilution()` | Dilution (C1V1 = C2V2) |
| `heatTransfer()` | Conduction/convection/radiation heat transfer |
| `ph()` | pH and buffer calculations |
| `pipeFlow()` | Darcy-Weisbach pipe flow pressure drop |
| `reactor()` | Reactor sizing |
| `shelfLife()` | Shelf life prediction (Arrhenius) |
| `injectionCycle()` | Injection molding cycle time |
| `flowControl()` | Control valve Cv/Kv sizing (ISA/IEC 60534) |
| `reliefValve()` | Safety relief valve sizing (API 520/526) |
| `pid()` | PID controller tuning (Z-N / Cohen-Coon) |

### Electronics & SMT (13 functions)

```typescript
import { traceWidth, solderPaste, resistorDecode, ohmsLaw } from 'formulab/electronics';
```

| Function | Description |
|----------|-------------|
| `ohmsLaw()` | Ohm's Law V/I/R/P calculator |
| `reflowProfile()` | Reflow temperature profile |
| `resistorDecode()` | Resistor color code decoder |
| `smtTakt()` | SMT line takt time |
| `solderPaste()` | Solder paste volume calculation |
| `traceWidth()` | PCB trace width (IPC-2221) |
| `awgProperties()` | AWG wire properties |
| `capacitorDecode()` | Capacitor code decoder |
| `ledResistor()` | LED resistor calculation |
| `stencilAperture()` | Stencil aperture design |
| `viaCurrent()` | Via current capacity |
| `getPasteTypes()` | Available solder paste types |

### Construction (16 functions)

```typescript
import { concreteMix, rebarWeight, slope, stair, momentOfInertia } from 'formulab/construction';
```

| Function | Description |
|----------|-------------|
| `momentOfInertia()` | Section properties (Ix, Sx, rx) for 7 shapes |
| `beamLoad()` | Beam load calculation |
| `concreteMix()` | Concrete mix ratio |
| `earthwork()` | Earthwork volume |
| `formwork()` | Formwork area calculation |
| `rebarWeight()` | Rebar weight by size |
| `slope()` | Slope conversion (%, degree, ratio) |
| `aggregate()` | Aggregate volume calculation |
| `brick()` | Brick quantity estimation |
| `pert()` | PERT schedule analysis |
| `roof()` | Roof calculation |
| `stair()` | Stair dimension calculation |
| `getAggregateDensity()` | Aggregate bulk density lookup |
| `aggregateCoverage()` | Aggregate coverage area from volume and depth |
| `getRebarUnitWeight()` | Rebar unit weight lookup (D10-D51) |

### Automotive (9 functions)

```typescript
import { batteryRuntime, evCharging, torque, brakingDistance, chargingLoss } from 'formulab/automotive';
```

| Function | Description |
|----------|-------------|
| `brakingDistance()` | Stopping distance (AASHTO method) |
| `batteryRuntime()` | Battery capacity/runtime |
| `evCharging()` | EV charging time estimation *(deprecated — use `chargingLoss()`)* |
| `fuelEconomy()` | Fuel economy conversion |
| `gearRatio()` | Gear ratio calculation |
| `tireCompare()` | Tire size comparison |
| `torque()` | Torque conversion |
| `power()` | Power conversion (HP, kW) |
| `chargingLoss()` | EV charging loss/efficiency |

### Logistics & Inventory (17 functions)

```typescript
import { cbm, eoq, safetyStock, kanban, inventoryTurnover, abcAnalysis } from 'formulab/logistics';
```

| Function | Description |
|----------|-------------|
| `abcAnalysis()` | ABC inventory classification by annual value |
| `cbm()` | Cubic meter calculation |
| `containerFit()` | Container capacity estimation |
| `dimWeight()` | Dimensional weight |
| `eoq()` | Economic Order Quantity |
| `fillRate()` | Fill rate calculation |
| `freightClass()` | NMFC freight class |
| `inventoryTurnover()` | Inventory turnover ratio & days of supply |
| `kanban()` | Kanban quantity |
| `loadCapacity()` | Forklift load capacity derating |
| `pallet3d()` | 3D pallet loading heuristic (BLF + FFD) |
| `palletStack()` | Pallet stacking calculation |
| `pickTime()` | Picking time estimation |
| `safetyStock()` | Safety stock calculation |
| `serviceLevel()` | Service level calculation |
| `shipping()` | Shipping cost estimation |
| `tsp()` | TSP heuristic (NN + 2-Opt; exact for n ≤ 10) |

### Energy & Utilities (15 functions)

```typescript
import { powerCost, motorEfficiency, carbonFootprint, solarOutput, boilerEfficiency, heatPump, cusum } from 'formulab/energy';
```

| Function | Description |
|----------|-------------|
| `boilerEfficiency()` | Boiler thermal efficiency (direct method) |
| `carbonFootprint()` | Scope 2 emissions |
| `compressedAirCost()` | Compressed air cost |
| `cusum()` | CUSUM energy anomaly detection |
| `degreeDay()` | Heating/Cooling degree days (HDD/CDD) |
| `heatPump()` | Heat pump COP & Carnot efficiency |
| `insulationRoi()` | Insulation ROI & payback |
| `ledRoi()` | LED lighting retrofit ROI |
| `motorEfficiency()` | Motor upgrade ROI |
| `pfCorrection()` | Power factor correction |
| `powerCost()` | Electricity cost with demand |
| `solarOutput()` | Solar panel output estimation (PVWatts-based) |
| `transformerLoss()` | Transformer loss & efficiency |
| `vfdSavings()` | VFD energy savings |
| `windOutput()` | Wind turbine output with Rayleigh CF |

### Safety & Ergonomics (14 functions)

```typescript
import { nioshLifting, noiseExposure, wbgtCalculate, ventilationRate, thermalComfort, arcFlash, lel } from 'formulab/safety';
```

| Function | Description |
|----------|-------------|
| `arcFlash()` | Arc flash incident energy & PPE (IEEE 1584) |
| `confinedSpace()` | Confined space atmospheric assessment (OSHA) |
| `ergonomicRisk()` | REBA ergonomic risk scoring |
| `fallClearance()` | Fall protection clearance |
| `havsCalculate()` | Hand-arm vibration exposure |
| `illuminance()` | Workplace illuminance (Lumen Method) |
| `ladderAngle()` | Ladder safety angle (OSHA 4:1) |
| `lel()` | Mixed gas LEL (Le Chatelier's rule) |
| `nioshLifting()` | NIOSH lifting equation |
| `noiseExposure()` | TWA/Dose calculation |
| `respiratorCalculate()` | Respirator MUC calculation |
| `thermalComfort()` | PMV/PPD thermal comfort (ISO 7730) |
| `ventilationRate()` | Required ventilation ACH/CFM (ASHRAE/OSHA) |
| `wbgtCalculate()` | WBGT heat stress index |

### Food & HACCP (7 functions)

```typescript
import { calorie, nutrition, haccp, waterActivity, stabilityStudy } from 'formulab/food';
```

| Function | Description |
|----------|-------------|
| `calorie()` | Calorie requirement (BMR/TDEE) |
| `expiry()` | Expiry date calculation |
| `nutrition()` | Nutrition facts calculation |
| `haccp()` | HACCP checklist generation |
| `waterActivity()` | Water activity microbial risk (HACCP) |
| `stabilityStudy()` | Accelerated stability (Arrhenius, ICH Q1A) |
| `getHaccpCategories()` | HACCP hazard category list |

### Utility (18 functions)

```typescript
import { solveAssignment, calculateUnit, statistics, regression, npv } from 'formulab/utility';
```

| Function | Description |
|----------|-------------|
| `solveAssignment()` | Hungarian algorithm optimization |
| `calculateUnit()` | Unit conversion (7 categories) |
| `getUnitCategories()` | Get unit categories |
| `statistics()` | Descriptive statistics (mean, median, stdDev, etc.) |
| `percentile()` | Percentile/quantile calculation |
| `correlation()` | Pearson correlation coefficient |
| `regression()` | Simple linear regression |
| `movingAverage()` | SMA/EMA/WMA moving average |
| `linearInterpolation()` | 1D linear interpolation |
| `bilinearInterpolation()` | 2D bilinear interpolation |
| `roi()` | Return on Investment |
| `npv()` | Net Present Value |
| `depreciation()` | Asset depreciation (SL/DDB/SYD) |
| `lcc()` | Life Cycle Cost analysis |
| `normalize()` | Data normalization (min-max/z-score) |
| `histogram()` | Frequency distribution histogram |
| `weightedScore()` | Weighted scoring model |
| `getUnitsForCategory()` | Unit definitions for a conversion category |

### Battery (11 functions)

```typescript
import { energyDensity, cRate, stateOfHealth, cycleLife } from 'formulab/battery';
```

| Function | Description |
|----------|-------------|
| `energyDensity()` | Wh/kg and Wh/L energy density |
| `cRate()` | C-rate ↔ current/time conversion |
| `stateOfHealth()` | SOH % with degradation status |
| `batteryPackConfig()` | Series/parallel cell configuration |
| `cycleLife()` | Cycle life estimation (chemistry/DOD/temp) |
| `internalResistance()` | DCIR from OCV and load voltage |
| `selfDischarge()` | Self-discharge rate calculation |
| `thermalRunaway()` | Thermal safety margin analysis |
| `bmsBalancing()` | BMS cell balancing time estimation |
| `chargingProfile()` | CC-CV charging profile timing |

### Environmental (10 functions)

```typescript
import { scope1Emissions, scope2Emissions, gwpCalculator, esgSummary } from 'formulab/environmental';
```

| Function | Description |
|----------|-------------|
| `scope1Emissions()` | Fuel combustion direct emissions (6 fuels) |
| `scope2Emissions()` | Purchased electricity emissions (12 regions) |
| `scope3Emissions()` | Supply chain spend-based emissions (8 categories) |
| `vocEmissions()` | VOC emissions with capture/destruction |
| `productCarbonFootprint()` | Product lifecycle carbon footprint |
| `gwpCalculator()` | GWP conversion (8 gases × 3 time horizons) |
| `energyIntensity()` | Energy intensity (MJ/unit, kWh/unit) |
| `waterFootprint()` | Water footprint (blue/green/grey) |
| `emissionsIntensity()` | Emissions intensity per unit/revenue/employee |
| `esgSummary()` | ESG reduction tracking and projections |

### Machining & CNC (12 functions)

```typescript
import { truePosition, boltCircle, toolDeflection, threadOverWires } from 'formulab/machining';
```

| Function | Description |
|----------|-------------|
| `truePosition()` | GD&T True Position (diametral, MMC bonus) |
| `boltCircle()` | Bolt hole pattern coordinates |
| `sineBarHeight()` | Sine bar gauge block height |
| `radialChipThinning()` | Chip load compensation for light radial cuts |
| `toolDeflection()` | End mill cantilever deflection |
| `cuspHeight()` | Ball mill scallop height |
| `effectiveDiameter()` | Ball mill effective cutting diameter |
| `boringBarDeflection()` | Boring bar deflection with L/D guidance |
| `threadOverWires()` | 3-wire thread measurement |
| `gaugeBlockStack()` | Gauge block combination (47/88/81-pc sets) |
| `triangleSolver()` | Triangle solver (SSS/SAS/ASA/SSA) |
| `cycleTimeEstimator()` | CNC cycle time estimation |

### Industrial Engineering (5 functions)

```typescript
import { standardTime, timeStudy, workSampling, learningCurve } from 'formulab/ie';
```

| Function | Description |
|----------|-------------|
| `standardTime()` | Standard time from normal time + allowances |
| `timeStudy()` | Time study observation analysis (rating, normal/standard time) |
| `workSampling()` | Work sampling ratio and required observations |
| `vaAnalysis()` | Value-added / non-value-added activity analysis |
| `learningCurve()` | Wright's learning curve (time per unit, cumulative) |

## API Examples

### OEE Calculation

```typescript
import { oee } from 'formulab/quality';

const result = oee({
  rawData: {
    plannedTime: 480,      // minutes
    runTime: 420,          // actual running time
    totalCount: 1000,      // total pieces produced
    goodCount: 990,        // good pieces
    idealCycleTime: 0.4,   // minutes per piece
  },
});

console.log(result);
// {
//   factors: { availability: 0.875, performance: 0.952, quality: 0.99, oee: 0.825 },
//   percentages: { availability: 87.5, performance: 95.2, quality: 99, oee: 82.5 }
// }
```

### NIOSH Lifting Equation

```typescript
import { nioshLifting } from 'formulab/safety';

const result = nioshLifting({
  loadWeight: 23,           // kg
  horizontalDistance: 25,   // cm
  verticalDistance: 75,     // cm (height at lift origin)
  verticalTravel: 25,       // cm (vertical travel distance)
  asymmetryAngle: 0,        // degrees
  coupling: 'good',         // 'good' | 'fair' | 'poor'
  frequency: 1,             // lifts per minute
  duration: 'short',        // 'short' | 'medium' | 'long'
});

console.log(result);
// {
//   rwl: 21.62,             // Recommended Weight Limit (kg)
//   liftingIndex: 1.06,     // LI = Load / RWL
//   riskLevel: 'moderate',
//   hm: 1.0, vm: 1.0, dm: 1.0, am: 1.0, fm: 0.94, cm: 1.0
// }
```

### Dimensional Weight

```typescript
import { dimWeight } from 'formulab/logistics';

const result = dimWeight({
  length: 60,
  width: 40,
  height: 30,
  unit: 'cm',
  carrier: 'international',
});

console.log(result);
// {
//   dimWeight: 14.4,
//   actualVolume: 0.072,
//   cbm: 0.072,
// }
```

## Type Guards for Discriminated Unions

formulab provides runtime type guard functions for all [discriminated union](https://www.typescriptlang.org/docs/handbook/2/narrowing.html#discriminated-unions) input types. These enable type-safe integration when working with dynamic data (e.g., form inputs, API responses):

```typescript
import { isCRateInput, cRate } from 'formulab/battery';

// Form data from user input (Record<string, unknown>)
const formData: unknown = { mode: 'currentToRate', capacityAh: 100, currentA: 50 };

if (isCRateInput(formData)) {
  const result = cRate(formData); // Type-safe, no 'as any' needed
}
```

### Available Type Guards

| Guard | Domain | Discriminant | Variants |
|-------|--------|-------------|----------|
| `isCRateInput()` | battery | `mode` | currentToRate, rateToCurrent |
| `isDilutionInput()` | chemical | `solveFor` | c1, v1, c2, v2 |
| `isReactorInput()` | chemical | `shape` | cylindrical, spherical |
| `isHeatTransferInput()` | chemical | `mode` | conduction, convection, radiation |
| `isMomentOfInertiaInput()` | construction | `shape` | rectangle, circle, hollowRectangle, hollowCircle, iBeam, tSection, cChannel |
| `isOhmsLawInput()` | electronics | `solveFor` | voltage, current, resistance, power |
| `isMetalWeightInput()` | metal | `shape` | plate, round, pipe, angle |
| `isBoltInput()` | metal | `mode` | torqueToPreload, preloadToTorque |

## Error Handling

See [ERRORS.md](./ERRORS.md) for the complete error behavior specification. Key points:

- **All validation failures** throw `RangeError` with descriptive messages
- **No silent NaN/Infinity** — every function guarantees finite outputs for valid inputs
- Every `@throws` condition is documented in each function's JSDoc

```typescript
import { metalWeight } from 'formulab/metal';

try {
  const result = metalWeight({ shape: 'plate', materialName: 'steel', length: 0, width: 100, thickness: 10 });
} catch (e) {
  if (e instanceof RangeError) {
    console.log(e.message); // "length must be positive"
  }
}
```

## Tree Shaking

Import only what you need to minimize bundle size:

```typescript
// Recommended - domain-specific import
import { oee } from 'formulab/quality';
import { metalWeight } from 'formulab/metal';

// Also works - main entry point (tree-shakeable)
import { oee, metalWeight } from 'formulab';

// Avoid - imports entire module
import * as formulab from 'formulab';
```

## TypeScript Support

Full TypeScript support with detailed type definitions:

```typescript
import type {
  OeeInput,
  OeeResult,
  CpkInput,
  CpkResult,
  MetalWeightInput,
  MetalWeightResult,
} from 'formulab';
```

## Browser Support

formulab works in all modern browsers and Node.js:

- Node.js 18+
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+

## Contributing

Contributions are welcome! Please see our [GitHub repository](https://github.com/iyulab/formulab).

```bash
# Clone the repository
git clone https://github.com/iyulab/formulab.git

# Install dependencies
pnpm install

# Run tests
pnpm test

# Build
pnpm build
```

## License

MIT © [iyulab](https://github.com/iyulab)

---

<p align="center">
  Made with engineering precision by <a href="https://github.com/iyulab">iyulab</a>
</p>
