Processing Code for Random Symmetrical P ...

Processing Code for Random Symmetrical Patterns

Mar 15, 2025

image

I've included code below for Processing (Java mode) that generates a variety of random symmetrical patterns using different algorithms.

Video example:

https://youtu.be/i0_bznpG1Zg

Just copy and paste it into your Processing window. Make sure you're using Java mode!

import java.io.File;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.HashMap;

int frameIndex = 0;

String outputFolder;

String[] patternModes = {

"dither", "grayscale", "bigcircle", "bigarc", "ink_blot",

"radialspread", "organicmesh", "fragmented_noise", "glitch"

};

// For each algorithm we store a random scale (so it doesn't change within a series)

HashMap<String, Float> modeScale = new HashMap<String, Float>();

public void settings() {

size(1024, 768);

}

public void setup() {

frameRate(5);

noStroke();

// Create a unique folder with current date and time

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");

outputFolder = "d://patterns/pattern_" + sdf.format(new Date());

File folder = new File(outputFolder);

if (!folder.exists()) {

folder.mkdirs();

}

}

public void draw() {

background(255);

int totalFramesPerMode = 5;

int currentModeIndex = frameIndex / totalFramesPerMode;

if (currentModeIndex >= patternModes.length) {

noLoop();

return;

}

String mode = patternModes[currentModeIndex];

println("Frame " + frameIndex + " mode: " + mode);

// If the scale for this algorithm hasn't been chosen yet - set it

if (!modeScale.containsKey(mode)) {

modeScale.put(mode, random(0.5f, 2.0f));

}

float elementScale = modeScale.get(mode);

println("Scale factor: " + elementScale);

// loop_t changes from 0 to 1 over 30 frames and then repeats

float loop_t = (frameIndex % totalFramesPerMode) / (float)totalFramesPerMode;

int margin = 30; // Border width

int cellSize = 10; // Inner grid cell size

int effectiveWidth = width - 2 * margin;

int effectiveHeight = height - 2 * margin;

// Draw the pattern in the left half of the inner area

drawInnerPattern(mode, margin, cellSize, effectiveWidth, effectiveHeight, elementScale, loop_t);

// Mirror the inner area vertically for complete symmetry

mirrorInnerVertically(margin, effectiveWidth, effectiveHeight);

// Draw a black border around the edges

drawBorder(margin);

// Save the frame as an image

String filename = outputFolder + "/frame-" + nf(frameIndex, 4) + ".png";

saveFrame(filename);

frameIndex++;

if (frameIndex >= patternModes.length * totalFramesPerMode) {

noLoop();

}

}

// Function for cyclical noise.

// We use a technique where coordinates are shifted along a circle, which ensures a cycle.

float loopNoise(float a, float b, float t) {

float r = 100; // Radius - adjust for desired effect

float nx = cos(TWO_PI t) r;

float ny = sin(TWO_PI t) r;

return noise(a + nx, b + ny);

}

public void drawInnerPattern(String mode, int margin, int cellSize, int effectiveWidth, int effectiveHeight, float elementScale, float loop_t) {

for (int y = margin; y < margin + effectiveHeight; y += cellSize) {

for (int x = margin; x < margin + effectiveWidth/2; x += cellSize) {

float n = loopNoise((x - margin) 0.05f, (y - margin) 0.05f, loop_t);

drawCell(x, y, cellSize, n, mode, elementScale, loop_t);

int x_offset = x - margin;

int mirrorx = margin + effectiveWidth - xoffset - cellSize;

drawCell(mirrorx, y, cellSize, n, mode, elementScale, loopt);

}

}

}

public void drawCell(int x, int y, int cellSize, float n, String mode, float elementScale, float loop_t) {

if (mode.equals("dither")) {

noStroke();

fill(n < 0.5 ? 0 : 255);

rect(x, y, cellSize, cellSize);

} else if (mode.equals("grayscale")) {

noStroke();

int shade = (int)(n * 255);

fill(shade);

rect(x, y, cellSize, cellSize);

} else if (mode.equals("big_circle")) {

noStroke();

fill(0);

pushMatrix();

translate(x + cellSize/2, y + cellSize/2);

float d = cellSize (0.8f + 0.4f n) * elementScale;

ellipse(0, 0, d, d);

popMatrix();

} else if (mode.equals("big_arc")) {

noFill();

stroke(0);

strokeWeight(1.5f);

pushMatrix();

translate(x + cellSize/2, y + cellSize/2);

float startangle = n * TWOPI;

float arcextent = PI + n * HALFPI;

float d = cellSize (1.2f + 0.5f n) * elementScale;

arc(0, 0, d, d, startangle, startangle + arc_extent);

popMatrix();

} else if (mode.equals("ink_blot")) {

noStroke();

fill(0);

pushMatrix();

translate(x + cellSize/2, y + cellSize/2);

beginShape();

int num_vertices = (int)random(8, 16);

for (int i = 0; i < num_vertices; i++) {

float angle = map(i, 0, numvertices, 0, TWOPI);

float base_r = (cellSize/2.0f) * elementScale;

// Calculate the third parameter separately to call noise with three arguments

float thirdParam = cos(TWOPI * loopt) * 0.5f + sin(TWOPI * loopt) * 0.5f;

float r = base_r (0.5f + 0.5f noise(cos(angle) + n, sin(angle) + n, thirdParam));

r *= random(0.8f, 1.2f);

vertex(r cos(angle), r sin(angle));

}

endShape(CLOSE);

popMatrix();

} else if (mode.equals("radial_spread")) {

stroke(0);

strokeWeight(1);

pushMatrix();

translate(x + cellSize/2, y + cellSize/2);

int num_lines = (int)(4 + n * 8);

for (int i = 0; i < num_lines; i++) {

float angle = map(i, 0, numlines, 0, TWOPI);

float length = cellSize (0.5f + n elementScale);

if (loopNoise(cos(angle) + 0.1f, sin(angle) + 0.1f, loop_t) > 0.4f) {

line(0, 0, length cos(angle), length sin(angle));

}

}

popMatrix();

} else if (mode.equals("organic_mesh")) {

noFill();

stroke(0);

strokeWeight(1);

pushMatrix();

translate(x, y);

int num_points = 4 + (int)(n * 4);

beginShape();

for (int i = 0; i < num_points; i++) {

float px = random(0, cellSize);

float py = random(0, cellSize);

curveVertex(px, py);

}

endShape();

popMatrix();

} else if (mode.equals("fragmented_noise")) {

noStroke();

int num_fragments = 4;

float fragSize = cellSize / 2.0f;

for (int i = 0; i < 2; i++) {

for (int j = 0; j < 2; j++) {

float fragnoise = loopNoise((x + i fragSize) 0.1f, (y + j fragSize) 0.1f, loopt);

if (frag_noise > 0.4f) {

fill(0);

} else {

fill(255);

}

rect(x + i fragSize, y + j fragSize, fragSize, fragSize);

}

}

} else if (mode.equals("glitch")) {

noStroke();

fill(0);

pushMatrix();

float dx = random(-cellSize 0.2f, cellSize 0.2f);

float dy = random(-cellSize 0.2f, cellSize 0.2f);

translate(x + cellSize/2 + dx, y + cellSize/2 + dy);

for (int i = 0; i < 3; i++) {

int alpha_val = (int)(150 - i * 40);

fill(0, alpha_val);

float sizeoffset = cellSize (0.5f + 0.5f loopNoise(n, i, loopt));

rectMode(CENTER);

rect(0, 0, sizeoffset * elementScale, sizeoffset * elementScale);

}

popMatrix();

}

}

public void mirrorInnerVertically(int margin, int effectiveWidth, int effectiveHeight) {

loadPixels();

int inner_top = margin;

int inner_bottom = margin + effectiveHeight;

int halfinnerheight = effectiveHeight / 2;

for (int y = innertop; y < innertop + halfinnerheight; y++) {

int mirrory = innerbottom - 1 - (y - inner_top);

for (int x = margin; x < margin + effectiveWidth; x++) {

int topIndex = x + y * width;

int bottomIndex = x + mirror_y * width;

pixels[bottomIndex] = pixels[topIndex];

}

}

updatePixels();

}

public void drawBorder(int margin) {

noStroke();

fill(0);

rect(0, 0, width, margin);

rect(0, height - margin, width, margin);

rect(0, margin, margin, height - 2 * margin);

rect(width - margin, margin, margin, height - 2 * margin);

}

A Little Note

I'm sharing this code freely because I love creating and sharing interesting visual patterns with the community. While I certainly don't expect anything in return, if you find this useful or it sparks joy in your projects, I wouldn't mind a coffee! ☕

Your support helps me continue creating and sharing more free resources like this one. Either way, I hope you enjoy playing with these symmetrical patterns as much as I enjoyed making them!

Enjoy this post?

Buy Georgiy Ermakov a coffee

More from Georgiy Ermakov