@kaliber/math
Version:
Math utilities
195 lines (144 loc) • 5.64 kB
Markdown
# @kaliber/math
A set of useful math functions!
## Motivation
Some math problems are just way easier to reason about if you have access to some higher level abstractions. This library provides some of these abstractions in a clear, consistent API.
## Installation
```
yarn add @kaliber/math
```
## Reference
1. [`lerp`](#lerp)
2. [`unlerp`](#unlerp)
3. [`clamp`](#clamp)
4. [`sequence`](#sequence)
5. [`randomNumberGenerator`](#random-number-generator)
6. [`pseudoRandom`](#pseudo-random)
[Common usecases](#common-usecases)
### `lerp`
`lerp({ start: number, end: number, amount: number, clamp: boolean = false }): number`
Linearly interpolates between points.
| Argument | Type | |
| --- | --- | --- |
| `start` | `Number` | Start of the input range. |
| `end` | `Number` | End of the input range. |
| `input` | `Number` | Value indicating where to interpolate. If you want your result to lie between `start` and `end`, you should provide an input between `0` and `1`. |
| `clamp` | `Boolean` (default is `false`) | Whether to clamp the output value between the `start` and `end` values. |
```js
const rotZ = lerp({ start: -45, end: 45, input: 0.5 })
```
### `unlerp`
`unlerp({ start: number, end: number, input: number, clamp: boolean = false })`
Normalizes a number to a value between 0 and 1, given an input range.
| Argument | Type | |
| --- | --- | --- |
| `start` | `Number` | Start of the input range. |
| `end` | `Number` | End of the input range. |
| `input` | `Number` | The value to normalize. If the given input lies between `start` and `end`, your output value will always be between `0` and `1`. |
| `clamp` | `Boolean` (default is `false`) | Whether to clamp the output value between `0` and `1`. |
```js
const normalizedMouseX = unlerp({ start: 0, end: window.innerWidth, input: mouseX })
```
### `clamp`
`clamp({ min: number, max: number, input: number }) : number`
Constrain a number between two boundary values. The boundary arguments are called `min` and `max` to make them easy to memorize, but swapping them has no consequences.
| Argument | Type | |
| --- | --- | --- |
| `min` | `Number` | First boundary value |
| `max` | `Number` | Second boundary value |
| `input` | `Number` | Number to constrain |
```js
const clamped = clamp({ min: 0, max: 1, input: normalizedMouseX })
```
### `sequence`
`sequence(length: number) : array`
Return an array of `length` consequtive numbers, starting with `0`.
| Argument | Type | |
| --- | --- | --- |
| `length` | `Number` | The length of the sequence |
```js
sequence(10).map(index => {
// ...
})
```
### `randomNumberGenerator`
`randomNumberGenerator(seed: string | number) : function`
Creates a random number generator that deterministically generates a
(seemingly) random number, based on the input `seed`. Will always return the
same sequence of numbers, given the same `seed`. The output values fall between
0 (inclusive) and 1 (exclusive).
| Argument | Type | |
| --- | --- | --- |
| `seed` | `String \| Number` | A string or number |
```js
const random = randomNumberGenerator('hello world')
```
### `pseudoRandom`
`pseudoRandom(seed: string | number) : number`
Deterministically generate a (seemingly) random number. Uses
`randomNumberGenerator` internally, based on the input `seed`. Will always
return the same number, given the same `seed`. The output value falls between
0 (inclusive) and 1 (exclusive).
The seed is salted, to make sure the first value returned by a
`randomNumberGenerator` generator is different, given the same seed.
| Argument | Type | |
| --- | --- | --- |
| `seed` | `String \| Number` | A string or number |
```js
const seeminglyRandomNumber = pseudoRandom('hello world')
```
## Common usecases
### `lerp` & `unlerp`
`lerp` and `unlerp` are exact opposites. This fact can help you build some intuition around them:
```js
lerp({ start: 0, end: 10, input: 0.7 }) === 7
unlerp({ start: 0, end: 10, input: 7 }) === 0.7
lerp({ start: a, end: b, input: c }) === d
unlerp({ start: a, end: b, input: d }) === c
```
They are often applied in tandem to remap values:
```js
// Input
const normalizedMouseX = unlerp({ start: 0, end: window.innerWidth, input: mouseX })
// Output
const rotZ = lerp({ start: -20, end: 20, input: normalizedMouseX })
// Apply output
element.style.transform = `rotateZ(${rotZ}deg)`
```
### `lerp`
`lerp` in itself is very useful if you have a library that returns normalized values (values between `0` and `1`). You can use `lerp` to map these values to other useful values. For instance:
```js
const { ref: viewportPositionRef } = useNormalizedPositionInViewport({
startViewportPercentage: 0,
endViewportPercentage: 50,
onChange(n) {
setSpring({
opacity: lerp({ start: 0, end: 1, input: n }),
clip: lerp({ start: 50, end: 100, input: n })
})
}
})
```
### `sequence`
`sequence` is often useful in React if you want to render `n` items, but your starting point is a number:
```js
const amountOfItems = 5
return (
<ul>
{sequence(amountOfItems).map(i => (
<li>Item {i + 1}</li>
))}
</ul>
)
```
### `pseudoRandom`
Sometimes you want elements to appear random, but they shouldn't really change. In this case, you can use a pseudo random number. Returns a number between `0` and `1`, including `0` but excluding `1`.
```js
<div>
{items.map(x => <Item rotation={lerp(-10, 10, pseudoRandom(x.id))} />)}
</div>
```
-----

## Disclaimer
This library is intended for internal use, we provide __no__ support, use at your own risk.
This library is not transpiled.