Processing Code Examples: Creative Coding Fun! Modifying Published Processing Sketches

title image

This is an example of a modification of a published Processing code, in which the particles appear to autonomously divide into groups of different colors. The source code of the program is presented here, along with the key points of its creation.

The source code of the program is presented here, along with the key points of its production.

 

日本語版の記事はこちらです。


Original Processing Code for Modification

This example was created by modifying the code that ひさだん(@hisadan) san had published on Twitter.


Its autonomous and organic moving are attractive. So, I wanted to make some modified works.

 

Key Points of Reading Source Code in Creative Coding Way

At first, I refactored the minified source code for Twitter posting.



/**
 * Ref. https://x.com/hisadan/status/1913976946687422638
 */

int i, s, n = 999;
float a[] = new float[n * 2];
float x, y, d, r, e, f;

void setup() {
  size(800,800);
  colorMode(HSB);
  background(0);

  // locate the particles randomly
  // a[i] as x axis, a[i + n] as y axis
  for (i = 0; i < n; i++) {
    d = random(250);
    r = random(TAU);
    a[i] = d * sin(r);
    a[i + n] = d * cos(r);
  }
}

void draw() {
  // translucent for afterimage
  fill(0,2);
  square(0, 0, 800);
  
  // calculation for particle move
  for(i = 0; i < n; i++) {
    for(s = 0; s < n; s++) {
      x = 0;
      y = 0;
      d = dist(a[i], a[i + n], a[s], a[s + n]);
      e = (a[s] - a[i]) / d / d;
      f = (a[s + n] - a[i + n]) / d / d;

      if (i != s) {
        if (i % 2 == s % 2) {
          x += d > 100 ? -e : e;
          y += d > 100 ? -f : f;
        } else {
          x += d > 50 ? e : -e;
          y += d > 50 ? f : -f;
        }
      }

      a[i] += x;
      a[i + n] += y;

    }

    // color with distance from center of sketch
    stroke(mag(a[i], a[i + n]), 255, 255);
    point(a[i] + 400, a[i + n] + 400);
  }
}  

I've written some comments on source code.

This level of understanding is sufficient when reading the code for modifications, and the rest will be understood as modifications are made.

 

Key Points for Creative Coding Style Modifications

Since it is boring to read code all the time, I will follow the creative coding style and start modifying the code, leaving the understanding of the code there.

When making modifications, if you start with simple changes such as changing initial values, you will smoothly understand how the program works. By the time you move on to more difficult modifications such as changing movements, you will be able to see what the key parts of the code are and where the appeal is created.

 

Try to Change the Number of Particles


int i, s, n = 999;

Change the number of 999 to an extreme 10,000 or 10 and see the result.

 

Try to Change the Way to Draw


  // translucent for afterimage
  fill(0,2);
  square(0, 0, 800);

Try opaque or transparent.


    // color with distance from center of sketch
    stroke(mag(a[i], a[i + n]), 255, 255);
    point(a[i] + 400, a[i + n] + 400);

For example.

 

Try to Change the Moving of Particles


      d = dist(a[i], a[i + n], a[s], a[s + n]);
      e = (a[s] - a[i]) / d / d;
      f = (a[s + n] - a[i + n]) / d / d;

This is one of the most important points because it is the part that determines the amount of change in position. It's both a rewarding and challenging aspect of the modification.


        if (i % 2 == s % 2) {
          x += d > 100 ? -e : e;
          y += d > 100 ? -f : f;
        } else {
          x += d > 50 ? e : -e;
          y += d > 50 ? f : -f;
        }

This is a part where I don't know what it's doing, or rather, I know what it's doing, but I don't know why it's doing this.

So, I guess it must be a key point of this work!

Example modification of this part.

 

Processing Code of Modified Work

Here is the Processing code of my modified work.


/**
 * Processing Example Code: particles seemingly autonomously sort themselves into different color clusters.
 * Ref. https://x.com/hisadan/status/1913976946687422638
 *
 * @author @deconbatch
 * @version 0.1
 * @license CC0 1.0 https://creativecommons.org/publicdomain/zero/1.0/deed.ja
 * Processing 4.3.3
 * 2025.05.22
 */

void setup() {

  int   frmMax   = 24 * 10; // 24fps x 10sec
  int   pNumMax  = 1800;
  int   pClass   = 6;
  float pIniRad  = 80.0;
  float pDistMax = 220.0;
  float distMag  = 12.0;
  float baseHue  = random(120.0, 300.0);
  
  PVector curP[] = new PVector[pNumMax];
  PVector prvP[] = new PVector[pNumMax];

  size(720, 720);
  colorMode(HSB, 360.0, 100.0, 100.0, 100.0);

  for(int pCnt = 0; pCnt < pNumMax; pCnt++){
    float r = random(pIniRad);
    float t = random(TAU);
    curP[pCnt] = new PVector(r * cos(t), r * sin(t));
    prvP[pCnt] = new PVector(curP[pCnt].x, curP[pCnt].y);
  }
  
  translate(width * 0.5, height * 0.5);
  rectMode(CENTER);
  blendMode(BLEND);
  background(baseHue, 40.0, 10.0, 100.0);

  // iterate for the number of animation frames
  for (int frm = 0; frm < frmMax; frm++) {

    // for afterimage
    blendMode(BLEND);
    fill(baseHue, 40.0, 10.0, 20.0);
    noStroke();
    rect(0.0, 0.0, width, height);

    // calc position of points
    for (int mCnt = 0; mCnt < pNumMax; mCnt++) {
      for (int oCnt = 0; oCnt < pNumMax; oCnt++) {
        if (mCnt != oCnt) {

          float pDist = 1.0 + PVector.dist(prvP[mCnt], prvP[oCnt]);
          PVector pDiv = PVector.div(PVector.mult(PVector.sub(prvP[mCnt], prvP[oCnt]), distMag), pow(pDist, 2));

          if (mCnt % pClass == oCnt % pClass) {
            curP[mCnt].add(pDiv.mult((pDistMax - pDist) / pDistMax));
          } else {
            if (pDist > pDistMax) {
              curP[mCnt].sub(pDiv);
            } else {
              curP[mCnt].add(pDiv);
            }
          }
          
        }
      }
    }

    // calc min/max distance
    float drMin = 99.0;
    float drMax = -drMin;
    for (int mCnt = 0; mCnt < pNumMax; mCnt++) {
      float dR = PVector.dist(curP[mCnt], prvP[mCnt]) / pDistMax;
      drMax = max(drMax, dR);
      drMin = min(drMin, dR);
    }

    // draw lines
    blendMode(SCREEN);
    noFill();
    for (int mCnt = 0; mCnt < pNumMax; mCnt++) {
      float distRatio = map(PVector.dist(curP[mCnt], prvP[mCnt]) / pDistMax, drMin, drMax, 0.0, 1.0);
      float hueRatio = (mCnt % pClass) * 1.0 / pClass;
      float satRatio = floor(0.5 + mCnt / (pNumMax * 0.3)) / 3.0;
      float briRatio = floor(0.5 + mCnt / (pNumMax * 0.2)) / 5.0;

      stroke((baseHue + 90.0 + hueRatio * 120.0 + distRatio * 90.0) % 360.0,
             10.0 + satRatio * (1.0 - distRatio) * 80.0,
             20.0 + briRatio * 30.0 + distRatio * 30.0,
             100.0
             );
      strokeWeight(constrain(6.0 * (1.0 - distRatio), 1.0, 6.0));
      line(prvP[mCnt].x, prvP[mCnt].y, curP[mCnt].x, curP[mCnt].y);
    }

    // carry over
    cur2prv(curP, prvP);

    // make image files for animation frames
    saveFrame("frames/" + String.format("%04d", frm) + ".png");
  }

  exit();
}

/**
 * deep copy from c to p
 */
void cur2prv(PVector[] c, PVector[] p){
  for(int pCnt = 0; pCnt < p.length; pCnt++){
    p[pCnt].x = c[pCnt].x;
    p[pCnt].y = c[pCnt].y;
  }
}

 

Points of Modification

I decided to manage the particles with PVector.


    curP[pCnt] = new PVector(r * cos(t), r * sin(t));

I separated arrays for position calculations and for the results of previous calculations, so that the results of one particle's calculations do not affect the position calculations of other particles.


  PVector curP[] = new PVector[pNumMax]; // current
  PVector prvP[] = new PVector[pNumMax]; // previous

I implemented a change in the particle's position calculation formula, using the condition '(mCnt % pClass == oCnt % pClass)'.


          float pDist = 1.0 + PVector.dist(prvP[mCnt], prvP[oCnt]);
          PVector pDiv = PVector.div(PVector.mult(PVector.sub(prvP[mCnt], prvP[oCnt]), distMag), pow(pDist, 2));

          if (mCnt % pClass == oCnt % pClass) {
            curP[mCnt].add(pDiv.mult((pDistMax - pDist) / pDistMax));
          } else {
            if (pDist > pDistMax) {
              curP[mCnt].sub(pDiv);
            } else {
              curP[mCnt].add(pDiv);
            }
          }

Because of the long computation time required, I did not make real-time animation with draw() function. Instead, I've decided to use a method that writes out a still image for each frame to generate a movie.

 

Additional Ideas for Modification

Even with the code as it is, you can get various results by changing the initial values of the variables.


  int   pNumMax  = 1800;
  int   pClass   = 6;
  float pIniRad  = 80.0;
  float pDistMax = 220.0;
  float distMag  = 12.0;

It would be interesting to get interesting results if these variables were not fixed values, but rather values that change as the frame progresses.

 

Conclusion

My modified work leaned more towards a simulation than an art piece.

It looks as if the particles by color move and gather autonomously, but in reality it is better to say that the color is changed by the group of particles that gather.


      float hueRatio = (mCnt % pClass) * 1.0 / pClass;

To tell the truth, I have no idea why both the original code and the modified code work like this.

This means that even if you do not have a technical understanding of the program code, you can modify it and create a work of art with your hands. I think this is the best part of creative coding.

Without the underlying code this time, this work would not have been created.
Thank you, ひさだん(@hisadan) san for publishing this interesting example code.

 

Previous Post
No Comment
Add Comment
comment url