Last active
May 23, 2021 17:15
-
-
Save somaholiday/ad03c9445ac25046ba66dd74b84915be to your computer and use it in GitHub Desktop.
Seamlessly Looping Art • Code Samples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int rectSize = 100; | |
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
// This will draw a rectangle with a top-left corner where your mouse cursor is. | |
rect(mouseX, mouseY, rectSize, rectSize); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int x = 0; | |
int y = 0; | |
int rectSize = 100; | |
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
// Draw a rectangle that moves 2 pixels right and down each frame. | |
rect(x, y, rectSize, rectSize); | |
x += 2; | |
y += 2; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int x = 0; | |
int y = 0; | |
int rectSize = 100; | |
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
rect(x, y, rectSize, rectSize); | |
x += 2; | |
y += 2; | |
// This is one way to reset if the rectangle goes off-screen. | |
/* | |
if (x > width || y > height) { | |
x = 0; | |
y = 0; | |
} | |
*/ | |
// This is another, more succinct and expressive way. | |
// % is the modulo operator | |
// a % b = the remainder of a / b | |
x = x % width; | |
y = y % height; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int rectSize = 100; | |
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
drawRect(frameCount); | |
} | |
void drawRect(int frameNumber) { | |
int x = (frameNumber * 2) % width; | |
int y = (frameNumber * 2) % height; | |
rect(x, y, rectSize, rectSize); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int rectSize = 100; | |
void setup() { | |
size(500, 500); | |
/* | |
note: if you divide an int by an int, you get an int. | |
*/ | |
int someInteger = 50; | |
// This returns 0, not 0.5! | |
println(someInteger / rectSize); | |
} | |
void draw() { | |
background(0); | |
drawRect(frameCount, 240); | |
} | |
/* | |
note: due to the note above, we are using floats now, rather than ints, because we are working with fractional values | |
*/ | |
void drawRect(float frameNumber, float totalFramesForLoop) { | |
// keep loopFrame always between 0 and totalFramesForLoop | |
float loopFrame = frameNumber % totalFramesForLoop; | |
// calculate percentage of frames passed of totalFramesForLoop | |
float normalizedTime = loopFrame / totalFramesForLoop; | |
float x = normalizedTime * width; | |
float y = normalizedTime * height; | |
rect(x, y, rectSize, rectSize); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int rectSize = 100; | |
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
float normalizedTime = loopNormal(frameCount, 240); | |
drawRect(normalizedTime); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
/* | |
Now our animation function just takes in a value from 0 to 1 | |
*/ | |
void drawRect(float normalizedTime) { | |
float x = normalizedTime * width; | |
float y = normalizedTime * height; | |
rect(x, y, rectSize, rectSize); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
stroke(255); | |
//float normalizedTime = loopNormal(frameCount, 240); | |
drawSine(); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawSine() { | |
float baseY = height * 0.5; | |
float amplitude = 100; | |
// draw X axis | |
push(); | |
stroke(255, 64); | |
line(0, baseY, width, baseY); | |
pop(); | |
for (int x=0; x < width; x++) { | |
// multiply by amplitude to increase height of wave | |
// multiply x by 0.1 to increase wavelength of wave | |
float y = amplitude * sin( x * 0.1 ); | |
point(x, baseY + y); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
stroke(255); | |
float normalizedTime = loopNormal(frameCount, 240); | |
drawSine(normalizedTime); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawSine(float normalizedTime) { | |
float baseY = height * 0.5; | |
float amplitude = 100; | |
// draw X axis | |
push(); | |
stroke(255, 64); | |
line(0, baseY, width, baseY); | |
pop(); | |
float x_offset = normalizedTime * TWO_PI; | |
for (int x=0; x < width; x++) { | |
float y = amplitude * sin( x * 0.1 + x_offset ); | |
point(x, baseY + y); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
stroke(255); | |
float normalizedTime = loopNormal(frameCount, 240); | |
drawCircle(normalizedTime); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawCircle(float normalizedTime) { | |
float x_center = width * 0.5; | |
float y_center = height * 0.5; | |
float diameter = width * sin(normalizedTime * TWO_PI); | |
// note that diameter goes into negative values | |
// (also note that printing lots of values can slow down your sketch) | |
println(diameter); | |
circle(x_center, y_center, diameter); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
} | |
void draw() { | |
background(0); | |
stroke(255); | |
float normalizedTime = loopNormal(frameCount, 240); | |
drawCircle(normalizedTime); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawCircle(float normalizedTime) { | |
float x_center = width * 0.5; | |
float y_center = height * 0.5; | |
// map the output of sin from the range [-1, 1] to [100, 300] | |
float diameter = map(sin(normalizedTime * TWO_PI), -1, 1, 100, 300); | |
circle(x_center, y_center, diameter); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
stroke(255); | |
strokeWeight(2); | |
} | |
void draw() { | |
background(0); | |
// I'm going to start calling normalizedTime "t" | |
float t = loopNormal(frameCount, 60); | |
drawGrid(t); | |
// draw a red circle on top of the grid | |
drawTopCircle(); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawGrid(float t) { | |
int rows = 10; | |
int cols = rows; | |
float distance = width/rows; | |
// draw the vertical lines (note <= rather than < to add last line) | |
for (int i=0; i <= cols; i++) { | |
float x = i * distance; | |
/* | |
Here's where our loop timing comes in. | |
We want the lines to move by (distance) pixels | |
across the duration of the loop. | |
*/ | |
x -= t * distance; | |
line(x, 0, x, height); | |
} | |
// draw the horizontal lines (note <= rather than < to add last line) | |
for (int j=0; j <= rows; j++) { | |
float y = j * distance; | |
/* | |
Here's where our loop timing comes in. | |
We want the lines to move by (distance) pixels | |
across the duration of the loop. | |
*/ | |
y += t * distance; | |
line(0, y, width, y); | |
} | |
} | |
void drawTopCircle() { | |
/* | |
push() and pop() allow us to set styles and then reset them. | |
*/ | |
push(); | |
noStroke(); | |
fill(255, 0, 0); | |
circle(width * 0.5, height * 0.5, 200); | |
/* | |
When we call pop(), the styles will return to what they were | |
at the last time push() was called. | |
*/ | |
pop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
noStroke(); | |
fill(255); | |
} | |
void draw() { | |
background(0); | |
// I'm going to start calling normalizedTime "t" | |
float t = loopNormal(frameCount, 120); | |
drawCircles(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawCircles(float t) { | |
int rows = 5; | |
int cols = rows; | |
float diameter = width/rows; | |
for (int i=0; i < cols; i++) { | |
float x = i * diameter + diameter * 0.5; | |
/* Note that we start from -1 to have an extra row that comes in from the top */ | |
for (int j=-1; j < rows; j++) { | |
float y = j * diameter + diameter * 0.5; | |
/* | |
Here's where our loop timing comes in. | |
We want the circles to move by (diameter) pixels | |
across the duration of the loop. | |
*/ | |
float y_offset = t * diameter; | |
ellipse(x, y + y_offset, diameter, diameter); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
noStroke(); | |
fill(255); | |
} | |
void draw() { | |
background(0); | |
float t = loopNormal(frameCount, 120); | |
drawCircles(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawCircles(float t) { | |
int rows = 10; | |
int cols = rows; | |
float diameter = width/rows; | |
for (int i=0; i < cols; i++) { | |
float x = i * diameter + diameter * 0.5; | |
for (int j=0; j < rows; j++) { | |
float y = j * diameter + diameter * 0.5; | |
// First we decide what should contribute to the offset of the sine wave | |
float sin_offset = x + y; | |
// Then add that offset to a wave that we know will complete one cycle in our loop | |
float sin_value = sin(t * TWO_PI + sin_offset); | |
// Then map the output to the parameter we want to modulate. | |
float draw_diameter = map(sin_value, -1, 1, 0, diameter); | |
ellipse(x, y, draw_diameter, draw_diameter); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
noStroke(); | |
} | |
void draw() { | |
background(0); | |
float t = loopNormal(frameCount, 120); | |
drawRing(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawRing(float t) { | |
int circle_count = 12; | |
float ring_radius = 150; | |
float circle_diameter = 50; | |
// push() and pop() work for translate() too! | |
push(); | |
/* | |
translate() changes the origin of our coordinate system | |
This call has the effect of moving (0, 0) to the center of our sketch | |
*/ | |
translate(width * 0.5, height * 0.5); | |
for (int i=0; i < circle_count; i++) { | |
// distribute the circle number evenly across the range [0, TWO_PI] | |
float angle = map(i, 0, circle_count, 0, TWO_PI); | |
// remember when we looked at that sin/cos visualization? | |
// https://jackschaedler.github.io/circles-sines-signals/sincos.html | |
float x = cos(angle) * ring_radius; | |
float y = sin(angle) * ring_radius; | |
// First we decide what should contribute to the offset of the sine wave | |
float sin_offset = angle; | |
// Then add that offset to a wave that we know will complete one cycle in our loop | |
float sin_value = sin(t * TWO_PI + sin_offset); | |
// Then map the output to the parameter we want to modulate. | |
float draw_diameter = map(sin_value, -1, 1, 0, circle_diameter); | |
circle(x, y, draw_diameter); | |
} | |
// after we call pop(), (0, 0) will move back to the top-left corner | |
pop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
noStroke(); | |
} | |
void draw() { | |
background(255, 0, 0); | |
float t = loopNormal(frameCount, 120); | |
drawFadingCircle(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
void drawFadingCircle(float t) { | |
// use push() and pop() to keep style changes isolated | |
push(); | |
float sin_value = sin(t * TWO_PI); | |
// map the sin value to the range for colors | |
float fill_value = map(sin_value, -1, 1, 0, 255); | |
// set the fill to the mapped color | |
fill(fill_value); | |
circle(width * 0.5, height * 0.5, 200); | |
pop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void setup() { | |
size(500, 500); | |
noStroke(); | |
} | |
void draw() { | |
background(255, 0, 0); | |
float t = loopNormal(frameCount, 120); | |
drawFadingCircle(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
/* | |
We use this so much, it's worth having a utility function for it. | |
*/ | |
float mapsin(float value, float start, float stop) { | |
return map(sin(value), -1, 1, start, stop); | |
} | |
void drawFadingCircle(float t) { | |
// use push() and pop() to keep style changes isolated | |
push(); | |
// map the sin value to the range for colors | |
float fill_value = mapsin(t * TWO_PI, 0, 255); | |
// set the fill to the mapped color | |
fill(fill_value); | |
circle(width * 0.5, height * 0.5, 200); | |
pop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
color red = color(255, 0, 0); | |
color green = color(0, 255, 0); | |
void setup() { | |
size(500, 500); | |
noStroke(); | |
} | |
void draw() { | |
background(0, 0, 255); | |
float t = loopNormal(frameCount, 120); | |
drawFadingCircle(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
/* | |
We use this so much, it's worth having a utility function for it. | |
*/ | |
float mapsin(float value, float start, float stop) { | |
return map(sin(value), -1, 1, start, stop); | |
} | |
void drawFadingCircle(float t) { | |
// use push() and pop() to keep style changes isolated | |
push(); | |
float sin_value = sin(t * TWO_PI); | |
// this value will range from 0 to 1 | |
float normalized_value = norm(sin_value, -1, 1); | |
// interpolate the color based on normalized_value | |
color lerpedColor = lerpColor(red, green, normalized_value); | |
// set the fill to the lerp color | |
fill(lerpedColor); | |
circle(width * 0.5, height * 0.5, 200); | |
pop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
NOTE: these colors will still be RGB, | |
because they are defined before we call colorMode() | |
*/ | |
color red = color(255, 0, 0); | |
color green = color(0, 255, 0); | |
void setup() { | |
size(500, 500); | |
noStroke(); | |
colorMode(HSB, 1.0); | |
} | |
void draw() { | |
background(0); | |
float t = loopNormal(frameCount, 120); | |
drawRainbowCircle(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
/* | |
We use this so much, it's worth having a utility function for it. | |
*/ | |
float mapsin(float value, float start, float stop) { | |
return map(sin(value), -1, 1, start, stop); | |
} | |
void drawRainbowCircle(float t) { | |
// use push() and pop() to keep style changes isolated | |
push(); | |
// choose the hue based on t | |
// keep saturation and brightness at full | |
color hsbColor = color(t, 1, 1); | |
// set the fill | |
fill(hsbColor); | |
circle(width * 0.5, height * 0.5, 200); | |
pop(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Generate a random number between 1000 and 10000 to mix up the noise motion | |
float noiseSeed = random(1000, 10000); | |
void setup() { | |
size(500, 500); | |
noStroke(); | |
} | |
void draw() { | |
background(0); | |
float t = loopNormal(frameCount, 480); | |
drawNervousCircle(t); | |
} | |
/* | |
This function calculates how far we are through our total frame count | |
*/ | |
float loopNormal(float frameNumber, float totalFramesForLoop) { | |
return (frameNumber % totalFramesForLoop) / totalFramesForLoop; | |
} | |
/* | |
We use this so much, it's worth having a utility function for it. | |
*/ | |
float mapsin(float value, float start, float stop) { | |
return map(sin(value), -1, 1, start, stop); | |
} | |
void drawNervousCircle(float t) { | |
push(); | |
float base_x = width * 0.5; | |
float base_y = height * 0.5; | |
/* | |
We're drawing a circle around the noise space, | |
so at the end of our loop, our noise offset is the same | |
as it was when started. | |
*/ | |
float noise_input_x = cos(t * TWO_PI); | |
float noise_input_y = sin(t * TWO_PI); | |
float x_offset = noise(noise_input_x, noise_input_y); | |
// We add a random noiseSeed to move to a different part of the noise space | |
float y_offset = noise(noiseSeed + noise_input_x, noiseSeed + noise_input_y); | |
// Remap the noise offsets from [0, 1] to [-100, 100] | |
x_offset = map(x_offset, 0, 1, -100, 100); | |
y_offset = map(y_offset, 0, 1, -100, 100); | |
/* | |
Uncomment this line to offset by a sine wave instead | |
and compare the motions. | |
*/ | |
//x_offset = 0; | |
//y_offset = mapsin(t * TWO_PI, -100, 100); | |
circle(base_x + x_offset, base_y + y_offset, 200); | |
pop(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment