How to make this boxes animation

Hi guys,
This is my first post here and I’m a beginner so I’m happy for you to explain anything you feel is relevant or link me any good resources. I have watched all the Daniel Shiffman (love that guy!) videos.

I’m thinking it might be fun to make a simple animation kinda like the Netflix UI.
Here is a picture:


I just knocked this up in GIMP but how would one go about making some simple boxes like this and then make them kinda rotate around in a circle so the middle one smoothly grows to double size when you click. Maybe make the border light up for the middle one too so it would have to be a rounded corner box inside another rounded corner box I think.

Any ideas? Thanks!

This is how I would do it:

-When you click on the box, translate() to the centre coordinates of that box (making sure you use push and pop matrix round all of this stuff) and rotate the box a set amount each frame. This would be TAU / the number of frames of the animation.

-Then draw the box but make the size the original size + the original size * the frames since the animation started / the number of frames of the animation

-Do the same in reverse when you want to go back again.

Does this work and answer your question?

Also, can you explain what you mean by this:

-The Wizard Bear

P.S. This is my first proper post here too. :grin:

Thanks for your response, I’ll try some of your ideas tomorrow.

The bit about the border lighting up. I just mean the blue border of the box might change to a brighter blue when it becomes the large middle box. So I meant to say, I don’t think it would work as an image, it would be better to use the rectangle function in Processing and layer 2 on top of each other so you could control the colours individually.

Yeah, you could create a variable to keep track of the color–using HSB color mode would make it easier to merge from a blue to a lighter blue.

You said:

but couldn’t you just clear the background and draw another one–especially if you are doing the animation in reverse–(or am I just not understanding your meaning)?

Also, here is a useful link for transformations in Processing.

Well let’s start with the basics: A blanks sketch with a class for just one of these objects that we want to make. And then we add a draw method or this objects so it appears.

class UIBox {
  float a; // Angle on the circle where this box is.
  float da; // Offset for that angle.
  UIBox(float offset_angle) {
    da = offset_angle;
    a = da;
  }
  void draw() {
    fill(0, 0, 200);
    if ( over() ) {
      fill(100, 100, 200);
    }
    noStroke();
    rectMode(CENTER);
    rect(0, 0, 110, 110, 20);
    fill(255);
    rect(0, 0, 100, 100, 20);
  }
  boolean over() {
    return(false);
  }
}

UIBox uibox0;

void setup() {
  size(600, 400);
  uibox0 = new UIBox(0);
}

void draw() {
  background(0);
  pushMatrix();
  translate(width/2, height/2);
  uibox0.draw();
  popMatrix();
}

Then fiddle with it until the effect feels right.

class UIBox {
  float x, dx;
  UIBox(float x_offset) {
    dx = x_offset;
    x = dx;
  }
  void draw() {
    pushMatrix();
    dx = mouseX-300;
    translate(dx,0);
    fill(0, 0, 200);
    if ( over() ) {
      fill(100, 100, 200);
    }
    noStroke();
    rectMode(CENTER);
    scale( map(abs(dx),0,300,2,1));
    rect(0, 0, 110, 110, 20);
    fill(255);
    rect(0, 0, 100, 100, 20);
    popMatrix();
  }
  boolean over() {
    return(false);
  }
}

UIBox uibox0;

void setup() {
  size(600, 400);
  uibox0 = new UIBox(0);
}

void draw() {
  background(0);
  pushMatrix();
  translate(width/2, height/2);
  uibox0.draw();
  popMatrix();
}

And at this point I’m sort of at a loss as to what more you want to do with it. You have a go!

Wow you’ve given me heaps to work with, thank you guys!
I am just watching a youtube video about push and pop matrix.
I remember Dan Shiffman talking about those functions and they’re related to arrays and adding elements? but I can’t remember specifics so I’ll learn it now.

Afterwards I’ll try adding more boxes and making the colours change.
Thanks again!

OK I understand push and pop matrix, they are like a big “start” and “end” on transformations to the Processing coordinate system.

@TfGuy44 - I have a few questions:
So when you instantiate the uibox0, you are passing a value of 0 to the x_offset which in turn is passed to the dx value? Why do you also have x = dx; ?

Also, in your draw function (at the bottom of the code) you translate the coordinate system so 0,0 is in the middle of the sketch. Obviously this works perfectly but I’m a little confused as to how that works?

Also you named the function inside the class “void draw()” is there any advantage to calling it that or would it be OK to call it something else? I’m still so new to programming so I need as little ambiguity as possible :smiley:

Last question, you have used a boolean, presumably as a state? But isn’t it always false? I don’t see any statement where it would change to true?

If you can clear those up, I’d really appreciate it! Thanks!

Put me on the spot…!

Originally I assumed that these boxes would but going in a circle in the x/z plane in 3D. But that’s not the effect you wanted. The weird variables used in the class’s constructor are leftover code from that, and can be simplified/removed. basically, they’re not being used yet. But maybe they might be useful if you have more than one box on the screen at once? I don’t know - I didn’t get/take it that far.

For a row of boxes that scroll horizontally across the screen, the natural choice for an origin point seems like the middle of the sketch. You might disagree - perhaps the center of the left edge would be better. Or you can keep (0,0) at the top left corner like usual. I liked having it in the center because then the “active” box is right in the middle and thus at the origin and thus at the “focus point” of the grid… this made it easy to get the transitional effect I wanted. But it might be a problem when it comes to interacting with this box.

It’s fine to call that function something other than draw(). Popular other choices include display() and render(). Whatever you call it, make sure you change the function name that’s being used inside the main draw() function too! Also: The function is called draw(). The void part is the return type of that function. void means that this function doesn’t return a value.

The UIBox has an over() function that might be useful if you’re trying to determine if the mouse is OVER the UIBox. The existing code in this function is a placeholder - it just assumes the mouse is never over the box, which is fine for placeholder code. You might try implementing this function… but you might have some problems with the way it’s done now, because instead of an absolute position, you’d have to work out where the box is in relation to the transitioned origin… Which is a pain. Anyway, the function that returns the boolean is a placeholder for a proper implementation of a function that determine if the mouse is over the box.

You know, you’ve asked a lot of good questions and it’s clear you’re trying to understand this. So I put a bit more work into it and now you can have a clean working example:

color[] colors = { 
  color(200, 0, 0), 
  color(200, 100, 50), 
  color(200, 200, 0), 
  color(0, 200, 0), 
  color(0, 200, 200),
  color(0, 0, 200), 
  color(200, 0, 200), 
  color(200) 
  };

class UIBoxes {
  boolean moving;
  int startingIndex = colors.length - 2;
  int offset = 0;
  void onDraw() {
    simulate();
    render();
  }
  void simulate() {
    if (offset > 0) {
      offset-=5;
    }
    if ( offset < 0 ) {
      offset+=5;
    }
    if ( offset == 0 ) {
      moving = false;
    }
  }
  void render() {
    for ( int i = 0; i< 5; i++) {
      do_box(i);
    }
    if (!moving) {
      fill(128, 128);
      rectMode(CORNER);
      rect(0, 0, 50, height);
      rect(width-50, 0, 50, height);
    }
  }
  void onClick() {
    if ( moving ) { 
      return;
    }
    moving = true;
    if ( mouseX < 50 ) {
      offset = -200;
      startingIndex--;
      startingIndex += colors.length;
      startingIndex %= colors.length;
    } else if ( mouseX > width - 50 ) {
      offset = 200;
      startingIndex++;
      startingIndex %= colors.length;
    }
  }
  void do_box(int i) {
    fill( colors[(startingIndex+i)%colors.length] );
    noStroke();
    rectMode(CENTER);
    pushMatrix();
    float x = -100 + offset+200*i;
    translate(x, height/2);
    //scale(.8);
    scale( map(abs(width/2-x), 0, width/2, 1.5, 1));
    rect(0, 0, 110, 110, 20);
    fill(255);
    rect(0, 0, 100, 100, 20);
    popMatrix();
  }
} // End class UIBoxes 

// ---

UIBoxes my_uiboxes;

void setup() {
  size(600, 400);
  my_uiboxes = new UIBoxes();
}

void draw() {
  background(0);
  my_uiboxes.onDraw();
}

void mousePressed() {
  my_uiboxes.onClick();
}

I left out the over() check this time. I’m sure you can add it back in to detect clicks on stationary boxes. Please understand this and ask more good questions?

Wow, awesome work. Yes I have some questions :smiley:
The UIBoxes class doesn’t seem to have a constructor? How does that work?
colors.length is 8 right? So why do you initialise the startingIndex variable as colors.length - 2? Why do you want it to start with the value 6? Also in the onClick function, you use %=. I know % is modulo so what is %= ?
What does the simulate() function do exactly?

I think if you can explain those ones to me, I should be able to piece the rest together.
Thank you so much by the way, I really appreciate it.

You are correct: it doesn’t have one. Classes don’t have to have constructor functions. All the variables in the class either take the default values for their type (which is why moving is initially false), or they are given an initial value. Since there’s no need to tell the class any information when creating a new one, I don;t need to pass any arguments into a constructor function either. Basically, I can get away without needing a constructor for this object. If it bothers you, you can certainly write one!

colors.length is 8, yes. I wanted the first color in my colors array to be the first color of the center box. If you dig into this, you’ll see that there are actually 5 boxes drawn at any time. The first is off the left side of the screen, but comes into view when the boxes all move right. The fifth is off the right side of the screen, and comes into view when they move left. If startingAt started at 0, the 5 boxes would be numbered [0,1,2,3,4], and so the middle one would be 2 (which is not the red color I wanted)! But if it’s colors.length - 2, then thy are numbered [(colors.length-2), (colors.length-1), 0, 1, 2]. Which is what I want. It’s not that I want it to start with the value 6. I want it to start at a value that causes the middle box to have index 0. And for a colors array of length 8, that value is 6. If the colors array had more colors in it (say, 300), then I’d still want to pick the valu that would put 0 in the middle (298, or two less than the array’s length!).

%= is shorthand. Instead of doing a = a % b;, you can just do a%=b;. They mean the same thing. This shorthand exists for other simple operations too: a+=b;, a*=b;, a^=b;, and several others…

The simulate() function is what causes the boxes to move. It’s a little sneaky though. It’s not causing them to move TO a new position. It’s only ever causing them to move BACK to their starting positions! See, when the boxes need to move, they don’t all just slide over to a new position. What’s actually happening is that the startingIndex changes immediately, but then all the boxes are given an offset so they only look like they are in the same positions as before. When simulate() sees that there is a non-zero offset, it “corrects” that offset a little bit (and thus the boxes move). When the offset is gone, the boxes have stopped moving.

1 Like

Hey thanks again for the amazing help.
I have a few final questions: How did you make it slide smoothly as opposed to just clicking into place each time?

Also in the onClick function, if I understand the logic correctly, it’s like: startingIndex of 6 is reduced by 1 (so now 5), it becomes 13 when we add on the colors.length and then we mod it by 8 to become 5 again. Is this just a way of avoiding negatives? Was it easier than using abs() or something?

I hope I’m on the right track…

I’ve added/changed a few things to the above code to hopefully get you to see how it works a bit better.

color[] colors = { 
  color(200, 0, 0), 
  color(200, 100, 50), 
  color(200, 200, 0), 
  color(0, 200, 0), 
  color(0, 200, 200), 
  color(0, 0, 200), 
  color(200, 0, 200), 
  color(200) 
};

class UIBoxes {
  boolean moving;
  int startingIndex = colors.length - 2;
  int offset = 0;
  void onDraw() {
    simulate();
    render();
  }
  void simulate() {
    if (offset > 0) {
      offset-=5;
    }
    if ( offset < 0 ) {
      offset+=5;
    }
    if ( offset == 0 ) {
      moving = false;
    }
  }
  void render() {
    for ( int i = 0; i< 5; i++) {
      do_box(i);
    }
    if (!moving) {
      fill(128, 128);
      rectMode(CORNER);
      rect(0, 0, 50, height);
      rect(width-50, 0, 50, height);
    } else {
      fill(255);
      text( offset, 300, 20 );
    }
  }
  void onClick() {
    if ( moving ) { 
      return;
    }
    moving = true;
    if ( mouseX < 50 ) {
      if ( mouseButton == RIGHT ) offset = -200;
      startingIndex--;
      startingIndex += colors.length;
      startingIndex %= colors.length;
    } else if ( mouseX > width - 50 ) {
      if ( mouseButton == RIGHT ) offset = 200;
      startingIndex++;
      startingIndex %= colors.length;
    }
  }
  void do_box(int i) {
    fill( colors[(startingIndex+i)%colors.length] );
    noStroke();
    rectMode(CENTER);
    pushMatrix();
    float x = -100 + offset+200*i;
    translate(x, height/2);
    //scale(.8);
    scale( map(abs(width/2-x), 0, width/2, 1.5, 1));
    rect(0, 0, 110, 110, 20);
    fill(255);
    rect(0, 0, 100, 100, 20);
    fill(0);
    text("box " + i, -30, -10);
    fill(colors[(startingIndex+i)%colors.length]);
    text("index " + (startingIndex+i)%colors.length, -30, 10);    
    popMatrix();
  }
} // End class UIBoxes 

// ---

UIBoxes my_uiboxes;

void setup() {
  size(600, 400);
  my_uiboxes = new UIBoxes();
  textSize(20);
}

void draw() {
  background(0);
  my_uiboxes.onDraw();
}

void mousePressed() {
  my_uiboxes.onClick();
}

First, notice that LEFT CLICK and RIGHT CLICK now do different things when you click the side buttons. Left clicking makes the boxes “jump” instantly. Right clicking also makes the boxes jump instantly, but it ALSO puts in the sneaky offset value that makes it look like the boxes HAVEN’T MOVED YET!

The offset value is now displayed when it is non-zero.

The boxes also have their box number on them (which ranges from 0 to 4), and their color index on them (which ranges from 0 to 7, since there are 8 colors!). Box #2 is the box in the middle. Notice that when they scroll nicely, it breifly becomes box 1 or 3 that is in the middle! Sneaky!

When boxes move instantly, only the startingAt value changes, and thus the index changes. When they move instantly but also get an offset, the BOX NUMBER changes too! Box #2 is always trying to get to the middle…


Hopefully the index numbers let you see what is going on with the colors. You want startingAt (the index of the color of the box off the left edge of the screen) to be a value between 0 and 7 (because, again, there are 8 colors). if it is 0 and you decrease it, you need to go back to 7. You could check for this specific case, or you could just add the array length and then mod by the array length - the effect is the same. If it gets to 8 then you need it to loop around to 0. Modding it here is all that’s needed.

1 Like