Processing Beginner Article 2

Loops & Patterns

Use for and while loops to generate grids, rings, spirals, and Truchet tile patterns.

⏱ 18 min loops for while patterns grid translate

The for loop

The for loop is your primary tool for repetition. Its three parts — initialise, test, increment — sit inside parentheses separated by semicolons.

// Print 0 through 9 to the console
for (int i = 0; i < 10; i++) {
  println(i);
}

Using it to draw shapes:

void setup() {
  size(600, 200);
  background(20);
  noStroke();
  fill(100, 180, 255);
  for (int i = 0; i < 10; i++) {
    float x = 30 + i * 55;
    ellipse(x, 100, 40, 40);
  }
}

The variable i counts up; you multiply it to spread the circles across the canvas.

Nested loops: drawing a grid

Nest one for loop inside another to iterate over rows and columns.

void setup() {
  size(600, 600);
  background(20);
  noStroke();

  int cols = 12;
  int rows = 12;
  float cellW = width  / (float) cols;
  float cellH = height / (float) rows;

  for (int row = 0; row < rows; row++) {
    for (int col = 0; col < cols; col++) {
      float x = col * cellW + cellW / 2;
      float y = row * cellH + cellH / 2;

      // Colour shifts with position
      float hue = map(col, 0, cols - 1, 0, 255);
      float brightness = map(row, 0, rows - 1, 60, 255);
      fill(hue, brightness * 0.6, brightness);
      ellipse(x, y, cellW * 0.8, cellH * 0.8);
    }
  }
}

The outer loop steps through rows; the inner loop steps through columns. Every combination (row, col) is visited exactly once.

The while loop

while repeats as long as its condition is true. Use it when you do not know in advance how many iterations you need.

float y = 10;
float gap = 10;

void setup() {
  size(400, 400);
  background(20);
  stroke(255, 255, 255, 80);

  while (y < height) {
    line(0, y, width, y);
    gap += 2;        // gap grows each iteration
    y  += gap;
  }
}

Be careful: if the condition never becomes false, the loop runs forever and Processing freezes. Always make sure the condition will eventually fail.

break and continue

break exits the loop immediately. continue skips the rest of the current iteration and jumps to the next one.

// Draw at most 50 circles, but skip positions too close to the centre
for (int i = 0; i < 200; i++) {
  float x = random(width);
  float y = random(height);

  if (i >= 50) break;   // stop after 50 circles total

  float d = dist(x, y, width / 2, height / 2);
  if (d < 80) continue; // skip circles near centre

  ellipse(x, y, 20, 20);
}

Radial patterns with translate()

translate() moves the origin, which makes radial (ring-based) layouts simple: always draw at the same local position, just rotate the coordinate system.

void setup() {
  size(600, 600);
  background(15);
  noStroke();

  int count = 18;
  float ringRadius = 200;
  float dotSize   = 22;

  translate(width / 2, height / 2);

  for (int i = 0; i < count; i++) {
    float angle = TWO_PI / count * i;
    float x = cos(angle) * ringRadius;
    float y = sin(angle) * ringRadius;

    // Colour cycles through the hue wheel
    colorMode(HSB, 360, 100, 100);
    fill(map(i, 0, count, 0, 360), 80, 100);
    ellipse(x, y, dotSize, dotSize);
  }
}

Spiral of dots

Combine an ever-increasing radius with an angle that ticks forward each step:

void setup() {
  size(600, 600);
  background(10);
  noStroke();
  fill(255, 140, 60, 180);

  float angle  = 0;
  float radius = 0;

  for (int i = 0; i < 300; i++) {
    float x = width  / 2 + cos(angle) * radius;
    float y = height / 2 + sin(angle) * radius;
    float sz = map(i, 0, 300, 2, 16);
    ellipse(x, y, sz, sz);

    angle  += 0.3;
    radius += 0.8;
  }
}

Full example: Truchet tile pattern

Truchet tiles fill a grid with quarter-circle arcs. In each cell you randomly choose one of two orientations. The result looks complex but the code is compact.

int COLS = 14;
int ROWS = 14;
float CELL;

void setup() {
  size(700, 700);
  CELL = width / (float) COLS;
  background(240, 235, 225);
  noFill();
  stroke(40, 35, 30);
  strokeWeight(3);
  drawTruchet();
}

void drawTruchet() {
  for (int row = 0; row < ROWS; row++) {
    for (int col = 0; col < COLS; col++) {
      float x = col * CELL;
      float y = row * CELL;
      drawTile(x, y, (int) random(2));
    }
  }
}

// orientation 0: arcs connect top-left and bottom-right corners
// orientation 1: arcs connect top-right and bottom-left corners
void drawTile(float x, float y, int orientation) {
  pushMatrix();
  translate(x, y);

  if (orientation == 0) {
    // Top-left quadrant arc
    arc(0, 0, CELL, CELL, 0, HALF_PI);
    // Bottom-right quadrant arc
    arc(CELL, CELL, CELL, CELL, PI, PI + HALF_PI);
  } else {
    // Top-right quadrant arc
    arc(CELL, 0, CELL, CELL, HALF_PI, PI);
    // Bottom-left quadrant arc
    arc(0, CELL, CELL, CELL, PI + HALF_PI, TWO_PI);
  }

  popMatrix();
}

// Press any key to regenerate
void keyPressed() {
  background(240, 235, 225);
  drawTruchet();
}

Run it a few times with the key press — each seed produces a completely different-looking pattern from the same simple rule.

Key takeaways

  • for (int i = 0; i < n; i++) is the standard counted loop in Java/Processing.
  • Nested loops give you every (row, col) combination — essential for grids.
  • while loops are best when the stopping condition is dynamic.
  • break exits early; continue skips the current iteration.
  • translate() before a loop is the cleanest way to build radial and grid layouts.
  • Complex-looking patterns often emerge from a simple rule applied many times.