primitive

simplex noise

Sampling canvas-sketch-util's simplex noise at UV coordinates scaled by a frequency, with an amplitude multiplier, extended to a third argument (time) to animate it.

Also called: noise2D · noise3D · Simplex noise · Simplex

Run it

Sampling a 2D simplex field simplex skew · frequency vs amplitude · sampling resolution
What it looks like when it goes wrong (4)
  • The signal is still continuous — simplex noise is smooth by construction at every frequency. What breaks is the SAMPLING: once one cell spans more than about half a period, neighbouring samples land on unrelated parts of the wave and the field reads as static. Nothing is wrong with the noise; the grid is too coarse for it. Raise the resolution and the smoothness comes back.
  • The field looks washed out but the structure is identical — same blobs, same positions, less contrast. Frequency changes what the field IS; amplitude only changes how far the output swings. They are not two dials for busyness, and reaching for amplitude when you wanted frequency is the most common way to spend an afternoon on the wrong knob.
  • Aliasing. Eight cells cannot represent twenty periods, so the field folds onto itself and shows large smooth blobs that are not in the signal at all. This is the failure that looks most like success — the output is plausible, and it is an artefact of the sampling grid.
  • Scaled to twice what the output can hold, so everything above and below the midtones clips to pure white and pure black. The blobs get harder edges and read as higher contrast, which is why this gets mistaken for a good setting — but the structure inside the light and dark regions is gone, not enhanced. Clipping is destructive and there is no way back from it later in the pipeline.

Clean-room implementation — written from the described algorithm, not from source. Reuse policy

What it is

Simplex noise, in this bundle, isn’t something you build up from primitives — it’s a library call: canvas-sketch-util’s noise2D / noise3D, the aliases this entity is filed under. Give it coordinates — two for noise2D, three for noise3D, and the underlying algorithm generalizes to however many dimensions you need — and it returns a continuous signal that “smoothly varies between -1…1.” That continuity is the whole reason to reach for it instead of Math.random(): feed it two nearby inputs and you get two nearby outputs, which is what makes a field of samples read as terrain or wind instead of static.

How it works

What’s here documents the calling convention, not the internal construction — no grid, no gradient vectors, no simplex-cell subdivision reaches this bundle. For that, go to the primary source linked under Go deeper. As a recipe:

  1. Decide how many coordinates you need. Two (noise2D) for a flat field sampled once; three (noise3D) once one of those coordinates is going to move.
  2. Scale each coordinate by a frequency before it goes in: amplitude * random.noise2D(u * frequency, v * frequency).
  3. Multiply the return value by an amplitude to move it out of the fixed -1..1 range.
  4. To animate the field rather than resample it, leave u/v alone and advance a third argument through amplitude * random.noise3D(u * frequency, v * frequency, time) — the same spatial field then evolves continuously frame to frame instead of jumping between unrelated states.
  5. There’s no noise1D. The workaround given is to call noise2D with the second argument pinned at zero and increment the first argument yourself each step — the worked example is a ball moved with organic, oscillating motion by incrementing its x and reading the return value as y.

Parameters & tuning

Two knobs are tied to a specific effect on the output here. frequency “changes how chaotic the noise signal will be” — push it up and the field wobbles over shorter stretches of u/v; pull it down and you get long, slow swells instead. amplitude only rescales what comes back — it “can be used to scale the value to something smaller or larger than -1..1 range” — it doesn’t touch the shape of the field at all, only how far it swings.

Past that, nothing in the bundle specifies a breaking point: no numeric extreme where the field degrades toward static, no clipping threshold for either knob. That’s worth stating as a gap rather than guessing at — check it by eye once steps 1–4 above are running.

Where it’s been used

What’s on record here is two teaching contexts, not a named artwork crediting its use: Matt Deslauriers’ workshop cheat sheet, which gives the canvas-sketch-util calling convention directly, and Varun Vachhar’s practical-js post at varun.ca, source of the “no noise1D” workaround and the dimension-generalization note. Treat “used simplex noise” as unremarkable on its own — most canvas-sketch work does — until a source says something more specific than that.

Variants & neighbours

Worley noise is a genuinely different construction, not a retuning of this one: instead of interpolating a smooth field, it shades every point by its distance to the nearest of a set of scattered feature points, which is what gives it a cellular, tessellated look rather than a continuous wave.

mapRange solves a different problem entirely — it takes a number you already have and rescales it into a new range via inverseLerp+lerp. Simplex noise generates the number in the first place; the amplitude step above is doing, informally, what mapRange would do more explicitly. That’s presumably why the two end up contrasted with each other in this graph rather than left unrelated.

Perlin noise is the one this page most needs to get right, and the bundle only gets it partway there. What’s supported: the same source treats Perlin noise as the earlier of the two flavours (built, per that entry’s own record, for Tron’s CG effects) and simplex as what came after — “he then improved on it with Simplex noise and made it a bit faster.” This project’s own graph already keeps the two as contrast-with, not variant-of — they are not the same construction with one setting changed. What the excerpts don’t give is why: no grid shape, no argument about cost scaling with dimension count reaches this bundle. That’s a real gap, not a place to reach for what’s generally believed about simplicial versus hypercubic lattices — the mechanism itself has to come from the linked entry or the primary source, not from here.

Go deeper

Connected to

Variant of: Perlin noise

Used to build: Seamless noise loop


Revision 1 · 2 sources · Something wrong? Tell us.