Ass­i­g­n­m­e­n­t 2

by Giselle Gray

//It should be noted that because there are so many sketches in this document, it can be quite laggy and slow. Please feel free to copy any sketchcodes and run it in processing/peep IDE as this is not normal behaviour and runs fine on its own.

//It also should be noted that the correct font is only being displayed on the peep website (I emailed asking about this issue and was told if it works in peep it will work, but when I opened it up the font was not working!) for this reason this is the link to my submission on peep with the working fonts --> (click here!)

Background Research, Inspiration and Response to Design Brief

Before I started this assignment I felt that I needed to understand the ethos of the Design Lab. The Design Lab focuses on:

  • Human centred design
  • Innovative solutions
  • Use of digital products

(From The University of Sydney Website)

With this in mind, I went to the Wilksonson Building (where the Design Lab is located) to see how other areas in the building were represented. I thought this was a good way for me to think about the design in context- it would help me to create a design that is consistent with the rest of the building & structures therein but also something that was easily distinguished.

I saw the DMAF lab's lit up sculpture above the entrance as well as the lighting lab's changing colour wall.

Alt text

(From Web: Australian Photos)

Click here to see photographs of Lighting Lab and DMAF lab structure hotos

I made note of their use of simple geometric shapes/lines. For the DMAF lab, the sculpture was lit up; lines were connected and the places they were connected were unlit. The number of lines that were connected varied. The lighting Lab's wall was made of straight, untouching zig zagging lines that were cut into the wall. There were tiny colour changing lights embedded into the lines.

The DMAF sculpture was lit up but unchanging. The lighting lab's wall changed colours - even though the physical design did not change, the colours allowed it to portray different emotions and feeling.

I liked how node-like corners were made in the DMAF sculture with varying number of lines - I wanted to implement something similar into my design. I also liked how the lighting lab had little lights embedded. I wanted to create something that utilised straight lines forming connections and thought I could make the corners form nodes.

From this research I decided to pursue a design with a focus on interaction and connectivity which can be represented by a network of moving and connecting nodes. Many connections will be made between each node.

Alt text

(From Web: Jon Lieff MD)

For me it symbolises neural connections being made through innovation and discovery of new things and it also works well as a representation of the constant interaction between individuals that collaborate together to form a hub or network of information and knowledge which is what the Design Lab aims to do. This knowledge made available through the Design Lab is not just reserved to be used in a specific area, but can also be applicable to any and every industry. In order to align with the human centred design mission of the Design Lab, I wanted it so that people could actually interact with and change the design. To do this I decided that the mouse would be able to guide the "nodes" forming connections. It's like a flashlight shining in the dark. The design can also be changed to having no nodes by clicking. It's also quite reminescent of stars and star maps which can be used to make sense of the universe around us.

Code Experimentation

The initial sketch I came up with was static and was just an experiment to test whether or not what I was trying to do was possible. It was hard to envision what the sketch would look like once motion was added, but I played around with it and found this was the best way to start off. I made use of a class for my node in order to be able to reuse the same code for multiple 'nodes'. The class will be responsible for mangaging the position, movement and rendering of each node. Making use of an array to contain all the nodes allows me to have any number of nodes without having to make any changes but specifying a different length. I also added a 'neighbours' array to each property to store the nodes that are within a certain range around that node. When this sketch is refreshed, the position of nodes as well as the number of connections changes.

  • Show Code
/** @peep sketch */
int NUMBER_NODES = 200;
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  frameRate(10);
 
  // Create an array of nodes
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  // Find neighbouring nodes of each node 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
void draw() {
  // Execute the draw method of each node
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
}
 
// Class to represent each node
class Node {
  // Each node has an id, position, radius and neighbours
  float id;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  // Constructor to set initial values of node's property
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    radius = random(10);
  }
 
  void findNeighbours() {
    // Loop through all nodes, if node isn't current node
    // and the distance between the two nodes is within a range
    // then add the node to the neighbours property
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 6 &&
            abs(nodes[i].y - y) < height / 6) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
  }
 
  // Draws circle at node poition and draws line connecting to neighbours of node
  void draw() {
    ellipse(x, y, radius, radius);
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}

When I was playing with motion the nodes moved around and stayed connected to their neighbours but did not create new connections. The movement was good, a little eerie but getting there. I achieved the movement effect by using the 'easing' technique we were shown in one of the tutorial. Each node has an initial position that it can wander from for a set distance.

  • Show Code
/** @peep sketch */
int NUMBER_NODES = 200;
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  //frameRate(10);
 
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
void draw() {
  background(0);
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
}
class Node {
  // Added properties to represent starting position and destination
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(5, 15);
 
  }
 
  // Function to set the destination position a random value based on the nodes starting position
  void refreshDestination() {
    destinationX = startX + random(50);
    destinationY = startY + random(50);
  }
 
  // Function to calculate the node's current position using 'easing'
  void calculatePosition() {
    x += (destinationX - x) * 0.1;
    y += (destinationY - y) * 0.1; 
  }
 
  void findNeighbours() {
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 8 &&
            abs(nodes[i].y - y) < height / 8) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
  }
 
  void draw() {
    // If node's current position is within a certain range of destination, refresh destination position
    if (abs(destinationX - x) < 1 &&
        abs(destinationY - y) < 1) {
      refreshDestination();
    }
    // Calculate current position
    calculatePosition();
    ellipse(x, y, radius, radius);
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.1);
        stroke('white');
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}

I then played around with mouse movement to make the sketch interactive (an important aspect of the Design Lab). I played around with opacity so it was like a torch light shining. The closer the nodes were to the mouse the more 'lit up' they were. I also played with the opacity of the nodes: they needed to be less like little circles moving around. I wanted it to be obvious that it was a point of connection - I also increased the number of connections each node made.

The product was something a bit spidery and creepy which I put down to the number of nodes and connections being too large. Apart from that I thought it was going pretty well.

  • Show Code
/** @peep sketch */
// Added more global variables to control various values
int NUMBER_NODES = 250;
int NODE_TERRITORY_RADIUS_HIGH = 60;
int NODE_TERRITORY_RADIUS_LOW = -60;
int EASING = 0.01;
 
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  //frameRate(10);
 
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
 
void draw() {
  background(0);
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
}
 
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(5, 12);
 
  }
 
  // Changes values to create a 'territory' the node can explore around its starting position
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  // Added global variable easing
  void calculatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  // Changed function to only find two neighbours per node
  void findNeighbours() {
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 8 &&
            abs(nodes[i].y - y) < height / 8) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
  }
 
  void draw() {
    if (abs(destinationX - x) < 1 &&
        abs(destinationY - y) < 1) {
      refreshDestination();
    }
    calculatePosition();
 
    // Checked distance of node's current position to the mouse
    // If further than certain range the node is made transparent
    // If closer then it is given more opacity correlating to the distance
    float distance = dist(mouseX, mouseY, x, y);
    if (distance > 255) {
      fill(255, 255, 255, 0);
      stroke(255, 255, 255, 0);
    } else {
      fill(255, 255, 255, 255 + -1 * distance);
      stroke(255, 255, 255, 255 + -1 * distance);
    }
    ellipse(x, y, radius, radius);
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}

In this iteration I added the text (didn't yet load the perscribed font). I made a conscious decision that in order to be less distacting, the text; Design Lab should be static, large and easily read. I really thought it would have too much going on and way too much of a distraction if I played around with it. The animation should add to the design, but it's not soley what the banner is about. I wanted the text to be easily read so it is obvious what it is. The animation being more transparent then the text also brought the text to the foreground of the canvas. In this iteration the nodes move and are able to form connections, but the number of connections were decreased from the previous iteration to make it less creepy and more symbolic of the formation of connections and interactions. I also made it so that when the design was clicked, the nodes disappear and just show lines connecting: I did this to make it interactive with the person playing with it so it can be centred around the user and what they prefer. I found that this sketch was not rescaleable (as can be seen the text is not fully shown). When I ran the sketch on smaller canvases not only was the text affected, but the number of nodes were too plenty. I had to make the size of the text as well as the size and number of nodes dependant on the canvas size instead of an arbitrary number. Another issue I thought of was that the animation depended on someone playing with it. If the design were to be on a screen somewhere nothing would happen as there wouldn't be a person moving the mouse to create the movement.

  • Show Code
/** @peep sketch */
int NUMBER_NODES = 200;
int NODE_TERRITORY_RADIUS_HIGH = 50;
int NODE_TERRITORY_RADIUS_LOW = -50;
int EASING = 0.01;
int circlesOn = true;
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  //frameRate(10);
  smooth(40);
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
 
void draw() {
  background(0);
  fill(255);
  stroke(0);
  textSize(72);
  // Added text to be drawn
  text("DESIGN LAB", width/2, height/2); 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
}
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(6);
 
  }
 
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  void calculatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  void findNeighbours() {
    neighbours = null;
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 12 &&
            abs(nodes[i].y - y) < height / 12) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
 
    if (neighbours != null) {
      radius = 2 * neighbours.length;
    } else {
      radius = 0; 
    }
  }
 
  void draw() {
    if (abs(destinationX - x) < 1 &&
        abs(destinationY - y) < 1) {
      refreshDestination();
    }
    calculatePosition();
    findNeighbours();
    float distance = dist(mouseX, mouseY, x, y);
    if (distance > 170) {
      fill(255, 255, 255, 0);
      stroke(255, 255, 255, 0);
    } else {
      fill(255, 255, 255, 255 + -1.5 * distance);
      stroke(255, 255, 255, 255 + -1.5 * distance * 2);
    }
    // Checking to see whether circles should be displayed
    if (circlesOn) {
      ellipse(x, y, radius, radius);
    }
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
}
// Upon mouse click toggle visibility of circles
void mouseClicked() {
 circlesOn = !circlesOn; 
}

In this iteration I fixed the sizing problems by having the size of the text and the size and number of nodes/connection depend on the size of the canvas (by using the width and height in the calculations). I also made it so that if the mouse was stationary for a certain amount of drawing 'cycles', the animation would begin to randomly move around on the canvas, but if the mouse were to move again then the animation would go back to being controlled by the movements of the mouse. I experimented with colour and decided that if I were to use yellow I'd use it on the animation. I only used yellow because I thought I had to, if we don't need to use yellow, I prefer it with a black background and white text as well as white nodes.

  • Show Code
/** @peep sketch */
/* @pjs font=http://peepproject.com/uploads/16100/controllertwo.otf; */
int NUMBER_NODES = 250;//increased by 50, as sometimes the number of nodes was too sparse
int NODE_TERRITORY_RADIUS_HIGH = 50;
int NODE_TERRITORY_RADIUS_LOW = -50;
float EASING = 0.01;
int CYCLES_BEFORE_STATIONARY = 200;
int TORCH_DISTANCE = 170;
boolean circlesOn = true;
float shownX = 0;
float shownY = 0;
float shownDestinationX = 0;
float shownDestinationY = 0;
float previousMouseX = 0;
float previousMouseY = 0;
int mouseStationaryCycles = 0;
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  //frameRate(10);
  // Added custom font
  PFont font = createFont("http://peepproject.com/uploads/16100/controllertwo.otf", 32);
  textFont(font);
  smooth(40);
  // Modified certain variables to change depending on canvas size
  TORCH_DISTANCE = width / 5;
  NUMBER_NODES = max(width * height / 2700, 100);
 
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
 
// The following two functions replicate the functions with the same name
// in the node class but change different variables
void refreshShownDestination() {
  shownDestinationX = random(width);
  shownDestinationY = random(height);
}
 
void updateShownPosition() {
  shownX += (shownDestinationX - shownX) * EASING * random(0.5);
  shownY += (shownDestinationY - shownY) * EASING * random(0.5); 
}
 
void draw() {
  background(0);
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
 
  fill(255);
  stroke(0);
  // Modified size based on the canvas size
  textSize(72/900*width);
  // Aligned in center so that text remains in middle of screen
  textAlign(CENTER);
  text("DESIGN LAB", width/2, height/2); 
 
  // Checks if the current mouse position is equal to the previous
  if (previousMouseX == mouseX 
    && previousMouseY == mouseY) {
    // Checks if the number of 'stationary cycles' is less than the global variable
    if (mouseStationaryCycles <= CYCLES_BEFORE_STATIONARY) {
      // Sets the uncovered area or 'shown' position to the current mouse position
     shownX = mouseX;
     shownY = mouseY;
    }
 
    // Increments the number of stationary cycles
    mouseStationaryCycles++;
  } else {
    // Resets stationary cycles as mouse has moved
    mouseStationaryCycles = 0;
  }
 
  // Sets previous mouse position to current mouse position
  previousMouseX = mouseX;
  previousMouseY = mouseY;
 
  // If unconvered destinatin is within certain range, refresh destination
  if (abs(shownDestinationX - shownX) < 10 &&
        abs(shownDestinationY - shownY) < 10) {
      refreshShownDestination();
    }
  // Update the currently unconvered area
  updateShownPosition();
 
}
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(6);
 
  }
 
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  void updatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  void findNeighbours() {
    neighbours = null;
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 12 &&
            abs(nodes[i].y - y) < height / 12) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
 
    if (neighbours != null) {
      radius = 2 * neighbours.length;
    } else {
      radius = 0; 
    }
  }
 
  void draw() {
    if (abs(destinationX - x) < 1 &&
        abs(destinationY - y) < 1) {
      refreshDestination();
    }
    updatePosition();
    findNeighbours();
    float distance = dist(mouseX, mouseY, x, y);
    if (mouseStationaryCycles > CYCLES_BEFORE_STATIONARY) {
      distance = dist(shownX, shownY, x, y);
    }
    if (distance > TORCH_DISTANCE) {
      fill(255, 255, 0, 0);
      stroke(255, 255, 0, 0);
    } else {
      fill(255, 255, 0, 0 + -1.5 * distance);
      stroke(255, 255, 0, 0 + -1.5 * distance * 2);
    }
 
    if (circlesOn) {
      ellipse(x, y, radius, radius);
    }
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}
void mouseClicked() {
 circlesOn = !circlesOn; 
}

Final Product & size variants

For the final product I was able to optimise the code. As shown it is rescalable, and a black and white variant is also shown! It is generative - it doesn't repeat and I think it encompasses the the values of the Design Lab well.

  • Show Code
/** @peep sketch */
/* @pjs font=http://peepproject.com/uploads/16100/controllertwo.otf; */
int NUMBER_NODES = 250;
int NODE_TERRITORY_RADIUS_HIGH = 50;
int NODE_TERRITORY_RADIUS_LOW = -50;
float EASING = 0.01;
int CYCLES_BEFORE_STATIONARY = 200;
int TORCH_DISTANCE = 170;
boolean circlesOn = true;
float shownX = 0;
float shownY = 0;
float shownDestinationX = 0;
float shownDestinationY = 0;
float previousMouseX = 0;
float previousMouseY = 0;
int mouseStationaryCycles = 0;
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  //frameRate(10);
  PFont font = createFont("http://peepproject.com/uploads/16100/controllertwo.otf", 32);
  textFont(font);
  smooth(40);
  TORCH_DISTANCE = width / 5;
  NUMBER_NODES = max(width * height / 2000, 150);
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
void refreshShownDestination() {
  shownDestinationX = random(width);
  shownDestinationY = random(height);
}
void updateShownPosition() {
  shownX += (shownDestinationX - shownX) * EASING * random(0.5);
  shownY += (shownDestinationY - shownY) * EASING * random(0.5); 
}
void draw() {
  background(0);
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
 
  fill(255);
  stroke(0);
  textSize(72/900*width);
  // Vertically centered too
  textAlign(CENTER, CENTER);
  text("DESIGN LAB", width/2, height/2); 
 
  if (previousMouseX == mouseX 
    && previousMouseY == mouseY) {
      if (mouseStationaryCycles <= CYCLES_BEFORE_STATIONARY) {
       shownX = mouseX;
       shownY = mouseY;
      }
    mouseStationaryCycles++;
  } else {
    mouseStationaryCycles = 0;
  }
 
  previousMouseX = mouseX;
  previousMouseY = mouseY;
 
  // Changed to using 'dist' function for cleaner code
  if (dist(shownDestinationX, shownDestinationY, shownX, shownY) < 10) {
      refreshShownDestination();
    }
  updateShownPosition();
 
}
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(6);
 
  }
 
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  void updatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  void findNeighbours() {
    neighbours = null;
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 12 &&
            abs(nodes[i].y - y) < height / 12) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
 
    // Set radius of node's circle based on number of neighbours
    if (neighbours != null) {
      radius = 2 * neighbours.length;
    } else {
      radius = 0; 
    }
  }
 
  void draw() {
    // Changed to use 'dist' function for cleaner code
    if (dist(destinationX, destinationY, x, y) < 1) {
      refreshDestination();
    }
    updatePosition();
    findNeighbours();
    float distance = dist(mouseX, mouseY, x, y);
    if (mouseStationaryCycles > CYCLES_BEFORE_STATIONARY) {
      distance = dist(shownX, shownY, x, y);
    }
    if (distance > TORCH_DISTANCE) {
      fill(255, 255, 0, 0);
      stroke(255, 255, 0, 0);
    } else {
      fill(255, 255, 0, 0 + -1.5 * distance);
      stroke(255, 255, 0, 0 + -1.5 * distance * 2);
    }
 
    if (circlesOn) {
      ellipse(x, y, radius, radius);
    }
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}
void mouseClicked() {
 circlesOn = !circlesOn; 
}
  • Show Code
/** @peep sketch */
/* @pjs font=http://peepproject.com/uploads/16100/controllertwo.otf; */
int NUMBER_NODES = 250;
int NODE_TERRITORY_RADIUS_HIGH = 50;
int NODE_TERRITORY_RADIUS_LOW = -50;
float EASING = 0.01;
int CYCLES_BEFORE_STATIONARY = 200;
int TORCH_DISTANCE = 170;
boolean circlesOn = true;
float shownX = 0;
float shownY = 0;
float shownDestinationX = 0;
float shownDestinationY = 0;
float previousMouseX = 0;
float previousMouseY = 0;
int mouseStationaryCycles = 0;
Node[] nodes;
void setup() {
  size(400, 400);
  //noStroke();
  //frameRate(10);
  PFont font = createFont("http://peepproject.com/uploads/16100/controllertwo.otf", 32);
  textFont(font);
  smooth(40);
  TORCH_DISTANCE = width / 5;
  NUMBER_NODES = max(width * height / 2000, 150);
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
void refreshShownDestination() {
  shownDestinationX = random(width);
  shownDestinationY = random(height);
}
void updateShownPosition() {
  shownX += (shownDestinationX - shownX) * EASING * random(0.5);
  shownY += (shownDestinationY - shownY) * EASING * random(0.5); 
}
void draw() {
  background(0);
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
 
  fill(255);
  stroke(0);
  textSize(72/900*width);
  textAlign(CENTER, CENTER);
  text("DESIGN LAB", width/2, height/2); 
 
  if (previousMouseX == mouseX 
    && previousMouseY == mouseY) {
      if (mouseStationaryCycles <= CYCLES_BEFORE_STATIONARY) {
       shownX = mouseX;
       shownY = mouseY;
      }
    mouseStationaryCycles++;
  } else {
    mouseStationaryCycles = 0;
  }
 
  previousMouseX = mouseX;
  previousMouseY = mouseY;
 
  // Changed to using 'dist' function for cleaner code
  if (dist(shownDestinationX, shownDestinationY, shownX, shownY) < 10) {
      refreshShownDestination();
    }
  updateShownPosition();
 
}
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(6);
 
  }
 
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  void updatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  void findNeighbours() {
    neighbours = null;
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 12 &&
            abs(nodes[i].y - y) < height / 12) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
 
    // Set radius of node's circle based on number of neighbours
    if (neighbours != null) {
      radius = 2 * neighbours.length;
    } else {
      radius = 0; 
    }
  }
 
  void draw() {
    // Changed to use 'dist' function for cleaner code
    if (dist(destinationX, destinationY, x, y) < 1) {
      refreshDestination();
    }
    updatePosition();
    findNeighbours();
    float distance = dist(mouseX, mouseY, x, y);
    if (mouseStationaryCycles > CYCLES_BEFORE_STATIONARY) {
      distance = dist(shownX, shownY, x, y);
    }
    if (distance > TORCH_DISTANCE) {
      fill(255, 255, 0, 0);
      stroke(255, 255, 0, 0);
    } else {
      fill(255, 255, 0, 0 + -1.5 * distance);
      stroke(255, 255, 0, 0 + -1.5 * distance * 2);
    }
 
    if (circlesOn) {
      ellipse(x, y, radius, radius);
    }
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}
void mouseClicked() {
 circlesOn = !circlesOn; 
}
  • Show Code
/** @peep sketch */
/* @pjs font=http://peepproject.com/uploads/16100/controllertwo.otf; */
int NUMBER_NODES = 250;
int NODE_TERRITORY_RADIUS_HIGH = 50;
int NODE_TERRITORY_RADIUS_LOW = -50;
float EASING = 0.01;
int CYCLES_BEFORE_STATIONARY = 200;
int TORCH_DISTANCE = 170;
boolean circlesOn = true;
float shownX = 0;
float shownY = 0;
float shownDestinationX = 0;
float shownDestinationY = 0;
float previousMouseX = 0;
float previousMouseY = 0;
int mouseStationaryCycles = 0;
Node[] nodes;
void setup() {
  size(600, 150);
  //noStroke();
  //frameRate(10);
  PFont font = createFont("http://peepproject.com/uploads/16100/controllertwo.otf", 32);
  textFont(font);
  smooth(40);
  TORCH_DISTANCE = width / 5;
  NUMBER_NODES = max(width * height / 2000, 150);
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
void refreshShownDestination() {
  shownDestinationX = random(width);
  shownDestinationY = random(height);
}
void updateShownPosition() {
  shownX += (shownDestinationX - shownX) * EASING * random(0.5);
  shownY += (shownDestinationY - shownY) * EASING * random(0.5); 
}
void draw() {
  background(0);
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
 
  fill(255);
  stroke(0);
  textSize(72/900*width);
  textAlign(CENTER, CENTER);
  text("DESIGN LAB", width/2, height/2); 
 
  if (previousMouseX == mouseX 
    && previousMouseY == mouseY) {
      if (mouseStationaryCycles <= CYCLES_BEFORE_STATIONARY) {
       shownX = mouseX;
       shownY = mouseY;
      }
    mouseStationaryCycles++;
  } else {
    mouseStationaryCycles = 0;
  }
 
  previousMouseX = mouseX;
  previousMouseY = mouseY;
 
  // Changed to using 'dist' function for cleaner code
  if (dist(shownDestinationX, shownDestinationY, shownX, shownY) < 10) {
      refreshShownDestination();
    }
  updateShownPosition();
 
}
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(6);
 
  }
 
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  void updatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  void findNeighbours() {
    neighbours = null;
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 12 &&
            abs(nodes[i].y - y) < height / 12) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
 
    // Set radius of node's circle based on number of neighbours
    if (neighbours != null) {
      radius = 2 * neighbours.length;
    } else {
      radius = 0; 
    }
  }
 
  void draw() {
    // Changed to use 'dist' function for cleaner code
    if (dist(destinationX, destinationY, x, y) < 1) {
      refreshDestination();
    }
    updatePosition();
    findNeighbours();
    float distance = dist(mouseX, mouseY, x, y);
    if (mouseStationaryCycles > CYCLES_BEFORE_STATIONARY) {
      distance = dist(shownX, shownY, x, y);
    }
    if (distance > TORCH_DISTANCE) {
      fill(255, 255, 0, 0);
      stroke(255, 255, 0, 0);
    } else {
      fill(255, 255, 0, 0 + -1.5 * distance);
      stroke(255, 255, 0, 0 + -1.5 * distance * 2);
    }
 
    if (circlesOn) {
      ellipse(x, y, radius, radius);
    }
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}
void mouseClicked() {
 circlesOn = !circlesOn; 
}

This is the white node alternative:

  • Show Code
/** @peep sketch */
/* @pjs font=http://peepproject.com/uploads/16100/controllertwo.otf; */
int NUMBER_NODES = 250;
int NODE_TERRITORY_RADIUS_HIGH = 50;
int NODE_TERRITORY_RADIUS_LOW = -50;
float EASING = 0.01;
int CYCLES_BEFORE_STATIONARY = 200;
int TORCH_DISTANCE = 170;
boolean circlesOn = true;
float shownX = 0;
float shownY = 0;
float shownDestinationX = 0;
float shownDestinationY = 0;
float previousMouseX = 0;
float previousMouseY = 0;
int mouseStationaryCycles = 0;
Node[] nodes;
void setup() {
  size(600, 400);
  //noStroke();
  //frameRate(10);
  PFont font = createFont("http://peepproject.com/uploads/16100/controllertwo.otf", 32);
  textFont(font);
  smooth(40);
  TORCH_DISTANCE = width / 5;
  NUMBER_NODES = max(width * height / 2000, 150);
  nodes = new Node[NUMBER_NODES];
  for (int i = 0; i < nodes.length; i++) {
    nodes[i] = new Node();
  }
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].findNeighbours();
  }
}
void refreshShownDestination() {
  shownDestinationX = random(width);
  shownDestinationY = random(height);
}
void updateShownPosition() {
  shownX += (shownDestinationX - shownX) * EASING * random(0.5);
  shownY += (shownDestinationY - shownY) * EASING * random(0.5); 
}
void draw() {
  background(0);
 
  for (int i = 0; i < nodes.length; i++) {
    nodes[i].draw();
  }
 
  fill(255);
  stroke(0);
  textSize(72/900*width);
  textAlign(CENTER, CENTER);
  text("DESIGN LAB", width/2, height/2); 
 
  if (previousMouseX == mouseX 
    && previousMouseY == mouseY) {
      if (mouseStationaryCycles <= CYCLES_BEFORE_STATIONARY) {
       shownX = mouseX;
       shownY = mouseY;
      }
    mouseStationaryCycles++;
  } else {
    mouseStationaryCycles = 0;
  }
 
  previousMouseX = mouseX;
  previousMouseY = mouseY;
 
  // Changed to using 'dist' function for cleaner code
  if (dist(shownDestinationX, shownDestinationY, shownX, shownY) < 10) {
      refreshShownDestination();
    }
  updateShownPosition();
 
}
class Node {
  float id;
  float startX;
  float startY;
  float destinationX;
  float destinationY;
  float x;
  float y;
  float radius;
  Node[] neighbours = null;
 
  Node() {
    id = random(1000000);
    x = random(width);
    y = random(height);
    startX = x;
    startY = y;
    refreshDestination();
    radius = random(6);
 
  }
 
  void refreshDestination() {
    destinationX = startX + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
    destinationY = startY + random(NODE_TERRITORY_RADIUS_LOW, NODE_TERRITORY_RADIUS_HIGH);
  }
 
  void updatePosition() {
    x += (destinationX - x) * EASING * random(2);
    y += (destinationY - y) * EASING * random(2); 
  }
 
  void findNeighbours() {
    neighbours = null;
    for (int i = 0; i < nodes.length; i++) {
      if (nodes[i].id != id) {
        if (abs(nodes[i].x - x) < width / 12 &&
            abs(nodes[i].y - y) < height / 12) {
          if (neighbours == null) {
            neighbours = new Node[1];
            neighbours[0] = nodes[i];
          } else if (neighbours.length > 2) {
            return;
          } else {
            append(neighbours, nodes[i]);
          }
        }
      }
    }
 
    // Set radius of node's circle based on number of neighbours
    if (neighbours != null) {
      radius = 2 * neighbours.length;
    } else {
      radius = 0; 
    }
  }
 
  void draw() {
    // Changed to use 'dist' function for cleaner code
    if (dist(destinationX, destinationY, x, y) < 1) {
      refreshDestination();
    }
    updatePosition();
    findNeighbours();
    float distance = dist(mouseX, mouseY, x, y);
    if (mouseStationaryCycles > CYCLES_BEFORE_STATIONARY) {
      distance = dist(shownX, shownY, x, y);
    }
    if (distance > TORCH_DISTANCE) {
      fill(255, 255, 0, 0);
      stroke(255, 255, 0, 0);
    } else {
      fill(255, 255, 255, 0 + -1.5 * distance);
      stroke(255, 255, 255, 0 + -1.5 * distance * 2);
    }
 
    if (circlesOn) {
      ellipse(x, y, radius, radius);
    }
    if (neighbours != null) {
      for (int i = 0; i < neighbours.length; i++) {
        strokeWeight(0.5);
        line(x, y, neighbours[i].x, neighbours[i].y); 
      }
    }
  }
 
}
void mouseClicked() {
 circlesOn = !circlesOn; 
}

Comments

Nobody has said anything yet.