# How to play a short animation upon interaction (rotate a shape)

**URL:** <https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934>\
**Category:** Coding Questions\
**Created:** [October 10, 2023, 12:26am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934 "2023-10-10T00:26:08Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 10, 2023, 12:26am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/1 "2023-10-10T00:26:08Z")

</div>

Hi all!

I want to rotate a cube about a particular axis through a particular angle every time the user presses the RIGHTARROW key. I want the user to see the rotation happen, starting at its original position and rotating through until it reaches its final position over the course of a couple of seconds. I can do all the necessary math, I just can’t figure out a nice way to have a short animation like that play upon a keyPressed. Is this a bad question? Do I need to be more clear and/or specific?

Oh, I’m doing this in p5.js.

Thank you,

Jack

---

<div class="post-metadata">

**Author:** ![jafal](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/jafal/32/19112_2.png) [@jafal](https://discourse.processing.org/u/jafal)\
**Post date:** [October 10, 2023, 1:26am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/2 "2023-10-10T01:26:32Z")

</div>

Hi  
Hope this helps

> **[p5.js: How to rotate 3D objects on the X, Y, and Z axis - Chris Nielsen Code...](http://bluegalaxy.info/codewalk/2017/12/21/p5-js-how-to-rotate-3d-objects-on-the-x-y-and-z-axis/)**
>
> On the 2D plain of a browser window p5.js can represent 3D space using WEBGL. This is specified as the third argument to the createCanvas() function in the setup portion of the sketch: createCanvas(400, 300, WEBGL); Here is some code that...

[![](https://img.youtube.com/vi/o9sgjuh-CBM/maxresdefault.jpg "How to Rotate Shapes in p5.js (translate, rotate, push, pop)") ](https://www.youtube.com/watch?v=o9sgjuh-CBM)

> **[reference | p5.js](https://p5js.org/reference/#/p5/keyPressed)**
>
> p5.js a JS client-side library for creating graphic and interactive experiences, based on the core principles of Processing.

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 10, 2023, 1:42am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/3 "2023-10-10T01:42:33Z")

</div>

Thank you jafal!

I’m super familiar with these functions, but how would I get an animation like this to start upon a key press and then stop a predetermined number of seconds later? I also need to update some variables at the end of each round of animation.

I’m going to try some simple versions of this on my own so I have code to share, but I hope that clears up my question.

---

<div class="post-metadata">

**Author:** ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)\
**Post date:** [October 10, 2023, 4:34am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/4 "2023-10-10T04:34:25Z")

</div>

Think of it as running in a state machine with a variable that represents your current state. Yours is simple with just two states – stopped or rotating – so you could just represent that with a boolean. You also need to keep track of where you are along the rotation while in the rotating state, which you can do with a counter that starts at however many frames you want the animation to take and tics down by one each frame. When it hits zero, you’re done animating and switch back to the stopped state.

So, in `keyPressed()`, you would set your state variable to rotating (`true`) and set the counter to the number of frames to animate, and set up whatever math you want for your start and end orientations. In `draw()`, if your rotating state variable is `true`, you set the rotation based on the interpolated rotation based on the counter, decrease the counter, and if it hits 0, set the state back to `false` and update your other variables for the new orientation.

In your case, you could even just use the counter as the state variable. If it’s greater than 0, then you are in the rotating state. 0 means you are stopped. `counter / total number of frames` gives you your interpolation variable from 1 to 0 between the start and end orientations.

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 10, 2023, 4:56am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/5 "2023-10-10T04:56:01Z")

</div>

thank you scudly! i am going to take a closer look at this response tomorrow and see what i can come up with. much appreciated.

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [October 10, 2023, 10:00am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/6 "2023-10-10T10:00:13Z")

</div>

> [@jackeddielove](#):
>
> I want the user to see the rotation happen, starting at its original position

I think the basic information here is that Processing

- updates the screen only **once** at the end of `draw()`.

This means that

- using a for-loop for an animation won’t work since the screen is not updated throughout but only at the end of `draw()` - and then your for-loop is already over.

- So, don’t use a for-loop or while-loop for animations but make use of the fact that `draw()` loops in itself 60 times per second automatically, which is perfect for animations.

```auto
void draw() {
  background(0); 
  if(stateVariableAnimate) {
    angle+=0.022; 
  }//if
  showCube(); 
}//func

```

**Easing**

We could also use _easing_, which is a simple technique to slow down an action / animation. In our case we would apply the easing to the change of the angle, here is the example for a ball following the mouse but slowly: [Easing / Examples / Processing.org](https://processing.org/examples/easing.html). Here the easing is for the change of the position I guess.

Chrisir

---

<div class="post-metadata">

**Author:** ![Chrisir](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/chrisir/32/45_2.png) [@Chrisir](https://discourse.processing.org/u/Chrisir)\
**Post date:** [October 11, 2023, 4:12pm UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/7 "2023-10-11T16:12:48Z")

</div>

here is an easing example, the easing happens with the two angles

```auto
// "Demo for Easing"

final String title = "Demo for Easing";
final String helpText = "Use right mouse button (click or drag). Use Escape key.";

final color RED = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE = color(0, 0, 255);
final color YELLOW = color(240, 240, 0);
final color PINK = color(0, 240, 240);

// for the graphical representation, 2 pairs coupled with easing
float angleXThatIs; // current angles, used for displaying the cube
float angleYThatIs;
float angleXDesired; // the angles entered by the mouse (requested by the user)
float angleYDesired;

// --------------------------------------------------------------------
// Core functions

void setup() {
  size(1300, 700, P3D);
}

void draw() {
  background(255);
  lights();

  // read mouse to change angles angleXDesired and angleYDesired ----
  if (mousePressed && mouseButton==RIGHT) {
    angleXDesired=map(mouseY, 0, height, PI, -PI);
    angleYDesired=map(mouseX, 0, width, -PI, PI);
  }
  // calc the current angle angleXThatIs and angleYThatIs with easing (this is done throughout)
  angleXThatIs += (angleXDesired-angleXThatIs)*0.08;
  angleYThatIs += (angleYDesired-angleYThatIs)*0.08;

  // Show the cube/scene -----------------
  showCube();

  // HUD ---------------------------------
  HUD(); // The Texts
}

// --------------------------------------------------------------------
// Input functions

// (mouse is read in draw())

void keyPressed() {
  if (key==ESC) {
    // reset view
    angleXDesired=0;
    angleYDesired=0;
    key=0; // kill Esc
  }
}

// --------------------------------------------------------------------
// Other functions

void showCube() {
  //
  pushMatrix();
  translate (width/2, height/2+98);

  rotateX(angleXThatIs); // use angles / ESC resets
  rotateY(angleYThatIs);

  fill(RED);
  stroke(111);
  box(100); // main box

  // 4 decorations cubes
  smallCubeRelativePos(0, -65, 0, GREEN); // Top
  smallCubeRelativePos(0, 65, 0, PINK); // Bottom

  smallCubeRelativePos(65, 0, 0, BLUE); // right
  smallCubeRelativePos(-65, 0, 0, YELLOW); // left

  popMatrix();
}

void smallCubeRelativePos (float x_, float y_, float z_,
  color col_) {

  // draws a small Cube from a Relative Pos x,y,z and color col

  pushMatrix();
  translate(x_, y_, z_);
  fill(col_);
  box(28);
  popMatrix();
}

void HUD() {
  // Head-up-Display (HUD)
  camera() ;
  noLights();

  // TOP Text
  // Title
  textSize(32);
  textAlign(CENTER, CENTER);
  fill(0);
  text (title, width / 2, 30);

  // Help
  textSize(14);
  text (helpText, width / 2, 90);

  // reset
  textAlign(LEFT);
}
//

```

* * *

**New version**

New version, in which first angle x is handled, and afterwards angle y

- Visually, this makes it easier to understand what’s going on.

- It’s especially good when clicking Escape key or click the mouse right button

- It’s less good when dragging the mouse since the rotation is not complete

```auto

// "Demo for Easing"

final String title = "Demo for Easing";
final String helpText = "Use right mouse button (click or drag). Use Escape key.";

final color RED = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE = color(0, 0, 255);
final color YELLOW = color(240, 240, 0);
final color PINK = color(0, 240, 240);

// for the graphical representation, 2 pairs coupled with easing
float angleXThatIs; // current angles, used for displaying the cube
float angleYThatIs;
float angleXDesired; // the angles entered by the mouse (requested by the user)
float angleYDesired;

// --------------------------------------------------------------------
// Core functions

void setup() {
  size(1300, 700, P3D);
}

void draw() {
  background(255);
  lights();

  // read mouse to change angles angleXDesired and angleYDesired ----
  if (mousePressed && mouseButton==RIGHT) {
    angleXDesired=map(mouseY, 0, height, PI, -PI);
    angleYDesired=map(mouseX, 0, width, -PI, PI);
  }

  // calc the current angles
  // we start with angle X
  // println(abs(angleXDesired-angleXThatIs));
  // calc the current angle angleXThatIs with easing (this is done throughout)
  angleXThatIs += (angleXDesired-angleXThatIs)*0.08;
  // below a certain value we stop x
  if (abs(angleXDesired-angleXThatIs)<0.02)
    angleXThatIs = angleXDesired;

  // when x is done, we start y
  if (abs(angleXDesired-angleXThatIs) == 0.0) {
    // calc the current angle angleYThatIs with easing (this is done throughout)
    angleYThatIs += (angleYDesired-angleYThatIs)*0.08;
    // below a certain value we stop y
    if (abs(angleYDesired-angleYThatIs)<0.02)
      angleYThatIs = angleYDesired;
  }

  // Show the cube/scene -----------------
  showCube();

  // HUD ---------------------------------
  HUD(); // The Texts
}

// --------------------------------------------------------------------
// Input functions

// (mouse is read in draw())

void keyPressed() {
  if (key==ESC) {
    // reset view
    angleXDesired=0;
    angleYDesired=0;
    key=0; // kill Esc
  }
}

// --------------------------------------------------------------------
// Other functions

void showCube() {
  //
  pushMatrix();
  translate (width/2, height/2+98);

  rotateX(angleXThatIs); // use angles / ESC resets
  rotateY(angleYThatIs);

  fill(RED);
  stroke(111);
  box(100); // main box

  // 4 decorations cubes
  smallCubeRelativePos(0, -65, 0, GREEN); // Top
  smallCubeRelativePos(0, 65, 0, PINK); // Bottom

  smallCubeRelativePos(65, 0, 0, BLUE); // right
  smallCubeRelativePos(-65, 0, 0, YELLOW); // left

  popMatrix();
}

void smallCubeRelativePos (float x_, float y_, float z_,
  color col_) {

  // draws a small Cube from a Relative Pos x,y,z and color col

  pushMatrix();
  translate(x_, y_, z_);
  fill(col_);
  box(28);
  popMatrix();
}

void HUD() {
  // Head-up-Display (HUD)
  camera() ;
  noLights();

  // TOP Text
  // Title
  textSize(32);
  textAlign(CENTER, CENTER);
  fill(0);
  text (title, width / 2, 30);

  // Help
  textSize(14);
  text (helpText, width / 2, 90);

  // reset
  textAlign(LEFT);
}
//

```

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 13, 2023, 1:35am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/8 "2023-10-13T01:35:50Z")

</div>

How does this look? It does what I want, but is it clunky? Is there anything to clean up? An important feature I need is that the square rotates through an additional PI/4 every time the right arrow is pressed, hence the ‘rotations’ variable keeping track of how many times it’s been pressed.

```auto
function setup() {
  createCanvas(400, 400);
  countdown = 100;
  rotations = 0;
  animate = false;
}

function keyPressed() {
  if (keyCode === RIGHT_ARROW) {
    animate = true;
    countdown = 100;
  }
}

function draw() {
  background(220);
  push();
  translate(width / 2, height / 2);
  if (animate == true) {
    rotate((rotations + (100 - countdown) / 100) * (PI / 4));
    rect(0, 0, 100, 100);
    countdown--;
  } else {
    rotate(rotations * (PI / 4));
    rect(0, 0, 100, 100);
  }
  pop();
  if (countdown == 0) {
    animate = false;
    rotations++;
    countdown = 100;
  }
}

```

---

<div class="post-metadata">

**Author:** ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)\
**Post date:** [October 13, 2023, 2:39am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/9 "2023-10-13T02:39:45Z")

</div>

One caution any time you are doing division is whether you want your result to be an integer or a float. If you divide an integer by another integer, the result will be an integer. In this case, though, you want

```auto
(100 - countdown) / 100

```

to be a float between `0.0` and `1.0`. If the calculation is done on integers, you can only get a value of `0` or `1`, but nothing in between. To ensure a `float` result, you want at least one of those values in the expression to be a `float`. You don’t show your declaration for `countdown`. If it’s a `float`, you’ll be good. Alternatively, leave it as an `int` and change the `100`s to `100.0`.

Another problem is that you only want to check for the transition from rotating to stopping while you are rotating and not the rest of the time. That means your final check of `if (countdown == 0) {` should only be done inside the `if` block when `animate == true`. So move that whole second if block up to just below the `countdown--;` statement inside the first if block.

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 13, 2023, 3:22am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/10 "2023-10-13T03:22:19Z")

</div>

this is great, thank you. it performs the same before and after i make the changes you suggest, so i guess p5 is treating countdown as a float. i guess also that, although the performance looks the same to me, p5 has much less work to do if it’s not checking whether countdown equals 0 every time it runs through the code.

again, thank you

---

<div class="post-metadata">

**Author:** ![scudly](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/scudly/32/5597_2.png) [@scudly](https://discourse.processing.org/u/scudly)\
**Post date:** [October 13, 2023, 4:14am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/11 "2023-10-13T04:14:01Z")

</div>

Ah, right. You’re in javascript where every number is a float. I forgot.

The other reason you need to keep the `countdown == 0` check inside the first `if` is that you increase the `rotations` variable each time, so your object would continue rotating by `PI/4` every frame. Try drawing a triangle instead of a square to see what happens if you don’t move it.

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 13, 2023, 4:20am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/12 "2023-10-13T04:20:58Z")

</div>

I thought about that issue, which is why I changed countdown to 100 after I incremented rotations. But I see now that I don’t need to do that extra step if I keep that conditional inside the other conditional.

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 13, 2023, 4:24am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/13 "2023-10-13T04:24:35Z")

</div>

Here’s the finished product. RIGHTARROW rotates about one of the axes, UPARROW rotates about the other. Would love for you to try it out and tell me what you think.

```auto
function setup() {
  createCanvas(700, 700, WEBGL);

  //constants for drawing the tetrapod

  s = 50;
  l = sqrt(8 / 3) * s;

  //variables for animating

  vAnimate = false;
  eAnimate = false;
  vCountdown = 100;
  eCountdown = 100;
  vAxis = createVector(1, 1, 1);
  eAxis = createVector(1, 0, 0);

  //indexing parts of the tetrapod to use in for-loop

  hub = [
    [1, 1, 1],
    [-1, -1, 1],
    [1, -1, -1],
    [-1, 1, -1],
    [1, 1, -1],
    [1, -1, 1],
    [-1, 1, 1],
    [-1, -1, -1],
  ];
  feet = [
    [-1, -1, -1],
    [1, 1, -1],
    [-1, 1, 1],
    [1, -1, 1],
  ];

  //colors for the legs and feet

  colors = ["#F500D3", "#FFBC00", "#019AFF", "#41F501"];
}

//interaction

function keyPressed() {
  if (keyCode === RIGHT_ARROW) {
    vAnimate = true;
    vCountdown = 100;
  }

  if (keyCode === UP_ARROW) {
    eAnimate = true;
    eCountdown = 100;
  }
}

function draw() {
  background(220);
  orbitControl();

  push();

  // draw rotation axes
  strokeWeight(3);
  line(-500, 0, 500, 0);
  line(-500, -500, -500, 500, 500, 500);

  //rotate about vAxis

  if (vAnimate == true) {
    rotate((((100 - vCountdown) / 100.0) * 2 * PI) / 3, vAxis);
    for (i = 0; i <= 3; i++) {
      strokeWeight(1);
      //HUB
      fill(255);
      beginShape();
      vertex(s * hub[i][0], 0, 0);
      vertex(0, s * hub[i][1], 0);
      vertex(0, 0, s * hub[i][2]);
      endShape(CLOSE);

      //LEGS
      fill(color(colors[i]));
      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(0, feet[i][1] * s, 0);
      vertex(feet[i][0] * s, 0, 0);
      endShape(CLOSE);

      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      vertex(0, 0, feet[i][2] * s);
      vertex(feet[i][0] * s, 0, 0);
      endShape(CLOSE);

      beginShape();
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      vertex(0, 0, feet[i][2] * s);
      vertex(0, feet[i][1] * s, 0);
      endShape(CLOSE);

      //FEET
      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      endShape(CLOSE);
    }
    vCountdown--;
    if (vCountdown == 0) {
      vAnimate = false;
      colors = [colors[0], colors[3], colors[1], colors[2]];
    }
  }

  //rotate about eAxis
  else if (eAnimate == true) {
    rotate(((100 - eCountdown) / 100.0) * PI, eAxis);
    for (i = 0; i <= 3; i++) {
      strokeWeight(1);
      //HUB
      fill(255);
      beginShape();
      vertex(s * hub[i][0], 0, 0);
      vertex(0, s * hub[i][1], 0);
      vertex(0, 0, s * hub[i][2]);
      endShape(CLOSE);

      //LEGS
      fill(color(colors[i]));
      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(0, feet[i][1] * s, 0);
      vertex(feet[i][0] * s, 0, 0);
      endShape(CLOSE);

      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      vertex(0, 0, feet[i][2] * s);
      vertex(feet[i][0] * s, 0, 0);
      endShape(CLOSE);

      beginShape();
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      vertex(0, 0, feet[i][2] * s);
      vertex(0, feet[i][1] * s, 0);
      endShape(CLOSE);

      //FEET
      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      endShape(CLOSE);
    }
    eCountdown--;
    if (eCountdown == 0) {
      eAnimate = false;
      colors = [colors[2], colors[3], colors[0], colors[1]];
    }
  }

  //draw shape in current orientation
  else {
    for (i = 0; i <= 3; i++) {
      strokeWeight(1);
      //HUB
      fill(255);
      beginShape();
      vertex(s * hub[i][0], 0, 0);
      vertex(0, s * hub[i][1], 0);
      vertex(0, 0, s * hub[i][2]);
      endShape(CLOSE);

      //LEGS
      fill(color(colors[i]));
      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(0, feet[i][1] * s, 0);
      vertex(feet[i][0] * s, 0, 0);
      endShape(CLOSE);

      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      vertex(0, 0, feet[i][2] * s);
      vertex(feet[i][0] * s, 0, 0);
      endShape(CLOSE);

      beginShape();
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      vertex(0, 0, feet[i][2] * s);
      vertex(0, feet[i][1] * s, 0);
      endShape(CLOSE);

      //FEET
      beginShape();
      vertex(feet[i][0] * (s + l), feet[i][1] * l, feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * (s + l), feet[i][2] * l);
      vertex(feet[i][0] * l, feet[i][1] * l, feet[i][2] * (s + l));
      endShape(CLOSE);
    }
  }

  pop();
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [October 13, 2023, 5:14am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/14 "2023-10-13T05:14:26Z")

</div>

Another cube rotating example: 🧊

https://OpenProcessing.org/sketch/2043104/embed/

---

<div class="post-metadata">

**Author:** ![jackeddielove](https://avatars.discourse-cdn.com/v4/letter/j/dc4da7/32.png) [@jackeddielove](https://discourse.processing.org/u/jackeddielove)\
**Post date:** [October 13, 2023, 6:01am UTC](https://discourse.processing.org/t/how-to-play-a-short-animation-upon-interaction-rotate-a-shape/42934/15 "2023-10-13T06:01:58Z")

</div>

very helpful, thank you!
