# Simulate book pages turning reacting to mouse (bezier)

**URL:** <https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284>\
**Category:** Coding Questions\
**Created:** [April 16, 2024, 1:22am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284 "2024-04-16T01:22:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 16, 2024, 1:22am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/1 "2024-04-16T01:22:43Z")

</div>

I’m trying to create a simulation of book pages that turn left or right depending on where the mouse is. Kind of as if the mouse is the wind and the pages go in its direction one by one.

This is how it should look like:

 ![Screenshot 2024-04-11 alle 16.08.07](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/d/f/df22c6c0e8f26a64bc3941eac376736f18986384.jpeg)

I have been working on this for a couple of days already, but am stuck and don’t know how to proceed from this point on.

This is what I have so far: [p5.js Web Editor](https://editor.p5js.org/slacle/sketches/Mp_Qw0vcJ)

I tried different approaches, and so far using Bezier curves and angles seems to be the best way. But I can’t think of a good way to make the pages move independently and accordingly to their position so that some are more to one side or the other or higher or lower.

I tried using the indexes as a proportion of the x and y positions. The challenge is that it only works left to right or right to left. I can’t think of way for it to be symmetrical. I tried for example reversing the array depending on which side the mouse is, but couldn’t get it to work.

Any ideas that could point me in the right direction? Or if I should consider a complete different approach altogether?

---

<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:** [April 16, 2024, 1:49pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/2 "2024-04-16T13:49:59Z")

</div>

in my opinion you need to move “angle” in the class and calculate it individually for each page (depending on its x-position). **Because each page needs to have its individual angle.**

I tried but you need to improve the calculation of the angle please

That’s this line in the class:

```auto
   this.angle = constrain(map(mouseX, 0, width, -this.xpos, this.xpos), -this.xpos, this.xpos);

```

- we need to pretend this.xpos is the middle of the mouse area or the center of the screen or something

**Code**

```auto
let lines = [];
let halfWidth;
let spacing = 20;
let lineAmount = 15;

function setup() {
  createCanvas(800, 400);
  angleMode(DEGREES);
  noFill();

  halfWidth = width * 0.5;

  for (let i = 0; i < lineAmount; i++) {
    lines.push(new Line(i));
  }
}

function draw() {
  background(color("#1d1419"));

  stroke(200, 0, 0);
  line(halfWidth, 0, halfWidth, height);

  for (const line of lines) {
    line.show();
  }

  // console.log(
  // constrain(
  // floor(map(abs(halfWidth - mouseX), 0, halfWidth, 0, lineAmount - 1)),
  // 0,
  // lineAmount - 1
  // )
  // );
}

class Line {
  constructor(i) {
    this.i = i;
    this.angle = 0;
    this.xpos = 0;
  }

  show() {
    this.xpos = this.i * spacing + (width - (lineAmount * spacing - spacing)) / 2;
    this.angle = constrain(map(mouseX, 0, width, -this.xpos, this.xpos), -this.xpos, this.xpos);

    push();
    translate(
      this.i * spacing + (width - (lineAmount * spacing - spacing)) / 2,
      height
    );

    this.x1 = 0;
    this.y1 = 0;
    this.x1control = this.x1;
    this.y1control = this.y1;

    this.x2 = 300 * cos(this.angle);
    this.y2 = 300 * sin(this.angle);
    this.x2control = this.x2 - 200 * abs(cos(this.angle)) * cos(-this.angle);
    this.y2control = this.y2 - 150 * abs(cos(this.angle)) * sin(-this.angle);

    stroke(color("#f9933e"));
    bezier(
      this.x1,
      this.y1,
      this.x1control,
      this.y1control,
      this.x2control,
      this.y2control,
      this.x2,
      this.y2
    );

    stroke(100);
    line(this.x2, this.y2, this.x2control, this.y2control);

    textSize(12);
    textAlign(CENTER, CENTER);
    fill(200);
    text(this.i, 0, -10);
    pop();
  }
}

```

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 16, 2024, 3:37pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/3 "2024-04-16T15:37:01Z")

</div>

Hey, thanks for the suggestion! And I did consider each line to have it’s own angle.

The thing is that the angle needs to be connected to 180 to 360 somehow, which is the part of the circle that the pages should rotate on. So my idea was to use the index of each page to modify the “main angle”.

For example like this:

```auto
    this.x2 = 200 * cos(angle) + this.index * 10;
    this.y2 = 200 * sin(angle) - this.index * 10;

```

You can see the effect in the editor: [p5.js Web Editor](https://editor.p5js.org/slacle/sketches/99zlShT-n)

I would have to solve the symmetry problem still. Somehow reversing the indexes depending on which side the mouse is.

And to achieve the wind effect I think I might have to use vectors. So I may have to do the angles individually anyway somehow.

---

<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:** [April 16, 2024, 3:56pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/4 "2024-04-16T15:56:07Z")

</div>

I appreciate your reply

Still think individual angle

When the mouse is on the left side, the pages on the legt fall left, the others fall right

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 16, 2024, 4:07pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/5 "2024-04-16T16:07:13Z")

</div>

The thing is they shouldn’t fall below the bottom of the canvas. So no less 180 degrees and no more than 360 degrees. I will see if I find a way to have individual angles while keeping them between the 180-360 degrees.

---

<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:** [April 16, 2024, 4:29pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/6 "2024-04-16T16:29:32Z")

</div>

this looks nice

```auto
let lines = [];
let halfWidth;
let spacing = 20;
let lineAmount = 15;

function setup() {
  createCanvas(800, 400);
  angleMode(DEGREES);
  noFill();

  halfWidth = width * 0.5;

  for (let i = 0; i < lineAmount; i++) {
    lines.push(new Line(i));
  }
}

function draw() {
  background(color("#1d1419"));

  stroke(200, 0, 0);
  line(halfWidth, 0, halfWidth, height);

  for (const line of lines) {
    line.show();
  }

  // console.log(
  // constrain(
  // floor(map(abs(halfWidth - mouseX), 0, halfWidth, 0, lineAmount - 1)),
  // 0,
  // lineAmount - 1
  // )
  // );
}

class Line {
  constructor(i) {
    this.i = i;
    this.angle = 0;
    this.xpos = 0;
  }

  show() {
    this.xpos =
      this.i * spacing + (width - (lineAmount * spacing - spacing)) / 2;

    this.myDist = this.xpos - mouseX;

    this.angle = map(this.myDist, -140, 140, 180, 360);
    this.max1 = 185;
    this.max2 = 357;
    if (this.angle < this.max1) this.angle = this.max1;
    if (this.angle > this.max2) this.angle = this.max2;

    push();
    translate(this.xpos, height);

    this.x1 = 0;
    this.y1 = 0;
    this.x1control = this.x1;
    this.y1control = this.y1;

    this.x2 = 300 * cos(this.angle);
    this.y2 = 300 * sin(this.angle);
    this.x2control = this.x2 - 200 * abs(cos(this.angle)) * cos(-this.angle);
    this.y2control = this.y2 - 150 * abs(cos(this.angle)) * sin(-this.angle);

    stroke(color("#f9933e"));
    bezier(
      this.x1,
      this.y1,
      this.x1control,
      this.y1control,
      this.x2control,
      this.y2control,
      this.x2,
      this.y2
    );

    stroke(100);
    line(this.x2, this.y2, this.x2control, this.y2control);

    textSize(12);
    textAlign(CENTER, CENTER);
    fill(200);
    text(this.i, 0, -10);
    text(this.myDist, -2, -24);

    pop();
  }
}

```

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 16, 2024, 7:31pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/7 "2024-04-16T19:31:03Z")

</div>

@Chrisir that did look much nicer! Although the pages should move in the direction of the mouse 😉

I came up with another idea for giving unique angles to each page. Check it out: [p5.js Web Editor](https://editor.p5js.org/slacle/sketches/Es0_PNcQ9)

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 17, 2024, 5:11am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/8 "2024-04-17T05:11:36Z")

</div>

It’s pretty much working now how I wanted it: [p5.js Web Editor](https://editor.p5js.org/slacle/sketches/GeZqEJ2ZZ)

Now I’m just thinking of ways to optimize it for performance and improve it in general. Any tips/ideas?

---

<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:** [April 17, 2024, 5:29am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/9 "2024-04-17T05:29:39Z")

</div>

My experience is that it’s very hard to optimize code to a result that is visible

Make a copy first

- First thing would be to get rid of push pop and translate.  
You can implement the numbers from translate into the formula you use

- It might be faster to store mouseX in a variable and use this

- You can maybe calculate some numbers that are constant in the constructor (as you did in setup())

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 17, 2024, 4:05pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/10 "2024-04-17T16:05:45Z")

</div>

Thanks for these tips! 🙂

I got rid of push/pop/translate.  
Do they affect performance a lot in general? And probably especially the combination of them together?

Why would storing mouseX in a variable be faster?  
Would it be something like `let mousePositionX = mouseX` ?  
Wouldn’t that be the same thing?

---

<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:** [April 17, 2024, 4:33pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/11 "2024-04-17T16:33:17Z")

</div>

> [@slacle](#):
>
> Do they affect performance a lot in general?

I think so, there is stuff going on behind the screnes

> [@slacle](#):
>
> Why would storing mouseX in a variable be faster?

I once had this and it was faster (imho). Maybe because we need to access the OS only once and working with the stored value is faster than accessing the OS?

> [@slacle](#):
>
> Would it be something like `let mousePositionX = mouseX` ?

Yes.

> [@slacle](#):
>
> Wouldn’t that be the same thing?

See above.

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 17, 2024, 5:24pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/12 "2024-04-17T17:24:10Z")

</div>

Hmm, but I don’t get it. The position of the mouse has to continuously be tracked. So if we save it to a variable it still has to keep accessing the OS to get the value of mouseX to then store it in the variable. Sounds like more work to me really. Am I missing something?

---

<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:** [April 17, 2024, 6:07pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/13 "2024-04-17T18:07:58Z")

</div>

Not my strong area of knowledge

It’s just instead of accessing it twice we only access it once

keep in mind that in this theory mouseX is a different kind of variable than `mousePositionX `

Never mind

When there’s a speed difference it’s probably very small

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [April 18, 2024, 8:08am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/14 "2024-04-18T08:08:19Z")

</div>

> [@slacle](#):
>
> I got rid of push/pop/translate.  
> Do they affect performance a lot in general? And probably especially the combination of them together?

These are very powerful methods that if used correctly will have minimal affect on performance.

You use them in your first [sketch](https://editor.p5js.org/slacle/sketches/99zlShT-n) and examining the code you have made excellent use of them and any loss of performance (if any) will be of the order of nanoseconds.

I strongly recommend using the `push/translate/rotate/scale/pop` methods in this type of situation.

---

<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:** [April 18, 2024, 8:33am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/15 "2024-04-18T08:33:44Z")

</div>

Okay, but when you calculate the positions anyway  
you can as well integrate your translation code into the calculation?

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 18, 2024, 1:26pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/16 "2024-04-18T13:26:02Z")

</div>

It’s true that very often such optimizations have minimal effect. I guess you recommend using these methods to make the code more legible? Or is there any other reason besides making the code easier to read for using them?

I can choose to use between this:

```auto
  show() {
    push();

    translate(this.origin, height);

    this.x = 400 * cos(this.angle);
    this.y = 350 * sin(this.angle);
    this.x2 = this.origin;
    this.y2 = this.y - (100 + sin(this.angle) * 100);

    bezier(0, 0, 0, 0, this.x2, this.y2, this.x, this.y);

    pop();
  }

```

Or this:

```auto
  show() {
    this.x = this.origin + 400 * cos(this.angle);
    this.y = height + 400 * sin(this.angle);
    this.x2 = this.origin;
    this.y2 = this.y - (100 + sin(this.angle) * 100);

    bezier(
      this.origin,
      height,
      this.origin,
      height,
      this.x2,
      this.y2,
      this.x,
      this.y
    );
  }

```

I think they are both about as easy to read. Would you still use push/pop/translate? Or here it would make sense to just leave them out?

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [April 18, 2024, 1:35pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/17 "2024-04-18T13:35:19Z")

</div>

Hello @slacle,

_How can you balance performance and readability in your software code?_

> [@keyPressed() combos - How can I check for UP and SHIFT in a switch()](https://discourse.processing.org/t/keypressed-combos-how-can-i-check-for-up-and-shift-in-a-switch/44148/8):
>
> Hello @vkbr, This was my initial effort: boolean shiftPressed = false; void setup() { background(255, 0, 0); } void draw() { } void keyPressed() { //println(key, keyCode); switch(key) { case 'a': case 'A': println("a or A:", key); break; // Add extra key cases here } switch(keyCode) { case SHIFT: shiftPressed = true; println("shift pressed"); background(0, 255, 0); // or in draw() …

In the end you have to maintain your code and may want to share with others so the decision is yours.

`:)`

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [April 18, 2024, 5:46pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/18 "2024-04-18T17:46:36Z")

</div>

> [@slacle](#):
>
> It’s true that very often such optimizations have minimal effect. I guess you recommend using these methods to make the code more legible? Or is there any other reason besides making the code easier to read for using them?

I am not sure that I would call the `push/translate/rotate/scale/pop` methods optimizations as they are an integral part of 2D/3D graphics programming, in fact anywhere you have distinct, hierarchical graphic elements. I use them extensively in many of my libraries e.g. G4P, Shapes3D, canvasGUI. These libraries would have been much harder to develop and maintain otherwise.

---

<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:** [April 18, 2024, 5:56pm UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/19 "2024-04-18T17:56:25Z")

</div>

Notice that [**push()**](https://processing.org/reference/push_.html) is **pushMatrix()** + **pushStyle()** in Processing:

> **[pushMatrix() / Reference](https://processing.org/reference/pushmatrix_)**
>
> Pushes the current transformation matrix onto the matrix stack. Understanding pushMatrix() and popMatrix() requires understanding the concept of a matrix stack. The pushMatrix() f…

> **[pushStyle() / Reference](https://processing.org/reference/pushstyle_)**
>
> The pushStyle() function saves the current style settings and popStyle() restores the prior settings. Note that these functions are always used together. They allow you to change the sty…

p5js only has **push()**: [reference | p5.js](https://p5js.org/reference/#/p5/push)  
Which stacks lots of information, which might be a tad slow.

---

<div class="post-metadata">

**Author:** ![slacle](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/slacle/32/19522_2.png) [@slacle](https://discourse.processing.org/u/slacle)\
**Post date:** [April 19, 2024, 1:26am UTC](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284/20 "2024-04-19T01:26:58Z")

</div>

I meant NOT using the `push/translate/rotate/scale/pop` methods to be an optimization 😉

But anyway, I’m not an “optimization freak”. I won’t sacrifice code legibility for an unnoticeable gain in performance.

In this case, in my opinion, the legibility is about equal whether using or not using those methods. And the performance is probably going to be just about the same in either case. So I can’t see any extra benefit to either using them or not using them, and don’t see any reason to choose one or the other. So I guess in this case it’s just a matter of personal preference then.

[Next page](https://discourse.processing.org/t/simulate-book-pages-turning-reacting-to-mouse-bezier/44284.md?page=2)
