Mathematical utility functions providing clamping, interpolation, arithmetic operations, and numerical transformations.
Constrain numeric values within specified bounds.
/**
* Clamp a number between minimum and maximum values
* @param n - Number to clamp
* @param min - Minimum allowed value
* @param max - Maximum allowed value
* @returns Number clamped between min and max
*/
function clamp(n: number, min: number, max: number): number;Usage Examples:
import { clamp } from "@antfu/utils";
// Basic clamping
const clamped1 = clamp(15, 0, 10); // 10 (clamped to max)
const clamped2 = clamp(-5, 0, 10); // 0 (clamped to min)
const clamped3 = clamp(5, 0, 10); // 5 (within range)
// UI component bounds
function setOpacity(value: number): number {
return clamp(value, 0, 1); // Ensure opacity is between 0 and 1
}
// Game development
function updatePlayerHealth(currentHealth: number, damage: number, maxHealth: number): number {
const newHealth = currentHealth - damage;
return clamp(newHealth, 0, maxHealth);
}
// Slider/input validation
function handleSliderChange(value: number): void {
const clampedValue = clamp(value, 0, 100);
updateSliderDisplay(clampedValue);
}
// Animation progress
function animationProgress(elapsed: number, duration: number): number {
return clamp(elapsed / duration, 0, 1);
}Enhanced arithmetic operations with support for arrays and multiple inputs.
/**
* Sum numbers or arrays of numbers
* @param args - Numbers or arrays of numbers to sum
* @returns Total sum of all input values
*/
function sum(...args: number[] | number[][]): number;Usage Examples:
import { sum } from "@antfu/utils";
// Sum individual numbers
const total1 = sum(1, 2, 3, 4, 5); // 15
// Sum arrays
const total2 = sum([1, 2], [3, 4], [5]); // 15
// Mixed inputs
const total3 = sum(1, [2, 3], 4, [5, 6]); // 21
// Calculate totals from data
const prices = [10.99, 25.50, 7.25];
const tax = [1.10, 2.55, 0.73];
const total = sum(prices, tax); // 47.12
// Statistical calculations
function calculateAverage(numbers: number[]): number {
return sum(numbers) / numbers.length;
}
// Budget calculation
function calculateBudget(expenses: number[][], income: number[]): number {
const totalExpenses = sum(...expenses);
const totalIncome = sum(income);
return totalIncome - totalExpenses;
}
// Scoring system
const scores = {
math: [85, 92, 78],
science: [90, 88, 95],
english: [82, 85, 89]
};
const totalScore = sum(
scores.math,
scores.science,
scores.english
); // Sum all scores across subjectsSmooth interpolation between values for animations and transitions.
/**
* Linearly interpolates between `min` and `max` based on `t`
* @param min - The minimum value
* @param max - The maximum value
* @param t - The interpolation value clamped between 0 and 1
* @returns Interpolated value between min and max
*/
function lerp(min: number, max: number, t: number): number;Usage Examples:
import { lerp } from "@antfu/utils";
// Basic interpolation
const midpoint = lerp(0, 100, 0.5); // 50
const quarter = lerp(0, 100, 0.25); // 25
const threeQuarters = lerp(0, 100, 0.75); // 75
// Animation easing
function animatePosition(startPos: number, endPos: number, progress: number): number {
return lerp(startPos, endPos, progress);
}
// Color interpolation (single channel)
function interpolateRedChannel(color1: number, color2: number, t: number): number {
return Math.round(lerp(color1, color2, t));
}
// Temperature interpolation
function getTemperatureColor(temp: number, minTemp: number, maxTemp: number): number {
const t = (temp - minTemp) / (maxTemp - minTemp);
const blueToRed = lerp(240, 0, t); // Hue interpolation (blue to red)
return blueToRed;
}
// Game development - health bar
function updateHealthBar(currentHealth: number, maxHealth: number): number {
const healthPercent = currentHealth / maxHealth;
return lerp(0, 100, healthPercent); // Convert to percentage for UI
}
// Audio volume transitions
class VolumeController {
private currentVolume = 1.0;
private targetVolume = 1.0;
fadeTo(target: number, progress: number): void {
this.currentVolume = lerp(this.currentVolume, target, progress);
}
}
// Responsive design calculations
function responsiveSize(screenWidth: number): number {
const minWidth = 320;
const maxWidth = 1920;
const minSize = 14;
const maxSize = 24;
const t = clamp((screenWidth - minWidth) / (maxWidth - minWidth), 0, 1);
return lerp(minSize, maxSize, t);
}Transform values from one range to another range with linear scaling.
/**
* Linearly remaps a clamped value from its source range [`inMin`, `inMax`] to the destination range [`outMin`, `outMax`]
* @param n - Input value to remap
* @param inMin - Minimum of input range
* @param inMax - Maximum of input range
* @param outMin - Minimum of output range
* @param outMax - Maximum of output range
* @returns Value remapped to the output range
*/
function remap(n: number, inMin: number, inMax: number, outMin: number, outMax: number): number;Usage Examples:
import { remap } from "@antfu/utils";
// Basic remapping
const remapped = remap(0.5, 0, 1, 200, 400); // 300 (50% between 200-400)
// Sensor data scaling
function scaleSensorReading(rawValue: number): number {
// Raw sensor: 0-1023, desired output: 0-100
return remap(rawValue, 0, 1023, 0, 100);
}
// UI slider to API value conversion
function sliderToApiValue(sliderValue: number): number {
// UI slider: 0-100, API expects: -50 to +50
return remap(sliderValue, 0, 100, -50, 50);
}
// Temperature unit conversion with scaling
function celsiusToFahrenheitScale(celsius: number, displayMin: number, displayMax: number): number {
// Convert Celsius range to Fahrenheit, then scale to display range
const fahrenheit = celsius * 9/5 + 32;
return remap(fahrenheit, 32, 212, displayMin, displayMax); // Water freezing to boiling
}
// Game development - map coordinates
function worldToScreenX(worldX: number, worldWidth: number, screenWidth: number): number {
return remap(worldX, 0, worldWidth, 0, screenWidth);
}
// Audio processing - frequency to pixel position
function frequencyToPixel(frequency: number, canvasWidth: number): number {
const minFreq = 20; // 20 Hz
const maxFreq = 20000; // 20 kHz
return remap(frequency, minFreq, maxFreq, 0, canvasWidth);
}
// Data visualization - value to chart position
function valueToChartY(value: number, minValue: number, maxValue: number, chartHeight: number): number {
// Note: Y axis is flipped in most graphics systems
return remap(value, minValue, maxValue, chartHeight, 0);
}
// Animation timing curves
function easeInOut(t: number): number {
// Remap linear 0-1 to ease-in-out curve
if (t < 0.5) {
return remap(t, 0, 0.5, 0, 0.5) * 2; // Accelerate
} else {
return remap(t, 0.5, 1, 0.5, 1) * 0.5 + 0.5; // Decelerate
}
}
// Color space conversion
function hueToRGB(hue: number): [number, number, number] {
// Remap hue (0-360) to RGB components (0-255)
const normalizedHue = hue / 360;
const r = Math.round(remap(Math.sin(normalizedHue * Math.PI * 2), -1, 1, 0, 255));
const g = Math.round(remap(Math.sin((normalizedHue + 0.33) * Math.PI * 2), -1, 1, 0, 255));
const b = Math.round(remap(Math.sin((normalizedHue + 0.66) * Math.PI * 2), -1, 1, 0, 255));
return [r, g, b];
}