Come on! Feel the noise! Part 1
Perlin noise is an incredibly powerful tool in creative coding. However, I often hear beginners say, "I don't know where to start" or "It's too difficult to grasp."
This article is specifically for beginners who want to master the noise() function. I’ll break down its core features and provide practical code examples to get you started.
Let’s dive into the world of organic, generative patterns together!
Note:
I only explain the 'noise()' function in Processing and p5.js.
The example codes in this article are written in Processing. And I linked to the OpenProcessing for codes of the p5.js versions. Most code snippets in this article are released under the CC0 license, but please note that the featured artworks (full examples) are licensed under the GPL. Feel free to use the snippets for learning, but respect the GPL for the larger works.
What is Noise? Randomness, but Smooth.
In a nutshell, noise() produces "smoothly transitioning random values."
You’ve likely used the random() function before. For instance, creating a graph with random() looks something like this:
float y = random(height);
Now, if we switch to noise(), the graph transforms into this:
Look how smooth that is! 😲
The difference is even more striking with color. Here is a field of random colors:
It looks chaotic and disjointed. But with noise:
Notice the natural transitions? I didn't add any gradient functions; I simply replaced random() with noise().
Let’s examine the code behind the graph above.
/**
* Come on! Feel the noise! Part 1
* random/noise graph
*
* @author @deconbatch
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* Processing 3.5.3
* 2020.10.31
*/
void setup() {
size(640, 480);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
noLoop();
background(0.0, 0.0, 90.0, 100.0);
noFill();
stroke(0.0, 0.0, 0.0, 100.0);
strokeWeight(2.0);
}
void draw() {
int div = 50;
beginShape();
for (int i = 0; i < div; i++) {
float x = i * width / div;
// float y = random(height);
float y = noise(i * 0.05) * height;
vertex(x, y);
ellipse(x, y, 10.0, 10.0);
}
endShape();
}
View the p5.js version on OpenProcessing
The key difference lies here:
// float y = random(height);
float y = noise(i * 0.05) * height;
The commented random(height) returns a value from 0 up to 'height'.
And noise(i * 0.05) returns a value between 0 and 1, then scaled by 'height'.
Understanding the Parameter: What does 'i * 0.05' do?
You might be wondering about that multiplication. 😌
The noise() function always returns a value between 0 and 1, regardless of the input. If we simply write:
float y = noise(height);
The result is like this.
Oops!😣 'noise()' returns the value between 0 to 1. So 0 < y < 1. Let's multiply by 100. Then 0 < y < 100.
float y = noise(height) * 100.0;
It looks like a flat line. This is because noise() has two fundamental rules:
- It always returns a value between 0 and 1.
- The same input parameter always yields the same output value (within the same execution).
To create a curve, we need to increment the parameter gradually. That’s why we use i * 0.05.
float y = noise(i * 0.05) * 100.0;
Wait—if you run the code again.
You'll get a different result! 😳
I said 'noise() returns the same value for the same parameter value' before. It is only in the same execution of Processing / p5.js. While noise() is consistent within a single run, Processing/p5.js generates a new "noise seed" every time you start the program, giving you a fresh set of values.
Adjusting the "Frequency" of Noise
The smoothness of the curve depends entirely on the rate of change of your input parameter.
For example:
float y = noise(i * 0.05) * 100.0;
If we decrease the rate (the frequency):
float y = noise(i * 0.005) * 100.0;
The result is incredibly smooth, almost like a gentle hill.
If we increase the rate:
float y = noise(i * 0.5) * 100.0;
It becomes jagged and rough, starting to look more like random() again.
Rule of Thumb:
For natural-looking curves, start with a rate between 0.005 and 0.1 and tune it until it looks right for your project.
Symmetry and Absolute Values
Since noise() is based on a coordinate system, it actually returns the same value for the same absolute value of a parameter. This is a handy trick for creating symmetrical shapes.
/**
* Come on! Feel the noise! Part 1
* With the same parameter absolute value.
*
* @author @deconbatch
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* Processing 3.5.3
* 2020.10.31
*/
void setup() {
size(640, 480);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
noLoop();
background(0.0, 0.0, 90.0, 100.0);
stroke(0.0, 0.0, 0.0, 100.0);
strokeWeight(1.0);
}
void draw() {
int div = 50;
float w = width * 0.5 / div;
float h = height * 0.5 / div;
translate(width * 0.5, height * 0.5);
for (int i = -div; i < div; i++) {
for (int j = -div; j < div; j++) {
float x = i * w;
float y = j * h;
fill(noise(i * j * 0.01) * 360.0, 80.0, 90.0, 100.0);
rect(x, y, w, h);
}
}
}
View the p5.js version on OpenProcessing
Putting some flavor.
The Dimension of the Parameter
It is how to use rather than a feature.
As you see in the reference of Processing / p5.js, 'noise()' takes one, two, and three parameters.
noise() \ Language (API) \ Processing 3+
noise() | reference | p5.js
We call the 'noise()' with one parameter as '1D noise'. Two as '2D noise', three as '3D noise'.
// one, two, and three parameters.
noise(x) // 1D noise
noise(x, y) // 2D noise
noise(x, y, z) // 3D noise
We have used 1D noise so far.
The feature of 'noise()' described before is the same in 1D, 2D, and 3D noise.
Let's write a code like this with 2D noise:
/**
* Come on! Feel the noise! Part 1
* Let's observe 2D noise in the line graph.
*
* @author @deconbatch
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* Processing 3.5.3
* 2020.10.31
*/
void setup() {
size(640, 320);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
noLoop();
background(0.0, 0.0, 90.0, 100.0);
noFill();
stroke(0.0, 0.0, 0.0, 100.0);
strokeWeight(2.0);
}
void draw() {
int divX = 50;
int divY = 5;
float w = width / divX;
float h = height / divY;
for (int j = 0; j < divY; j++) {
beginShape();
for (int i = 0; i < divX; i++) {
float x = i * w;
float y = noise(i, j) * 100 + j * h;
vertex(x, y);
}
endShape();
}
}
View the p5.js version on OpenProcessing
Here is the 2D noise.
float y = noise(i, j) * 100 + j * h;
The result is like this:
It is a little bit rough. Let's reduce the change rate value of the x-axis.
float y = noise(i * 0.1, j) * 100 + j * h;
This smoothed out the curve along the x-axis.
Then, what happens when we reduce the change rate value of the y-axis?
float y = noise(i, j * 0.1) * 100 + j * h;
You can see these lines are similar in shape to each other.
If we set the change rate value of the y-axis to zero (no change).
float y = noise(i, j * 0.0) * 100 + j * h;
Now, all lines are the same shape. It means 'noise(i, no change parameter)' run as 1D noise.
Taking it Further: 2D Noise
While 1D noise is great for graphs, 2D noise is where the real magic happens. By passing two parameters—usually x and y—we can create textures that change smoothly in every direction.
/**
* Come on! Feel the noise! Part 1
* THIS IS THE 2D NOISE!
*
* @author @deconbatch
* @version 0.1
* @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
* Processing 3.5.3
* 2020.10.31
*/
void setup() {
size(640, 480);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
noLoop();
background(0.0, 0.0, 90.0, 100.0);
fill(220.0, 90.0, 60.0, 100.0);
stroke(40.0, 60.0, 90.0, 100.0);
strokeWeight(5.0);
}
void draw() {
int divX = 16;
int divY = 12;
float w = width / divX;
float h = height / divY;
for (int i = 0; i < divX; i++) {
float x = i * w;
for (int j = 0; j < divY; j++) {
float y = j * h;
float s = noise(x * 0.005, y * 0.005);
rect(x, y, s * w, s * h);
}
}
}
View the p5.js version on OpenProcessing
I applied the 2D noise to the rectangle size. You can see these size change smoothly from left to right and top to bottom.
In this 2D noise,
noise(x * 0.005, y * 0.005)
When the 'x' value remains constant, the sizes along the y-axis transition smoothly.

And when the 'y' value remains constant, the sizes along the x-axis transition smoothly.

So, every rectangle's neighbors have a little bit of difference.

As above, when we treat 2D noise's parameter as x-axis and y-axis, we get smoothly changing random value even if we moves vertical, horizontal, and slantingly.
This is the 2D noise!
We can apply to the colors.

Even further:

And you may have seen this before.

I like to call certain 2D noise patterns "Leg Hair" (or more politely, a Hairy Map) 🤣 because of how the spiky lines emerge when the parameters are scaled a certain way.

Beyond "leg hair," this leads to a powerful concept called a Vector Field or Noise Field.
Check out my Vector Field gallery here.
If it's your first time to use 'noise()', it's good to make some graph with 1D noise.

These are the graphs with many vertical lines with 1D noise.



You can enjoy tunning the change rate value of the parameter. It will show us different faces with the same code as above.
Some Example Works.
Note: This code does not display any images on the screen but generates image files in frames directory.
Sorry, it's Processing code only.
/**
* Behind Closed Doors.
* It creates still images with noise().
*
* @author @deconbatch
* @version 0.1
* @license GPL Version 3 http://www.gnu.org/licenses/
* Processing 3.5.3
* 2020.11.23
*/
void setup() {
size(600, 360);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
noLoop();
}
void draw() {
int frmMax = 3;
int len = max(width, height);
float pA = random(0.01, 0.15);
float pB = random(0.01, 0.15);
float baseHue = random(360);
for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {
baseHue += 120.0;
pA += 0.08;
pB += 0.04;
pA %= 0.15;
pB %= 0.15;
pushMatrix();
translate(len * 0.5, len * 0.5);
rotate(HALF_PI * floor(random(4.0)));
translate(-len * 0.5, -len * 0.5);
background(0.0, 0.0, 90.0, 100.0);
noStroke();
for (int x = 0; x < len; x++) {
for (int y = 0; y < len; y++) {
float distLT = dist(x, y, width * 0.2, height * 0.2);
float distRB = dist(x, y, width * 0.8, height * 0.8);
float nHue = noise(x * 0.008, y * 0.008, customNoise(distLT * pA, distRB * pB) * 2.0);
float nBri = noise(x * 0.008, y * 0.008, customNoise(distLT * pA, distRB * pB) * 4.0);
fill((baseHue + nHue * 240.0) % 360.0, 40.0 + nHue * 40.0, 10.0 + nBri * 80.0, 100.0);
rect(x, y, 1.0, 1.0);
}
}
popMatrix();
casing();
saveFrame("frames/" + String.format("%04d", frmCnt + 1) + ".png");
}
exit();
}
/**
* customNoise : custom noise function
*/
float customNoise(float _a, float _b) {
return sin(_a) - cos(_b);
}
/**
* casing : draw fancy casing
*/
public void casing() {
fill(0.0, 0.0, 0.0, 0.0);
strokeWeight(50.0);
stroke(0.0, 0.0, 30.0, 100.0);
rect(0.0, 0.0, width, height);
strokeWeight(42.0);
stroke(0.0, 0.0, 100.0, 100.0);
rect(0.0, 0.0, width, height);
}
/*
Copyright (C) 2020- deconbatch
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
And these tweet of mine are various example works with 'noise()'. Please use it as reference.
2D ノイズで色相、彩度、明度を変化させた作例。🎨#p5js #creativecoding pic.twitter.com/jWVzPgvr8z
— deconbatch (@deconbatch) October 30, 2020
Summary
noise()always returns a value between 0 and 1.- Inputting the same absolute value yields the same output.
- Values transition smoothly as input parameters change.
- Smoothness is controlled by the "step size" (rate of change) of the input.
Stay Tuned!
Stay tuned for Part 2, where we'll explore 3D noise and animation!
In part 2 of this article, we'll challenge to make an animation.
Thank you for reading! Please enjoy your creative coding with noise()!




















