Breath Deep

Breath Deep

Sometimes I find myself staring out into space to relive stress and re-center however, lately staring into space hasn’t been enough. So I decided to make my final project an interactive distraction. I wanted to focus on user interaction, making it easy for the user to adjust the output and understand how the changes they were making effected the end result. The ability to re-start the graphic was also important.

Since the UI was an import aspect of this project I wanted to focus on making it easily understandable. My first iteration was not the most user friendly.

In the above version all of the sliders for the starting position of four shapes were grouped together, followed by two sliders that control global variables, followed by sliders for color and stroke for each of the shapes. The order didn’t really make any sense. The other aspect of this interface that I disliked, and pointed out by John Henry, was that the user had to have all the shapes actively on screen. Adding a check-box to allow the user to select what shapes were seen made it so the user had more control over the graphic that was produced.

In the final UI global variables and the ability to re-size and reset the graphic are located at the top of the UI, each shape and all sliders associated with it are grouped together. A check-box turns the shapes on and off. The value is displayed to the right of each slider for those that control the shape’s position.  I didn’t feel like it was necessary to display the vale for the color and stroke since those elements don’t change the way the shapes behave, and the values aren’t important for the user to really understand how the changes to the sliders effect the position and size of the shapes.

Breath Deep
Breath Deep
Breath Deep

The images above show some of the combinations produced with the adjustment of various sliders. The first image is “in-set” with the UI showing under it. The other two images show the graphic as “full-screen”.

I would like to continue the development of this sketch there are a few different ides I would like to implement.

  • I want to be able to mirror the graphic produced into the four quadrants or even make it so the use can determine how many mirrors of the graphic are produced.
  • The ability to save the graphic as an .svg and then plot it out would be a nice added feature. That would enable the user to create permanent works of generated art and not just use this as a tool for relaxation.
  • I would like ta add a slider for each shape that would change the spacing between each new object in the series, to open up the patterning a bit.
  • Add line(), beginShape() and endShape().

The code is long so feel free to skip it and head over to the working sketch found here. https://editor.p5js.org/phil-in-a-can/sketches/d4J4kzzvH

This is the main sketch.

let x1 = 0;
let y1 = 0;
let x2 = 50;
let y2 = 50;
let x3 = 25;
let y3 = 25;
let x4 = 30;
let y4 = 75;
let rep = 2;
let col1 = 10;
let col2 = 100;
let col3 = 200;
let col4 = 300;
let strk1 = 1;
let strk2 = 1;
let strk3 = 1;
let strk4 = 1;
let frmRt = 30
let shape1 = false;
let shape2 = false;
let shape3 = false;
let shape4 = false;
let deg1 = 0.33
let deg2 = 0.33
let deg3 = 0.33
let deg4 = 0.33

function setup() {
  createCanvas(400, 400);
  background(0, 0, 0);
  angleMode(DEGREES);
  colorMode(HSB, 360, 100, 100, 100);
  // rectMode(CENTER);
  // frameRate(frmRt);
  create_ui();
}

function draw() {
  frameRate(frmRt);
  slider_value('Rep', rep);
  slider_value('frmRt', frmRt);
  slider_value('x1', x1);
  slider_value('y1', y1);
  slider_value('Degrees1', deg1);
  slider_value('x2', x2);
  slider_value('y2', y2);
  slider_value('Degrees2', deg2);
  slider_value('x3', x3);
  slider_value('y3', y3);
  slider_value('Degrees3', deg3);
  slider_value('x4', x4);
  slider_value('y4', y4);
  slider_value('Degrees4', deg4);
  noFill();
  translate(width / 2, height / 2);
  // push();

  // rectMode(CENTER);
  if (shape1) {
    ellipseMode(CENTER);
    push();
    // stroke(0, random(0, 85), 0);
    // stroke(85, random(0, 85), 85);
    strokeWeight(strk1);
    stroke(col1, 100, 100, 50);
    rotate(x1 / deg1);
    // rect(x, y, rep * (random(1, 10)), rep * (random(1, 10)));
    // ellipse(t1, t2, 10, t1 + 45);
    ellipse(x1, y1, 10, x1 + 45);
    // rect(x, y, rep * x + 1, y + 5);
    // x = x + 5
    pop();

    x1 = x1 + rep;
    if (x1 > width) {
      x1 = 0;
      y1 = y1 + rep;
    }
  } else {}

  if (shape2) {
    push();
    ellipseMode(CENTER);
    // translate(x*0.33,random(10,200));
    // translate(0, 0);
    rotate(x2 / deg2);
    // fill(0,random(0, 255), 255,0);
    // stroke(85, random(85, 170), 170);
    // stroke(0, random(85, 170), 0);
    strokeWeight(strk2);
    stroke(col2, 100, 100, 50);
    // rotate(x1 / 0.33);
    // ellipse(x1, y1, 10, x1 + 45);
    // circle(x, y, rep * (random(1, 10)));
    ellipse(x2, y2, 20, x2 + 45);
    pop();

    x2 = x2 + rep;
    if (x2 > height) {

      x2 = 0;
      y2 = y2 + rep
    }

  } else {}

  if (shape3) {
    push();
    ellipseMode(CENTER);
    // translate(x*0.33,random(10,200));
    // translate(0, 0);
    rotate(x3 / deg3);
    // fill(0,random(0, 255), 255,0);
    // stroke(0, random(170, 255), 0);
    // stroke(170, random(170, 255), 255);
    strokeWeight(strk3);
    stroke(col3, 100, 100, 50);
    // rotate(x1 / 0.33);
    ellipse(x3, y3, 40, x3 + 45);
    // circle(x, y, rep * (random(1, 10)));
    pop();


    x3 = x3 + rep;
    if (x3 > height * 1.5) {

      x3 = 0;
      y3 = y3 + rep
    }

  } else {}

  if (shape4) {
    push();
    rotate(x4 / deg4);
    strokeWeight(strk4);
    stroke(col4, 100, 100, 50);
    // triangle(0, 0,x4, 20, y4, 75);
    // triangle(30, 75, x2 + 58, y + 20, y1 + 86, y2 + 75);
    triangle(x4, y4, x4 + 100, y4 + 150, x4 + 200, y4 + 250);
    pop();

    x4 = x4 + rep;
    if (x4 > height) {

      x4 = 0;
      y4 = y4 + rep
    }

  } else {}
}

And here is the code for the UI.

function create_ui() {
  createP();
  {
    let a_button = createButton('resize-full');
    a_button.mousePressed(function() {
      resizeCanvas(windowWidth, windowHeight);
      background(0, 0, 0);
    });
    // createP();
  } {
    let a_button = createButton('resize-inset');
    a_button.mousePressed(function() {
      resizeCanvas(400, 400);
      background(0, 0, 0);
    });
    // createP();
  } {
    let a_button = createButton('reset');
    a_button.mousePressed(function() {
      // translate(windowWidth/2,windowHeight/2);
      fill(0);
      rect(-windowWidth / 2, -windowHeight / 2, windowWidth, windowHeight);
    });
    createP();
  } {
    let a_span = createSpan('Rep:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 10, rep, 0.25);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      rep = a_slider.value();
    });
    // createP();
  }{
    let elm = createSpan().id('Rep');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
  } {
    let a_span = createSpan('frmRt:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(10, 100, frmRt);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      frmRt = a_slider.value();
    });
    // createP();
  }{
    let elm = createSpan().id('frmRt');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  }

  //   X1,Y1

  {
    let a_check = createCheckbox('Shape 1', shape1);
    a_check.style('font-size', '25px');
    a_check.style('color:cyan');
    a_check.changed(function() {
      shape1 = this.checked();
    });
    createP();
  } {
    let a_span = createSpan('x1:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 100, x1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      x1 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('x1');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
  } {
    let a_span = createSpan('y1:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 100, y1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      y1 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('y1');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('Degrees:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(-0.99, 0.99, deg1, 0.01);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      deg1 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('Degrees1');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('color 1:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 360, col1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      col1 = a_slider.value();
    });
  } {
    let a_span = createSpan('stroke 1:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 5, strk1);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      strk1 = a_slider.value();
    });
    createP();
  }


  //   x2,y2
  {
    let a_check = createCheckbox('Shape 2', shape2);
    a_check.style('font-size', '25px');
    a_check.style('color:cyan');
    a_check.changed(function() {
      shape2 = this.checked();
    });
  } {
    let a_span = createSpan('x2:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 200, x2);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      x2 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('x2');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
  } {
    let a_span = createSpan('y2:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 200, y2);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      y2 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('y2');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('Degrees:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(-0.99, 0.99, deg2, 0.01);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      deg2 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('Degrees2');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('color 2:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 360, col2);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      col2 = a_slider.value();
    });
    // createP();
  } {
    let a_span = createSpan('stroke 2:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 5, strk2);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      strk2 = a_slider.value();
    });
    createP();
  }


  // x3,y3
  {
    let a_check = createCheckbox('Shape 3', shape3);
    a_check.style('font-size', '25px');
    a_check.style('color:cyan');
    a_check.changed(function() {
      shape3 = this.checked();
    });
  } {
    let a_span = createSpan('x3:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 500, x3);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      x3 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('x3');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
  } {
    let a_span = createSpan('y3:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 500, y3);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      y3 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('y3');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('Degrees:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(-0.99, 0.99, deg3, 0.01);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      deg3 = a_slider.value();
    });
    // createP();
  } {
    let elm = createSpan().id('Degrees3');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('color 3:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 360, col3);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      col3 = a_slider.value();
    });
    // createP();
  } {
    let a_span = createSpan('stroke 3:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 5, strk3);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      strk3 = a_slider.value();
    });
    createP();
  }


  //x4,y4
  {
    let a_check = createCheckbox('Shape 4', shape4);
    a_check.style('font-size', '25px');
    a_check.style('color:cyan');
    a_check.changed(function() {
      shape4 = this.checked();
    });
  } {
    let a_span = createSpan('x4:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 100, x4);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      x4 = a_slider.value();
    });
    // createP();
  }{
    let elm = createSpan().id('x4');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
  } {
    let a_span = createSpan('y4:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 100, y4);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      y4 = a_slider.value();
    });
    // createP();
  }{
    let elm = createSpan().id('y4');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('Degrees:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(-0.99, 0.99, deg4, 0.01);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      deg4 = a_slider.value();
    });
    // createP();
  }{
    let elm = createSpan().id('Degrees4');
    elm.style('font-size', '20px');
    elm.style('color:magenta');
    createP();
  } {
    let a_span = createSpan('color 4:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 360, col4);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      col4 = a_slider.value();
    });
    // createP();
  } {
    let a_span = createSpan('stroke 4:');
    a_span.style('font-size', '20px');
    a_span.style('color:cyan');
    let a_slider = createSlider(0, 5, strk4);
    a_slider.style('width', '200px');
    a_slider.input(function() {
      strk4 = a_slider.value();
    });
  }
}

function slider_value(label, num) {
  let elm = select('#' + label);
  num = round(num, 2);
  // elm.html('[' + label + ' ' + num + '] ');
  elm.html('[' + num + '] ');
}

If you have stuck around this long you aerie a champion, as always please share your thoughts in the comments.