Uniform
Simplest form of random - every value has an equal probability of being selected. In 1D, this creates an even spread of points along a line. In 2D, it creates an even spread of points across a plane.
Uniform distributions are useful as a baseline for comparison and for generating truly random positions. However, they often look artificial since natural phenomena rarely follow perfectly uniform patterns.
/**
* Generates a random number between the specified minimum and maximum values.
* If only one argument is provided, it is assumed to be the maximum value and the minimum value is set to 0.
*
* @param {number} [min=0] - The minimum value (inclusive). Defaults to 0 if not provided.
* @param {number} [max=1] - The maximum value (exclusive). Defaults to 1 if not provided.
* @returns {number} - A random number between min and max.
*/
function uniform(min = 0, max = 1) {
if (arguments.length === 1) {
// assume the user passed in a max value
max = min
min = 0
}
// Return a random number between min and max
return Math.random() * (max - min) + min
}
// example: create 1000 uniformly random points
// const pts = Array.from({ length: 1000 }, () => [uniform(), uniform()])
Gaussian
Gaussian distribution - mean: 0.5, stdDev: 0.15
Also known as the normal distribution or "bell curve", Gaussian distributions cluster values around a mean (center) value, with decreasing probability as you move away from the mean. The spread of values is controlled by the standard deviation.
Gaussian distributions are extremely common in nature and statistics. They're useful for creating natural-looking clusters, organic patterns, and modeling real-world variation. The central limit theorem states that many random processes tend toward a Gaussian distribution.
In a Gaussian distribution, about 68% of values lie within one standard deviation of the mean, 95% within two, and 99.7% within three — a property known as the empirical rule.
// Function to generate a normally distributed random number
// Note: this throws away the 2nd value and can be optimized through caching
function boxMullerTransform() {
let u = 0,
v = 0
while (u === 0) u = Math.random() // Converting [0,1) to (0,1)
while (v === 0) v = Math.random()
let z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v)
return z
}
/**
* Calculates a random number from a Gaussian distribution.
*
* @param {number} mean - The mean value of the distribution.
* @param {number} stdDev - The standard deviation of the distribution.
* @returns {number} The random number from the Gaussian distribution.
*/
function gaussian(mean, stdDev) {
return mean + stdDev * boxMullerTransform()
}
Pareto
Noise
Should this be included?
Creative Coding Examples
Urban Density
import { Rectangle } from 'root/geo'
import { gaussian, pareto, weightedRandom } from 'root/random'
import { range } from 'root/array'
/* https://www.tylerxhobbs.com/words/probability-distributions-for-algorithmic-artists */
function urbanDensity(cmd, palette) {
const { background, primary, secondary, accent, dark, neutral } = palette
const colors = [primary, secondary, accent, neutral]
// draw random rect (width, heights) according to pareto distribution
const rects = range(2000).map(() => {
const width = pareto(0.008, 1.0)
const height = pareto(0.005, 1.0)
const color = weightedRandom(colors, [3, 3, 2, 1])
return new Rectangle([gaussian(-0.2, 0.4), gaussian(-0.2, 0.5)], [width, height], { fill: color + 'AA' })
})
cmd.clear(background)
cmd.draw(rects)
}
urbanDensity.title = 'Urban Density'
export { urbanDensity }