P5.js translation to Processing (saving frames)

Hello!
I am working with an open processing sketch of constructivist art. I have translated to processing and I am trying to save a picture everytime the animation stops, but it makes the sketch so slow and it rewrite the file again and again, instead saving files number 1, 2, 3, etc, as I want. Could you please help me?

color[] colors = {
  color(#edb218),
  color(#029cc2),
  color(#6b8c87),
  color(#a5473d),
  color(#588344),
  color(#28312e),
  color(#edb218),
  color(#029cc2),
  color(#6b8c87),
  color(#a5473d),
  color(#588344)
};

ArrayList<Placement> fromPlacements = new ArrayList<Placement>();
ArrayList<Placement> toPlacements = new ArrayList<Placement>();
ArrayList<ShapeDancer> shapeDancers = new ArrayList<ShapeDancer>();

int frames = 150;
PGraphics p;

void setup() {
  size(1000, 1000);
  background(color(238, 235, 211));
  
  float spitA = random(-PI/3, PI/3);
  
  Placement spit = new Placement(spitA, new PVector(width/2, height/2), height*0.03, width*0.8);
  fromPlacements.add(spit);
  
  for(int i = 0; i < 3; i++) {
    spit = new Placement(spitA, new PVector(random(width), random(height)), height*0.02, random(height*0.3, height*0.6));
    fromPlacements.add(spit); 
  }
  
  for(float a = spitA + PI/2 + PI/3; a < spitA + PI/2 + TWO_PI - PI/3; a += PI/12) {
    float d = random(height*0.05, height*0.5);
    float xer = width/2 + cos(PI/2 + a) * d;
    float yer = height/2 + sin(PI/2 + a) * d;
    float her = random(height*0.01, height*0.3);
    float wer = random(height*0.01, height*0.3);
    Placement shape = new Placement(spitA, new PVector(xer, yer), her, wer);
    fromPlacements.add(shape);
  }
  
  spitA = random(-PI/3, PI/3);
  spit = new Placement(spitA, new PVector(width/2, height/2), height*0.03, width*0.8);
  toPlacements.add(spit);
  
  for(int i = 0; i < 3; i++) {
    spit = new Placement(spitA, new PVector(random(width), random(height)), height*0.02, random(height*0.3, height*0.6));
    toPlacements.add(spit); 
  }
  
  for(float a = spitA + PI/2 + PI/3; a < spitA + PI/2 + TWO_PI - PI/3; a += PI/12) {
    float d = random(height*0.05, height*0.5);
    float xer = width/2 + cos(PI/2 + a) * d;
    float yer = height/2 + sin(PI/2 + a) * d;
    float her = random(height*0.01, height*0.3);
    float wer = random(height*0.01, height*0.3);
    Placement shape2 = new Placement(spitA, new PVector(xer, yer), her, wer);
    toPlacements.add(shape2);
  }
  
  //Collections.shuffle(toPlacements, true);
  
  for(int i = 0; i < fromPlacements.size(); i++) {
    shapeDancers.add(new ShapeDancer(i));
  }
  
  p = createGraphics((int)(height * 1.5), height);
  
  for(int i = 0; i < 100000; i++) {
    p.noStroke();
    p.fill(255, (int)random(5, 10));
    //p.ellipse(random(width), random(height), random(1, 3));
  }
}

void draw() {
  blendMode(MULTIPLY);
  clear();
  background(238, 235, 211);

  
  if(frameCount % 300 == 0) {
    fromPlacements = new ArrayList<Placement>(toPlacements);
    toPlacements.clear();
    
    float spitA = random(-PI/3, PI/3);
    Placement spit = new Placement(spitA, new PVector(width/2, height/2), height*0.03, width*0.8);
    toPlacements.add(spit);
    
    for(int i = 0; i < 3; i++) {
      spit = new Placement(spitA, new PVector(random(width), random(height)), height*0.02, random(height*0.3, height*0.6));
      toPlacements.add(spit); 
    }
    
    for(float a = spitA + PI/2 + PI/3; a < spitA + PI/2 + TWO_PI - PI/3; a += PI/12) {
      float d = random(height*0.05, height*0.5);
      float xer = width/2 + cos(PI/2 + a) * d;
      float yer = height/2 + sin(PI/2 + a) * d;
      float her = random(height*0.01, height*0.3);
      float wer = random(height*0.01, height*0.3);
      Placement shape2 = new Placement(spitA, new PVector(xer, yer), her, wer);
      toPlacements.add(shape2);
    }
    
    //Collections.shuffle(toPlacements, true);
  }
  
  for(ShapeDancer shapeDancer : shapeDancers) {
    shapeDancer.dance();
    shapeDancer.show();
  }
  
  push();
  blendMode(BLEND);
  image(p, 0, 0);
  pop();
      saveFrame("x.jpg");

}

class Placement {
  float between;
  int index;
  float theta;
  PVector pos;
  float h;
  float w;
  String colors;
  
  Placement(float angle, PVector position, float height, float width) {
    between = 0;
    index = 0;
    theta = angle;
    pos = position;
    h = height;
    w = width;
   // colors = colors.get((int)random(colors.size()));
  }
}

class ShapeDancer {
  float between;
  int index;
  float theta;
  PVector pos;
  float h;
  float w;
  String colors;
  
  ShapeDancer(int idx) {
    between = 0;
    index = idx;
    theta = fromPlacements.get(idx).theta;
    pos = fromPlacements.get(idx).pos;
    h = fromPlacements.get(idx).h;
    w = fromPlacements.get(idx).w;
    colors = fromPlacements.get(idx).colors;
  }
  
  void dance() {
    if(frameCount % 300 == 0) {
      between = 0;
    }
    
    float framesMap = map(between, 0, frames, 0, 1);
    pos = PVector.lerp(fromPlacements.get(index).pos, toPlacements.get(index).pos, easeInOutSine(framesMap));
    h = lerp(fromPlacements.get(index).h, toPlacements.get(index).h, easeInOutSine(framesMap));
    w = lerp(fromPlacements.get(index).w, toPlacements.get(index).w, easeInOutSine(framesMap));
    theta = lerp(fromPlacements.get(index).theta, toPlacements.get(index).theta, easeInOutBounce(framesMap));
    
    if(between < frames) {
      between += 1;

    }
  }
  
  
  void show() {
    noStroke();
    fill(0,124,0);
    push();
    rectMode(CENTER);
    translate(pos.x, pos.y);
    rotate(theta);
    rect(0, 0, w, h);
    pop();
  }
}


float easeInOutSine(float x) {
  return -(cos(PI * x) - 1) / 2;
}

float easeOutBounce(float x) {
  float n1 = 7.5625;
  float d1 = 2.75;
  if (x < 1 / d1) {
    return n1 * x * x;
  } else if (x < 2 / d1) {
    return n1 * (x -= 1.5 / d1) * x + 0.75;
  } else if (x < 2.5 / d1) {
    return n1 * (x -= 2.25 / d1) * x + 0.9375;
  } else {
    return n1 * (x -= 2.625 / d1) * x + 0.984375;
  }
}

float easeInOutBounce(float x) {
  if (x < 0.5) {
    return (1 - easeOutBounce(1 - 2 * x)) / 2;
  } else {
    return (1 + easeOutBounce(2 * x - 1)) / 2;
  }
}

This is the problem:

saveFrame(“x.jpg”);

Hello.
For this part, just use something like:

saveFrame(coolname-####.jpg);

to get files like

coolname-0001.jpg, coolname-0002.jpg

Saving is time consuming. I’ve dealt with this kind of problems in different ways.

  1. try .tif or .targa. They are faster.

if that’s not enough

  1. Save images to a list and at exiting the app, traverse the list saving the files.

if that’s not eough

  1. save all the parameters (probably a class to store the data together) and store them in a list. When ready retrive each frame’s parameters and save them. It works like a “render”

just did that in some code, but its a working uncommented code, if you wanna have a look…
here:
There is a lot of controls.
1 - toogle rec
2 - toogle replay
3 - toogle save (you can replay without saving)

Any movement is recorded and replayed/saved.

press 1 → move stuff → press 1 to stop recording → press 3 (or not) → press 2(replay/save)

Again a messy wip code… with dependencies. But you don’t need to run it, just to get the idea. look at draw and the extra classes. But if you want, it’s in test mode so it won’t try to load anything you don’t have : ) .

the main tab:

import nub.primitives.*;
import nub.core.*;
import nub.processing.*;

// Scene object for managing the 3D environment
Scene scene;
// Node objects for scene hierarchy
Node master, caixa;


// Canvas dimensions
int canvas_width = 1200;
int canvas_height = 810;
// Zoom factor for mouse wheel interaction
float zoom_factor = 2;

// Rotation offsets and speeds
float x_offset;
float y_offset;
float z_offset;




// Rotation of master
float x_speed;
float y_speed;
float z_speed;


// Orbit speeds around axes
float x_orbit_speed;
float y_orbit_speed;
float z_orbit_speed;

float offset_inc = 0.05;
float inc = 0.001;

// Speed variable for forward movement
float trav_speed;


// Translation variables
float trans_x, trans_y, trans_z;

// Terrain shape
PShape terrain_shape;
// Flags
boolean record = false, play = false, show_grid = true, test = true;
// Background color
color background_color = color(0);



boolean just_initialized = true;
boolean printout = false;
boolean first_run = true;

String name = "";
// Player object for managing scene interaction
Player player;
Player initial;

ArrayList<ArrayList<State>> states;

void settings() {
  // Set canvas size with P3D renderer
  size(canvas_width, canvas_height, P3D);
}

void setup() {
  // Instantiate nub objects
  scene = new Scene(this, 1000);
  master = new Node();
  caixa = new Node(master);
  
  // Load terrain shape
  if (test) {
    // Create a test box shape
    terrain_shape = createShape(BOX, 100, 50, 300);
  } else {
    // Load 3D model
    terrain_shape = loadShape("Mariana_simplified_3d_mesh.obj");
    // Flip the model
    terrain_shape.scale(1.0, -1, 1);
  }

  // Set the shape for the caixa node
  caixa.setShape(terrain_shape);
  caixa.align(master);

  // Initialize player object
  player = new Player(scene.eye(), master, caixa);
  initial = new Player(scene.eye(), master, caixa);
  initial.rec();
  println(scene.eye());
  
  
}






void draw() {
  smooth();
  // Set background color
  // background_color = printout? color(0): color(255);
  background(background_color);

  // Rotate master node
  master.rotate(1, 0, 0, x_speed);
  master.rotate(0, 1, 0, y_speed);
  master.rotate(0, 0, 1, z_speed);

  // Orbit around axes
  scene.eye().orbit(Vector.plusK, x_orbit_speed, 0.5);
  scene.eye().orbit(Vector.plusI, y_orbit_speed, 0.5);
  scene.eye().orbit(Vector.plusJ, z_orbit_speed, 0.5);

  // Translate eye
  scene.eye().translate(trans_x, trans_y, trans_z, 0.5);

  // Move scene forward
  scene.moveForward(trav_speed);
  stroke(120);
  // Toggle grid and axes visibility
  if (show_grid) {
    scene.drawGrid();
    scene.drawAxes();
    caixa.enableHint(Node.AXES);
  } else {
    caixa.disableHint(Node.AXES);
  }

  // Render the scene
  scene.render();

  if (record) {
    name =
      String.valueOf(year()) +
      String.valueOf(month())+
      String.valueOf(day())  +
      String.valueOf(hour()) +
      String.valueOf(minute());

    play = false;
    player.rec();
  }
  if (play) {
    if (just_initialized) {
      reset();
    }
    just_initialized = false;
    record = false;
    if (player.hasNext()) {
      player.play();
      if (printout) {
        saveFrame(name+"/pr########.tif");
      }
    } else {
      player.clear();
      just_initialized = true;
      play = false;
      printout = false;
      exit();
    }
  }
  if(first_run){
    initial.rec();
    first_run =false;
  }
}

void mouseDragged() {
  if (mouseButton == LEFT)
    scene.spin();
  else if (mouseButton == RIGHT)
    scene.shift();
}

void mouseWheel(MouseEvent event) {
  scene.moveForward(event.getCount() * zoom_factor);
}

// Handle key presses
void keyPressed() {
  // Switch statement to handle different keys
  switch(key) {
    // Start/stop recording
  case '1':
  case '!':
    record = !record;
    println("Recording: " + record);
    break;
    // Play recorded actions
  case '2':
  case '@':
    play = !play;
    println("Playing: " + play);
    break;
    // Decrease Z-axis rotation speed
  case 'a':
    z_speed -= inc;
    println("Z speed: " + z_speed);
    break;
    // Decrease Z-axis rotation speed by half
  case 'A':
    z_speed -= inc  * 2;
    println("Z speed: " + z_speed);
    break;
    // Increase Z-axis rotation speed
  case 'z':
    z_speed += inc;
    println("Z speed: " + z_speed);
    break;
    // Increase Z-axis rotation speed by half
  case 'Z':
    z_speed += inc  * 2;
    println("Z speed: " + z_speed);
    break;
    // Decrease X-axis rotation speed
  case 's':
    x_speed -= inc;
    println("X speed: " + x_speed);
    break;
    // Decrease X-axis rotation speed by half
  case 'S':
    x_speed -= inc  * 2;
    println("X speed: " + x_speed);
    break;
    // Increase X-axis rotation speed
  case 'x':
    x_speed += inc;
    println("X speed: " + x_speed);
    break;
    // Increase X-axis rotation speed by half
  case 'X':
    x_speed += inc  * 2;
    println("X speed: " + x_speed);
    break;
    // Decrease Y-axis rotation speed
  case 'c':
    y_speed -= inc;
    println("Y speed: " + y_speed);
    break;
    // Decrease Y-axis rotation speed by half
  case 'C':
    y_speed -= inc  * 2;
    println("Y speed: " + y_speed);
    break;
    // Increase Y-axis rotation speed
  case 'd':
    y_speed += inc;
    println("Y speed: " + y_speed);
    break;
    // Increase Y-axis rotation speed by half
  case 'D':
    y_speed += inc  * 2;
    println("Y speed: " + y_speed);
    break;
    // Reset Z-axis rotation speed
  case 'q':
  case 'Q':
    z_speed = 0;
    println("Z speed: " + z_speed);
    break;
    // Reset X-axis rotation speed
  case 'w':
  case 'W':
    x_speed = 0;
    println("X speed: " + x_speed);
    break;
    // Reset Y-axis rotation speed
  case 'e':
  case 'E':
    y_speed = 0;
    println("Y speed: " + y_speed);
    break;
    // Reset forward movement speed
  case 'p':
    trav_speed = 0;
    println("Traversal speed: " + trav_speed);
    break;
    // Reset forward movement speed by half
  case 'P':
    trav_speed = 0;
    println("Traversal speed: " + trav_speed);
    break;
    // Increase forward movement speed
  case 'i':
    trav_speed += inc;
    println("Traversal speed: " + trav_speed);
    break;
    // Increase forward movement speed by half
  case 'I':
    trav_speed += inc  * 2;
    println("Traversal speed: " + trav_speed);
    break;
    // Decrease forward movement speed
  case 'o':
    trav_speed -= inc;
    println("Traversal speed: " + trav_speed);
    break;
    // Decrease forward movement speed by half
  case 'O':
    trav_speed -= inc  * 2;
    println("Traversal speed: " + trav_speed);
    break;

    // Translate caixa along X-axis (right)
  case '.':
  case '>':
    caixa.translate(new Vector(5, 0, 0));
    println(caixa.worldPosition());
    break;
    // Translate caixa along X-axis (left)
  case ',':
  case '<':
    caixa.translate(new Vector(-5, 0, 0));
    println(caixa.worldPosition());
    break;
    // Translate caixa along Y-axis (up)
  case '/':
    caixa.translate(new Vector(0, 5, 0));
    println(caixa.worldPosition());
    break;
  case '?':
    trans_x = trans_y = trans_z = 0;
    println(caixa.worldPosition());
    break;
    // Translate caixa along Y-axis (down)
  case '\'':
  case '\"':
    caixa.translate(new Vector(0, -5, 0));
    println(caixa.worldPosition());
    break;
    // Toggle grid visibility
  case '9':
  case '(':
    show_grid = !show_grid;
    println("Grid visibility: " + show_grid);
    break;
    // Translate caixa along Z-axis (forward)
  case '[':
  case '{':
    caixa.translate(new Vector(0, 0, 5));
    println(caixa.worldPosition());
    break;
    // Translate caixa along Z-axis (backward)
  case ']':
  case '}':
    caixa.translate(new Vector(0, 0, -5));
    println(caixa.worldPosition());
    break;
    // Reset all speeds and positions
  case '\\':
  case '|':
    reset();
    break;

  case 'j':
    caixa.rotate(0, 0, 1, -1 * offset_inc);
    break;

  case 'J':
    caixa.rotate(0, 1, 0, offset_inc);
    break;

  case 'l':
    caixa.rotate(0, 0, 1, offset_inc);
    break;

  case 'L':
    caixa.rotate(0, 1, 0, -offset_inc);
    break;

  case 'k':
    caixa.rotate(1, 0, 0, offset_inc);
    break;

  case 'm':
    caixa.rotate(1, 0, 0, -offset_inc);
    break;

    // Handle arrow key presses
  case CODED:
    switch(keyCode) {
      // Arrow key RIGHT to increase trans_x
    case RIGHT:
      trans_x += inc * 2 ;
      println("Translate X: " + trans_x);
      break;
      // Arrow key LEFT to decrease trans_x
    case LEFT:
      trans_x -= inc * 2;
      println("Translate X: " + trans_x);
      break;
      // Arrow key UP to increase trans_y
    case UP:
      trans_y += inc * 2;
      println("Translate Y: " + trans_y);
      break;
      // Arrow key DOWN to decrease trans_y
    case DOWN:
      trans_y -= inc * 2;
      println("Translate Y: " + trans_y);
      break;
    }
    break;
    // Additional key bindings for fine-tuning speed
    // 'v' - Increase Z-axis
    // rotation speed by 0.001 units
  case 'v':
    z_speed += inc;
    println("Z speed: " + z_speed);
    break;
    // 'b' - Increase X-axis rotation speed by 0.001 units
  case 'b':
    x_speed += inc;
    println("X speed: " + x_speed);
    break;
    // 'n' - Increase Y-axis rotation speed by 0.001 units
  case 'n':
    y_speed += inc;
    println("Y speed: " + y_speed);
    break;
    // 'f' - Decrease Z-axis rotation speed by 0.001 units
  case 'f':
    z_speed -= inc;
    println("Z speed: " + z_speed);
    break;
    // 'g' - Decrease X-axis rotation speed by 0.001 units
  case 'g':
    x_speed -= inc;
    println("X speed: " + x_speed);
    break;
    // 'h' - Decrease Y-axis rotation speed by 0.001 units
  case 'h':
    y_speed -= inc;
    println("Y speed: " + y_speed);
    break;
    // 'r' - Reset Z-axis rotation speed to 0
  case 'r':
    z_speed = 0;
    println("Z speed: " + z_speed);
    break;
    // 't' - Reset X-axis rotation speed to 0
  case 't':
    x_speed = 0;
    println("X speed: " + x_speed);
    break;
    // 'y' - Reset Y-axis rotation speed to 0
  case 'y':
    y_speed = 0;
    println("Y speed: " + y_speed);
    break;


  case '3':
    printout = !printout;
    println("Printing is: " + printout);
  default:
    break;
  }
}


void reset() {
  // Reset rotation speeds
  z_speed = 0;
  x_speed = 0;
  y_speed = 0;

  // Reset orbit speeds
  z_orbit_speed = 0;
  x_orbit_speed = 0;
  y_orbit_speed = 0;

  // Reset traversal speed
  trav_speed = 0;

  // Reset translation variables
  trans_x = 0;
  trans_y = 0;
  trans_z = 0;

  // Reset scene eye position
  //scene.eye().reset();
  //scene.eye().setMagnitude(0.57735026);
  //scene.eye().setPosition(new Vector(0, 0, 2000));
  initial.play();
  println(scene.eye());
}

State is a data holder



class State {
  Vector worldPosition;
  Quaternion worldOrientation;
  float worldMagnitude;
  Vector xAxis;
  Vector yAxis;
  Vector zAxis;

  State(Vector worldPosition, Quaternion worldOrientation, float worldMagnitude,
    Vector xAxis, Vector yAxis, Vector zAxis) {
    this.worldPosition = worldPosition;
    this.worldOrientation = worldOrientation;
    this.worldMagnitude = worldMagnitude;
    this.xAxis = xAxis;
    this.yAxis = yAxis;
    this.zAxis = zAxis;
  }


  State(Node node) {
    this.worldPosition = node.worldPosition();
    this.worldOrientation = node.worldOrientation();
    this.worldMagnitude = node.worldMagnitude();
    this.xAxis = node.xAxis();
    this.yAxis = node.yAxis();
    this.zAxis = node.zAxis();
  }

  // Set Node properties with State values
  public void setNodeState(Node node) {
    node.setWorldPosition(worldPosition);
    node.setWorldOrientation(worldOrientation);
    node.setWorldMagnitude(worldMagnitude);
    // Assuming there are methods in Node class to set xAxis, yAxis, and zAxis
    node.setXAxis(xAxis);
    node.setYAxis(yAxis);
    node.setZAxis(zAxis);
  }
}

and Player is the recplay

class Player {
  ArrayList<Node> nodes;
  ArrayList<ArrayList<State>> states;

  // Constructor taking undefined number of nodes
  Player(Node... nodes) {
    this.nodes = new ArrayList<Node>();
    this.states = new ArrayList<ArrayList<State>>();

    for (Node node : nodes) {
      addNode(node);
    }
  }

  // Default constructor
  Player() {
    this.nodes = new ArrayList<Node>();
    this.states = new ArrayList<ArrayList<State>>();
  }

  void addNode(Node node) {
    nodes.add(node);
    states.add(new ArrayList<State>());
  }

  void rec() {
    for (int i = 0; i < nodes.size(); i++) {
      states.get(i).add(new State(nodes.get(i)));
    }
    //println("State recorded for all nodes");
  }

  void play() {
    if (states.isEmpty()) {
      println("No nodes added for state management");
      return;
    }

    for (int i = 0; i < nodes.size(); i++) {
      if (states.get(i).isEmpty()) {
        println("No recorded states available for node " + (i + 1));
      } else {
        State state = states.get(i).remove(0);
        state.setNodeState(nodes.get(i));
        //println("Playbacked state for node " + (i + 1));
      }
    }
  }
  
  void clear() {
    nodes.clear();
    states.clear();
    println("All lists cleared");
  }

  boolean hasNext() {
    return this.states.size() > 0;
  }
}


The whole thing is a bit overcomplicated, can be done in a simpler way depending of your data and etc.
The player class specially makes things a bit convoluted. Dealing with the lists direct in draw is more straightforward.

cheers

Thank you so much for your amazing answer. If I type this I get a millions frames, but I only want one everytime the animation stops, but I don’t want to get it pressing any button, I want the machine doing that without me. So where it has to be written to save an image at the end of every bounce?

Well, that’s a different question. I really did not dig into your code to get how things are done.

But what you need to do is to identify when there is a bounce and trig the save command.

Because when you use # in the name string it does not change how many frames are saved. It only avoids one file to overwrite the previous.

So you were saving one frame each draw loop, and still doing it. Just you stop overwriting them.

Meaning you need to control when you call save()

I’m not sure what you mean by bounce. But, for instance, supposing a bouncing ball, something like this would do the trick:

// pseudo code 
// assume y_position = 0 means it bounces in the floor
if (y_position == 0) {save("frame-###.jpg");}

That would save only at bounces, but wouldn’t overwrite the files.

Makes sense?

: )

In this animation shapes change their position and they stop for two seconds, then they start again and again. I want to save an image everytime shapes are motionless, but I am not able to see in the code when this is happening, could you please help me with that?

i see your solution with a simple animation as



float x =0;
float xDirection =1;

void setup() {
  size(800,1000);
  colorMode(HSB,360,100,100);
  background(360);
 }

void draw(){
  strokeWeight(5);
  background(360);

    stroke(100,100,100);
   x = x + xDirection;
  
  if(x < 0){
    xDirection = - xDirection;
  }
  if(x > width){
    xDirection = - xDirection;
  }
   
  line(x,0,x,height);
}

But in this animation it is not possible for me to resolve where shapes stop and how type that condition to save the frame. So can anybody help me to do it, please?

color[] colors = {
  color(#edb218),
  color(#029cc2),
  color(#6b8c87),
  color(#a5473d),
  color(#588344),
  color(#28312e),
  color(#edb218),
  color(#029cc2),
  color(#6b8c87),
  color(#a5473d),
  color(#588344)
};

ArrayList<Placement> fromPlacements = new ArrayList<Placement>();
ArrayList<Placement> toPlacements = new ArrayList<Placement>();
ArrayList<ShapeDancer> shapeDancers = new ArrayList<ShapeDancer>();

int frames = 150;
PGraphics p;

void setup() {
  size(1000, 1000);
  background(color(238, 235, 211));
  
  float spitA = random(-PI/3, PI/3);
  
  Placement spit = new Placement(spitA, new PVector(width/2, height/2), height*0.03, width*0.8);
  fromPlacements.add(spit);
  
  for(int i = 0; i < 3; i++) {
    spit = new Placement(spitA, new PVector(random(width), random(height)), height*0.02, random(height*0.3, height*0.6));
    fromPlacements.add(spit); 
  }
  
  for(float a = spitA + PI/2 + PI/3; a < spitA + PI/2 + TWO_PI - PI/3; a += PI/12) {
    float d = random(height*0.05, height*0.5);
    float xer = width/2 + cos(PI/2 + a) * d;
    float yer = height/2 + sin(PI/2 + a) * d;
    float her = random(height*0.01, height*0.3);
    float wer = random(height*0.01, height*0.3);
    Placement shape = new Placement(spitA, new PVector(xer, yer), her, wer);
    fromPlacements.add(shape);
  }
  
  spitA = random(-PI/3, PI/3);
  spit = new Placement(spitA, new PVector(width/2, height/2), height*0.03, width*0.8);
  toPlacements.add(spit);
  
  for(int i = 0; i < 3; i++) {
    spit = new Placement(spitA, new PVector(random(width), random(height)), height*0.02, random(height*0.3, height*0.6));
    toPlacements.add(spit); 
  }
  
  for(float a = spitA + PI/2 + PI/3; a < spitA + PI/2 + TWO_PI - PI/3; a += PI/12) {
    float d = random(height*0.05, height*0.5);
    float xer = width/2 + cos(PI/2 + a) * d;
    float yer = height/2 + sin(PI/2 + a) * d;
    float her = random(height*0.01, height*0.3);
    float wer = random(height*0.01, height*0.3);
    Placement shape2 = new Placement(spitA, new PVector(xer, yer), her, wer);
    toPlacements.add(shape2);
  }
  
  //Collections.shuffle(toPlacements, true);
  
  for(int i = 0; i < fromPlacements.size(); i++) {
    shapeDancers.add(new ShapeDancer(i));
  }
  
  p = createGraphics((int)(height * 1.5), height);
  
  for(int i = 0; i < 100000; i++) {
    p.noStroke();
    p.fill(255, (int)random(5, 10));
    //p.ellipse(random(width), random(height), random(1, 3));
  }
}

void draw() {
  blendMode(MULTIPLY);
  clear();
  background(238, 235, 211);

  
  if(frameCount % 300 == 0) {
    fromPlacements = new ArrayList<Placement>(toPlacements);
    toPlacements.clear();
    
    float spitA = random(-PI/3, PI/3);
    Placement spit = new Placement(spitA, new PVector(width/2, height/2), height*0.03, width*0.8);
    toPlacements.add(spit);
    
    for(int i = 0; i < 3; i++) {
      spit = new Placement(spitA, new PVector(random(width), random(height)), height*0.02, random(height*0.3, height*0.6));
      toPlacements.add(spit); 
    }
    
    for(float a = spitA + PI/2 + PI/3; a < spitA + PI/2 + TWO_PI - PI/3; a += PI/12) {
      float d = random(height*0.05, height*0.5);
      float xer = width/2 + cos(PI/2 + a) * d;
      float yer = height/2 + sin(PI/2 + a) * d;
      float her = random(height*0.01, height*0.3);
      float wer = random(height*0.01, height*0.3);
      Placement shape2 = new Placement(spitA, new PVector(xer, yer), her, wer);
      toPlacements.add(shape2);
    }
    
    //Collections.shuffle(toPlacements, true);
  }
  
  for(ShapeDancer shapeDancer : shapeDancers) {
    shapeDancer.dance();
    shapeDancer.show();
  }
  
  push();
  blendMode(BLEND);
  image(p, 0, 0);
  pop();

}

class Placement {
  float between;
  int index;
  float theta;
  PVector pos;
  float h;
  float w;
  String colors;
  
  Placement(float angle, PVector position, float height, float width) {
    between = 0;
    index = 0;
    theta = angle;
    pos = position;
    h = height;
    w = width;
   // colors = colors.get((int)random(colors.size()));
  }
}

class ShapeDancer {
  float between;
  int index;
  float theta;
  PVector pos;
  float h;
  float w;
  String colors;
  
  ShapeDancer(int idx) {
    between = 0;
    index = idx;
    theta = fromPlacements.get(idx).theta;
    pos = fromPlacements.get(idx).pos;
    h = fromPlacements.get(idx).h;
    w = fromPlacements.get(idx).w;
    colors = fromPlacements.get(idx).colors;
  }
  
  void dance() {
    if(frameCount % 300 == 0) {
      between = 0;
    }
    
    float framesMap = map(between, 0, frames, 0, 1);
    pos = PVector.lerp(fromPlacements.get(index).pos, toPlacements.get(index).pos, easeInOutSine(framesMap));
    h = lerp(fromPlacements.get(index).h, toPlacements.get(index).h, easeInOutSine(framesMap));
    w = lerp(fromPlacements.get(index).w, toPlacements.get(index).w, easeInOutSine(framesMap));
    theta = lerp(fromPlacements.get(index).theta, toPlacements.get(index).theta, easeInOutBounce(framesMap));
    
    if(between < frames) {
      between += 1;

    }
  }
  
  
  void show() {
    noStroke();
    fill(0,124,0);
    push();
    rectMode(CENTER);
    translate(pos.x, pos.y);
    rotate(theta);
    rect(0, 0, w, h);
    pop();
  }
}


float easeInOutSine(float x) {
  return -(cos(PI * x) - 1) / 2;
}

float easeOutBounce(float x) {
  float n1 = 7.5625;
  float d1 = 2.75;
  if (x < 1 / d1) {
    return n1 * x * x;
  } else if (x < 2 / d1) {
    return n1 * (x -= 1.5 / d1) * x + 0.75;
  } else if (x < 2.5 / d1) {
    return n1 * (x -= 2.25 / d1) * x + 0.9375;
  } else {
    return n1 * (x -= 2.625 / d1) * x + 0.984375;
  }
}

float easeInOutBounce(float x) {
  if (x < 0.5) {
    return (1 - easeOutBounce(1 - 2 * x)) / 2;
  } else {
    return (1 + easeOutBounce(2 * x - 1)) / 2;
  }
}

Is this not your code?
I can do that, as much as you can.
One needs to understand the code to do that.

To do so you need to follow the execution flow, line by line, function by function. Me or you.

:slight_smile:
I might do so, when i get some time. If I do, I’ll report it here.

Anyways, it’s around the if(frameCount % 300 == 0) i think…
You can add some println() arround to clarify the execution order.

If you could do it it would be fantastic, I would be very grateful, because I only understand some parts of the code, I can’t identify when polygons are motionless to save the image then. There is no hurry, of course I can wait until you have some time. Thanks in advance