Noise
The most common and useful approach when procedurally generating anything, is to use noise: randomly generated numbers.
Of course, purely random numbers are kind of useless to us, as we need to be able to test things (i.e.: reproducibility), so we tend to use Pseudorandom Number Generators that take some kind of seed and give us seemingly random numbers in return.
Noise can be used in many, many, many ways, such as...
 Generating textures from scratch
 Generating terrain by interpreting noise as height
 Generating terrain via voxel density volumes
 Creating interesting visual effects
 Enhancing existing textures with graininess;
e.g to make it look old/used/worn.  And so, so, much, more...
Seriously, we couldn't list them, even if we tried!
Noisebased generation generally happens via a noise pipeline, consisting of three parts:
 An initial noise function.
 Any number of noise operations.
 Final noise interpretation.
This is just a basic framework to get the concept across;
it can be changed and extended in a variety of ways once understood.
There are no hard rules... be creative!
Noise Functions
All uses of noise begin with a noise function.
That is, a function taking an ℕdimensional sample position
and returning a noise sample in the [1, +1]
range.
/// An abstract noise function.
///
///  Takes a position.
///  Returns a number.
///  May contain math.
///  A *lot* of math.
fn noise(position: Vecℕ) > f32;
Calling such a function means to sample the noise function.
A note on number ranges:
While most libraries return numbers in the [1, +1]
range, some may use the [0, +1]
range, or something else entirely even; read the documentation, or code, to make sure!
Though conversions are usually rather easy; for example:

To turn
[0, +1]
into[1, +1]
:
Multiply by two and subtract one:v * 2  1

To turn
[1, +1]
into[0, +1]
:
Add one and divide by two:(v + 1) / 2
Mind the parenthesis!
Now with that preface out of the way, let's proceed to the actual noise functions!
White Noise & Value Noise
If you have ever seen a Television that receives it's video as analog signals via an antenna, you might have seen what happens when the antenna isn't receiving anything: The screen becomes a sea of noise; commonly referred to as white noise.
White noise by itself is completely random, with no discernible patterns between/across the samples, which isn't really useful by itself.
However, take that very noise and scale it up/zoom into it, linearly interpolating between the individual samples, and it will begin to resemble something much more interesting: value noise.
Unfortunately, while value noise tends to be ludicrously fast to generate, it's quality isn't particularly great due to linear artifacts. When used for terrain generation, these artifacts will cause strange patterns to emerge, which is absolutely not what one wants, so we will have to find something better than value noise...
Perlin Noise
Now, again, value noise is extremely simple and fast to generate, but unfortunately has linear artifacts... which is where Perlin noise comes in!
Invented in the early 1980s by Ken Perlin, Perlin noise improves on value noise by interpolating between randomly generated gradients on a grid, instead of plain random values.
Explaining the exact algorithm is, (un)fortunately, outofscope for this article; since there are many implementations of it, finding one should not be a problem.
The 'blobby' nature of Perlin already makes it perfect for many use cases, though if one looks closely there appear to be... straight lines? Let's keep going!
Simplex Noise
Now, is Perlin noise perfect? Sadly, no: It too has artifacts, caused by the sampling being done on a regular grid, making values appear to be axisaligned and/or biased on the diagonal.
This is visible in the top left of the previous example image as a straight 'hill'.
If you are interested in the inner workings and actual reasons behind these artifacts, we highly recommend reading KdotJPG's excellent blog post The Perlin Problem: Moving Past Square Noise for more!
Thankfully, Ken Perlin noticed the issue circa 2001 and remedied this by coming up with a new noise function: simplex noise!
The solution is surprisingly simple: Instead of sampling and interpolating the random numbers in a square grid, he used a triangular ('simplex') grid, which has several advantages:
 The artifacts are no longer visible, due to the grid of pixels no longer being aligned with the grid of gradient positions.
 A triangle is the smallest polygon enclosing an area of two dimensional (or higher) space, so the algorithm only needs to evaluate and interpolate between three corners, instead of four, which is much faster!
 The algorithm can be extended into higher dimensions (3D, 4D, 5D, and higher!), without having to evaluate exponentially more corners, unlike Perlin noise, making it even faster in this case!
Due to patent shenanigans, simplex noise was not possible to freely implement for quite some time, leading to the creation of open simplex noise. Thankfully, the patent has run out, so go forth and code!
With that we have seen enough noise functions... on to noise operations!
Noise Operations
Noise operators are functions that accept noise modules (which are noisefunctions and operators), creating new noise modules from them. This allows for the creation of much more complex/detailed noise.
They are split into these four categories:

Modifiers change the output of a noise module.

Combiners mix the output of several noise modules.

Selectors mix the output of several noise modules,
controlled by another noise module. 
Transformers work with the sample positions going into the modules.
Modifier Operations
Even with just one noise sample, we can do many things... for example:
 Shift it by adding/subtracting
 Multiply it to scale its amplitude
 Put it through a spline or easing function
 Change its slope with
pow(v, …)
 Convert to other number ranges
 etc. etc.
Here is an example of a cubic easing modifier, written in Rust:
// Assuming we already have a noise function...
//  `p` is the *sample position*
//  `v` is the *noise sample*, here in the [1, +1]range
let mut v: f32 = noise(p);
// With help from <https://github.com/prideout/par/blob/master/par_easings.h>,
// let's apply a cubiceasing function to our noise sample!
// This one takes values in the [0, +1]range...
fn ease_cubic(mut t: f32, b: f32, c: f32, d: f32) {
t /= d / 2.0;
if t < 1.0 {
return c / 2.0 * t * t * t + b;
}
t = 2.0;
return c / 2 * (t * t * t + 2) + b;
}
// ...so we first have to convert our sample from [1, +1] to [0, +1]...
v = (v + 1.0) / 2.0;
// ...and then we can apply the function!
v = ease_cubic(v, 0, 1, 1);
You might notice that we did not define what the sample position p
is, or where the result goes... and this is on purpose!
Modifiers are independent of each other, so you can mixandmatch them however you like, there are no limits to your creativity here!
Combiner Operations
Selector Operations
Transformer Operations
Noise Interpretation
Once you've obtained a final value from your noise evaluation, you will need to interpret it.
Usually this means either putting the sample through a transfer function, thresholding it or using it directly asis.
Transfer Function
Thresholding
References
 Terrain from Noise
 3D Cube World Level Generation
 C# Perlin Noise
 Simplex Noise Demystified (PDF)
 Goodbye Perlin noise in 2D, hello Perlin noise in 3D!
 Voxel Terrain
Noise Libraries
Writing correct noisegenerating code can be quite hard, so it is generally recommended to try using a library first...
 libnoise
Great documentation, but quite old, slow and licensed under LGPL, which is a nogo for most projects. Notable because it has the best documentation for organizing/conceptualizing noise primitives and various operations on noise, so it's a good idea to browse through the various modules.  OpenSimplex2
Various improvements over Perlin Noise and under a CC0 license.  FastNoiseLite
Fast noise generation with implementations in several languages, several kinds of noise and a GUI to preview noise.  FastNoise2
Newer version of FastNoiseLite, by the same author, written entirely in C++. One of the, if not the, fastest noise generation libraries.