LED CONTROLLER

For this week’s project, I had the choice of making a physical input or output, given that I just needed to use the serial monitor to connect between Arduino and Processing. So I decided to make an LED controller that would switch on if you press the button for each one, and would turn off if you pressed an “off” button.

Overall it was not bad, but I had a few mistakes especially since I was using a new library and I had to get used to the syntax. Also, when I created the functions for each of the buttons, I didn’t know the names had to match but that was silly of me, since the functions wouldn’t work obviously if the names didn’t match. Finally, it was interesting to see that when Processing uses the “COM4” port that my Arduino is linked to, I cannot open the Serial Monitor in Arduino since it says that my Serial Port is busy (probably used in Processing).

The program is simple: it uses characters transferred within the Serial Monitor to communicate between the hardware and the software. The functions in Processing write on the port the characters that match with the buttons, then the Arduino reads those characters and if they match with each LED color (code in Arduino) the corresponding lights will turn on.

Below is the code, the pictures, and a video of me testing it out!

Arduino:

void setup(){
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(10,OUTPUT);

  Serial.begin(9600);
}

void loop(){
    
   if(Serial.available()){
    char val = Serial.read();

    if(val == 'r'){
      digitalWrite(8,HIGH);
    }
    if(val == 'b'){
      digitalWrite(9,HIGH);
    }
    if(val == 'g'){
      digitalWrite(10,HIGH);
    }
    if(val == 'f'){
      digitalWrite(8,LOW);
      digitalWrite(9,LOW);
      digitalWrite(10,LOW);
    }
    }
   }

Processing:

import controlP5.*;
import processing.serial.*;

Serial port;
ControlP5 a;
PFont b;
void setup(){
  size(400,600);
  
  printArray(Serial.list()); //print available ports
  port = new Serial(this,"COM4",9600); //connection time!  
  a = new ControlP5(this);
  b = createFont("Verdana",30);//bigger font to put for the buttons 
  
  
  //buttons:
  a.addButton("red") //name
    .setPosition(30,150) //position
    .setSize(150,100) //size
    .setFont(b) //font
    ;
  a.addButton("blue")
    .setPosition(220,150)
    .setSize(150,100)
    .setFont(b)
    ;
  a.addButton("green")
    .setPosition(30,350)
    .setSize(150,100)
    .setFont(b)
    ;
  a.addButton("off")
    .setPosition(220,350)
    .setSize(150,100)
    .setFont(b)
    ;
}

void draw(){
  background(227,154,118);
  textSize(15);
  text("INSTRUCTIONS: PRESS A BUTTON AND FIGURE OUT!",15,50);
  
  
}

void red(){
  port.write('r');
}
void blue(){
  port.write('b');
}
void green(){
  port.write('g');
}
void off(){
  port.write('f'); //press f in chat  
}

Images:

The Controller:The LEDs:

Video:

Tori and Kyle: Dart Board!

Oh come on, you knew we were gonna work together.

Concept: 

A dartboard with two panels layered on top of each other, one more permeable (conductive fabric). When you throw the dart, it connects both panels and triggers an output in processing.

Based on where the dart landed, processing effect with your score. (if too simple in processing, make a game out of it?)

A speaker that plays “Congratulations”

Technical Requirements:

LEDS (of course), projector, computer, redboard, conductive fabric, conductive paint, various wires and other circuit stuff

Equipment Needs: 

Corkboard, darts, plastic protection (for edges so darts don’t harm wiring) 

Block Diagrams: 

The Handshake of the Lines

I connected my computer generated artwork with the potentiometer to change how lines are drawn in the circle.

//Circles and Lines_Nisala Saheed


class DrawLine {

  PVector point1;
  PVector point2;

  float angle;
  float angle2;
  float radius;

  float x;
  float y;

  float x2;
  float y2;



  DrawLine(float _angle, float _angle2, float _radius) {

    point1 = new PVector(x, y);
    point2 = new PVector(x2, y2);

    angle=_angle;
    angle2=_angle2;
    radius = _radius;
  }

  void update() {

    angle2 = angle * sin(modifier) * 4;

    x = center.x + cos(angle)*radius;
    y = center.y + sin(angle)*radius;


    x2 = center.x- cos(angle2)*radius;
    y2 = center.y- sin(angle2)*radius;

    angle += PI/120;
    angle2+=PI/90;
  }

  void display() {

    stroke(modifier, 220, 160);
    line(x, y, x2, y2);
  }
}



DrawLine myLine[];
PVector center;
float angle;
float angle2;
float radius;
int numLines = 15;
float change;
float increment;
float modifier = 0;

import processing.serial.*;

Serial myPort;


void setup() {
  size(600, 600);

  printArray(Serial.list());
  String portname=Serial.list()[31];
  println(portname);
  myPort = new Serial(this, portname, 9600);

  center = new PVector (width/2, height/2); // we need to know the center of the cirlce that we are drawing.
  angle = 0;
  angle2 = 0;
  radius = 100;

  change = map (mouseX, 0, width, 0, 10);
  increment = TWO_PI/numLines;
  myLine = new DrawLine[numLines];

  for (int i=0; i<numLines; i++) {
    float ang = i*increment;//this is how much the angle increments by.
    myLine [i] = new DrawLine (ang, ang*sin(3)*4, radius);
  }

  //increase i as an increment for the number of lines, until it reaches the desired number of lines
}
void draw() {
  //background(50);
  noStroke();
  fill(20, 30); 
  rect(0, 0, width, height);

  //if you want to see the center
  //ellipse(center.x, center.y, 10, 10);
  //draw the lines

  //change = map (mouseX, 0, width, 1.5, 3);


  for (int i=0; i<numLines; i++) {
    myLine[i].display();

    map(modifier, 0, 1023/4, 2, 3);
    myLine[i].update();
  }
}

void serialEvent(Serial myPort) {
  modifier = myPort.read();
  myPort.write(0);
}


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.write(0);
}

void loop() {
  if(Serial.available()>0){
    int inByte=Serial.read();
    int sensor = analogRead(A0);
    delay(1);
    sensor/=4;
    Serial.write(sensor);
  }
}

 

 

For my final project, I am considering creating an audio-visualizer. Most of the complexity of this should lie in coding processing, but I would need a sound sensor that can detect various frequencies. If such a sensor is not available I could create a relationship between a particular visual and how loud a sound it, or where it is coming from. This could take form in a small object that listens to music, or a larger piece that requires an individual to move within a designated space to impact a visual.

On the note of coding.

I have come to develop a particular relationship to the idea of coding. I used to consider it purely ambiguous and inscrutable numbers and words that randomly create some beautiful thing. However, after taking this class, I consider it something that is not one and the same as numbers. I think of it as a regularized, replicateable process. When we first explored processing, I wanted to begin creating graphics and beautiful images using the coding platform, despite having access to illustrator. In my frustration at my lack of skill in creating images in the software, I came to think of medium, and which medium is appropriate for what work.

As such, I consider processing and the logical nature of code and computing as a medium by which express myself.

 

An Explosion of Generative Text

For this week’s assignment, I decided to go for the generative text but with a playful twist in relation to misheard lyrics from famous songs. The process was very challenging at first, since I wasn’t able to get a more organic transition from the text to the pixels. But after discovering several in-built functions in Processing, such as get() and set() it was easier to manipulate the pixels. get() was particularly useful and interesting to use, since it allowed me to extract the non-black pixels within set parameters. I also struggled a lot with the values being returned by my functions as they were doing almost the opposite of what I intended, until I used the function abs() – which returns positive values no matter what, and ultimately allowed me to scroll the text in the correct orientation.

I feel like at this point there are so many functions built in Processing that can help make my life easier and more interesting, and I’m making it my life’s mission to uncover these functions one by one.

Sweet dreams are indeed made of cheese!

Code:

ArrayList p;
PFont font; 

void setup() {
  int i, x, y;
  color c;
  size (640, 480);
  frameRate(60);

  p = new ArrayList();
  createText();
  
  //set font
  font = createFont("Arial", 100); 

  background(0);
  stroke(255);
  fill(244, 154, 194);
  rect(0, 0, 240, 480);
}

void createText() {
  PGraphics pg;
  int x, y;
  color c;

  pg = createGraphics(5000, 500);
  pg.beginDraw();
  pg.background(0);
  pg.fill(255);
  pg.stroke(255);
  pg.textSize(200);
  pg.textAlign(LEFT, CENTER);
  pg.text("Sweet dreams are made of cheese", 0, 200);
  pg.endDraw();

  // Extract all non-black pixels
  for (x=0; x<5000; x++) {
    for (y=0; y<480; y++) {
      if ((c=pg.get(x, y))!=color(0)) {
        p.add(new pxl(x+1000, int(y+100*sin(x/(PI*80))), -80000*5, 0, c, color(0)));
      }
    }
  }
}
void draw () {
  int i;
  pxl a;

  fill(154, 194, 244);
  triangle(0, 0, 240, 240, 0, 480);
  for (i=0; i<p.size(); i=i+1) {
    a = (pxl) p.get(i);
    a.moveSpecial();
  }
}

Pixel Class:

class pxl {
  // Position and speed is x>>16 
  int x, y, xorg, yorg;
  int xspeed, yspeed;
  color c;              // pixel color
  color b;              // background color
  color c_temp;
  int gravity = 00;
  int resistance = 20;

  pxl(int _x, int _y, int _xspeed, int _yspeed, color _c, color _b) {
    x = xorg = _x<<16;
    y = yorg = _y<<16;
    xspeed = _xspeed;
    yspeed = _yspeed;
    c = _c;
    b = _b;
  }
  void display() {
    c_temp = get(x>>16, y>>16);
    set(x>>16, y>>16, c);
  }
  void hide() {
    set(x>>16, y>>16, b);
  }
  void updateSpeed() {
    long t = xspeed;
    xspeed = xspeed - ((int) (t * resistance)>>16);
    t = yspeed;
    yspeed = yspeed - ((int) (t * resistance)>>16);
    yspeed = yspeed + gravity;
    if (abs(xspeed)<100 && abs(yspeed)<100) {
      xspeed = int(random(-500000, 500000));
      yspeed = int(random(-500000, 500000));
    }
  }
  void moveSpecial() {
    int yt;
    hide();
    x = x + xspeed;
    y = y + yspeed;
    if ((x>>16)<=(240-abs(((y>>16)-240)))) {
      x = x - xspeed;
      y = y - yspeed;
      // change speeds 
      xspeed = int(random(1<<16, 10<<16));
      yt=int(-240+(y>>16))/48;

      yspeed = int(random((yt-5)<<16, (yt+5)<<16)) ;
      c = color(random(255), random(255), random(255));
    }
    display();
    updateSpeed();
  }
}

 

 

Text generation

I tried a bunch of different text generation ways. I watched a video on the coding train and now I feel I have a much deeper understanding of text generation. I decided to go with a simple text fade.

float imeInterval;
float timePast;

int textAlpha = 100;
int textFade = 2;
float timeInterval = 2000.0f;
PFont f;
void setup() {
  size(400,400);
   timePast = millis();
   f = createFont("Zapfino", 64);
  
}

void textFade() {
  if (millis() > timeInterval + timePast){
  timePast = millis();
  textFade*= -1;
}
textAlpha += textFade;
}
void draw() {
background(0);
textFade();
textSize(90);
textFont(f,50);
fill(255,255,255, textAlpha);
text("Dream", width/4, height/2);
}

 

Darkness in the Darkness

Darkness in the Darkness

For this exercise, I have utilized the Geomerative library to trace the points within the text string, inspired from Aaron’s repository on geomerative text. Using this library, I wanted to show the general tracing of one point to another in a sorted order by drawing a line from i to i+1 in a loop – which created a mysterious illusion as if it is a handwriting.

To add some tweak, I have made each point as particles that starts off at random positions on the screen that eventually reaches its original position in the text. Also, the frameRate changes depending on the location of the cursor in respect to the X-axis.

The following are the source code and a short recording of the exercise:

import geomerative.*;
int iterator, count;
color c;
RFont font;
RPoint[] pnts;
Particle[] particles;

float w, h, mapVal;

void setup() {
  size(640, 480);

  RG.init(this);

  // set the font, the size, and left, center, or right adjusted
  font = new RFont("Franklin Goth Ext Condensed.ttf", 150, RFont.CENTER);
  
  // get the points along a String
  pnts = getPoints("DARKNESS");
  
  particles = new Particle[pnts.length];
  for (int i=0; i<particles.length; i++) {
    particles[i] = new Particle(random(-width/2, width/2), random(-height, height), pnts[i].x, pnts[i].y);
  }
  
  w = width/2;
  h = height/1.5;
  
  count = 1;  
  c = color(random(0,255), random(0,255), random(0,255));
  
  noFill();
  strokeWeight(3);
}

void draw() {
  mapVal = map(mouseX, 0, width, 10, 120);
  frameRate(mapVal);
  iterator = count % (particles.length-1);
  if (iterator == 0) {
      c = color(random(50,255), random(50,255), random(50,255));
    }
  
  fill(0, 11);
  noStroke();
  rect(0, 0, width, height);
  pushMatrix();
    translate(w, h);
    stroke(c);
    fill(c);
    for (int i=0; i<particles.length; i++) {
      particles[i].update();
    }
    line(particles[iterator].x, particles[iterator].y, particles[iterator+1].x, particles[iterator+1].y);
    count++;
  popMatrix();
}

// function that returns an array of RPoints based on a string
RPoint[] getPoints(String str) {
  // change this number to change the resolution of points outlining the circle
  RCommand.setSegmentLength(5);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  RGroup grp;
  grp = font.toGroup(str);
  grp = grp.toPolygonGroup();
  return grp.getPoints();
}
class Particle {
  float x, y, destX, destY, xSpeed, ySpeed;
  float dirX, dirY, rand;
  color c;
  
  Particle(float _x, float _y, float _destX, float _destY) {
    x = _x;
    y = _y;
    destX = _destX;
    destY = _destY;
    xSpeed = 0;
    ySpeed = 0;
  }
  
  void update() {
    dirX = destX - x;
    dirY = destY - y;
    xSpeed = (dirX*0.003);
    ySpeed = (dirY*0.003);

    xSpeed *= 0.95;
    ySpeed *= 0.95;
    x += xSpeed;
    y += ySpeed;
  }
}

 

Idk man it’s a thing with text and a pretty drawing

I really never know how to title these posts. Basically, I was up late at night after toying around with three other ideas for generative text output projects and I got an idea for something totally different which led to me making the google search for “cartoon kid reading”. I then got this totally unrelated picture of two people, in each other’s arms, looking at their phones, underneath the stars and constellations. I absolutely loved this photo. The aesthetic was beautiful and I immediately wanted to incorporate it into my sketch. Plus, I hadn’t yet experimented with loading a photo into processing, so I would get that skill too.

Now how would this incorporate text? There was an obvious element of astrology in this photo and when I followed the picture to its source, I found the article, “Why millenials are so into astrology?” I started taking words and phrases from that article and inputting them into a word document:

“The New Age of Astrology” “Millenial and Gen Z Quotient” “Horoscopes in the Backs of Magazines”

I imported that text into the screen and made it seem like it was coming out of the iPhone and into the guy’s head. And as they fade out of sight (and off screen), they loop back around, each phrase going at a different speed and at a different size, randomized by processing.

This work wasn’t really about, like, making something happen for me. It was more about the aesthetic and the atmosphere that the work of art instilled in me when I saw it. I had thought about making the text do something, with a mouse press or a release, or something, but I think that would have taken away from the art.

Here’s the video:

Here’s the main code:

PImage img;
PFont f;

float x = 70;
float y = 230;
int space = 30;
int fade = 255;



Text lines[];

void setup() {
  f = createFont("Courier", 44);

  size(1000, 680);
  img = loadImage ("astrology.jpg");
  String[] textLines = loadStrings("text.txt");
  lines = new Text[textLines.length];
  for (int i = 0; i < lines.length; i++) {
    lines[i] = new Text(textLines[i], x + i*space/2, y + i*space);
  }
}

void draw() {

  scale(.7);    // setting up the background image, note that scalge is fine for this project but not ideal for the future
  image(img, 0, 0);

  for (int i = 0; i < lines.length; i++) {
    lines[i].run();
  }
}

Here’s the class:

class Text {

  float x;
  float xHome = 85;
  float y;
  float speed;
  int fade = 255;
  float fadeAdjustment = 2.3;
  int space;
  int lines = 8;
  String text;
  int size = int(random(15, 25));


  Text(String t, float _x, float _y) {
    text = t;
    x = _x;
    y = _y;
    speed = random(1.6, 4.8);
  }


  void display() {

    pushMatrix();
    textAlign(LEFT);
    rotate(-.1);
    textSize(size);
    fill(255, fade);
    text(text, x, y);
    popMatrix();
  }


  void update() {
    x+= speed;
    fade -=  fadeAdjustment;
  }

  void checkEdges() {

    if (y>height) {
      y=0;
    }
    if (y<0) {
      y=height;
    }
    if (x>800) {
      x=xHome;
      fade=255;
    }
  }


  void run() {
    display();
    update();
    checkEdges();
  }
}

 

Here’s credit to the article and the artist is Maura Dwyer. Also, cheers to Jack and Aaron for meeting with me <3

Generative text

I really liked the idea of the text making a word out of random letters in the air. I tried to make a similar thing, but the word is always the same 😀

When the program starts the letters float on the screen. As soon as the mouse is pressed, they make a word in the center of the screen. I made sure that the letters won’t get out of bounds.

Here is the code:

String word = "hello world";
letters[] l1;

void setup() {
  size(640, 640);

  l1 = new letters[word.length()];
  for (int i =0; i<word.length(); i++) {
    l1[i] = new letters(word.charAt(i), width/3 +i*25, height/2);
  }
  //String word = "Hello";
}
void draw() {
  background(255);
  for (int i =0; i<word.length(); i++) {
    if (mousePressed) {
      l1[i].print();
      l1[i].returnBack();
    } else {
      l1[i].print();
    }
  }
}
class letters {
  char symbol;
  float x;
  float y;
  char c;
  float randX, randY;
  float originx, originy;
  letters(char _c, float _x, float _y) {
    x = _x;
    y = _y;
    c = _c;
    originx = x;
    originy = y;
    randX = random(-3, 3);
    randY = random(-3, 3);
  }
  void print() {
    fill(0);
    textSize(36);
    textAlign(CENTER);
    text(c, x, y);
    x += randX;
    if (x>= width || x <=0) {
      randX = -randX;
    }
    y += randY;
    if (y>= height || y <=0) {
      randY = -randY;
    }
  }
  void returnBack(){
    float deltaX = (originx - x)/3;
    float deltaY = (originy - y)/3;
    x += deltaX;
    y += deltaY;
  }
}

And here is a video:

Generative Text (questionable art)

For this week’s assignment, I created a little meaningless piece BUT with our favorite picture of Aaron. If the mouse is released, all of little Aarons wonder around, but when the mouse is pressed, all of them  (after a little hustle) form the word APPLES.

At first, I wanted to make the objects have a steering behavior (Shiffman has a great video with this). In theory, I understood the concepts and code, but when it came to implementing it on all of the objects that form the letters, not just one, I could not make it work. I was a little stubborn to admit that I bit off a little bit more than I could chew and only after a looong period of trying I had to go with something more familiar. Therefore the code is widely based on Aaron’s code we saw in class, with a little bit more playfulness and variations in the behavior. Spending some time, however, on understanding the steering was a great teaching moment, and yesterday’s full-on frustration turned to today’s motivation to actually make it work for another project.

 

 

And this is a little bonus not connected to the assignment, just a simpler version of what I was trying to do according to Shiffman’s code, but kind of failed to apply on a bigger scale.

The code and class for Formation of Aarons:

import geomerative.*;
RFont font;
RPoint[] pnts;
Photo[] formation;
PImage aaron, greenB;

void setup() {
  size(640, 360);

  //load the bckg image
  greenB = loadImage("green.jpg");


  //initialize and load the data (font)
  RG.init(this);
  font = new RFont("CaviarDreams.ttf", 150, RFont.CENTER);

  //get the points APPPLES out of the data
  pnts = getPoints("APPLES");


  int amountPerPoint = 1;

  //use the class
  formation = new Photo[pnts.length*amountPerPoint];


  int index = 0;
  for (int i=0; i<pnts.length*amountPerPoint; i+=amountPerPoint) {
    for (int j=0; j<amountPerPoint; j++) {
      int k = i+j;
      formation[i] = new Photo(width/2+pnts[index].x+random(-3, 3), height/1.5+pnts[index].y+random(-3, 3));
    }
    index++;
  }
}


void mousePressed() {
  for (int i =0; i<formation.length; i++) {
    formation[i].seek=true;
  }
}
void mouseReleased() {

  for (int i =0; i<formation.length; i++) {
    formation[i].xSpeed = random(-5, 5);
    formation[i].ySpeed = random(-5, 5);
    formation[i].seek=false;
  }
}
void draw() {
  background(0);
  image(greenB, 0, 0);
  for (int i=0; i<formation.length; i= i+2) {
    formation[i].seekHome();
    formation[i].update();
    formation[i].display();
    formation[i].checkEdges();
  }
}

RPoint[] getPoints(String str) {
  RCommand.setSegmentLength (10);
  RCommand.setSegmentator(RCommand.UNIFORMLENGTH);
  RGroup grp;
  grp = font.toGroup(str);
  grp = grp.toPolygonGroup();
  return grp.getPoints();
}

 

class Photo {
  float x, y, homeX, homeY;
  float xSpeed, ySpeed;
  boolean seek;
  char letter;
  PImage aaron;

  Photo(float _x, float _y ) {
    homeX = x = _x;
    homeY = y = _y;
    xSpeed = ySpeed = 0;
    // diam = _diam;
    seek = true;
  }

  void update() {
    x += xSpeed;
    y += ySpeed;
    xSpeed *= .95;
    ySpeed *= .95;

    aaron = loadImage("aaron.png");
  }

  void display() {
    aaron.resize(25, 50);
    image(aaron, x, y);
  }

  void seekHome() {
    if (seek) {
      float dirX = homeX-x;
      float dirY = homeY-y;
      dirX*=.05;
      dirY*=.05;
      xSpeed+=dirX;
      ySpeed+=dirY;
    }
  }

  void checkEdges() {
    if (y>height) {
      y=0;
    }
    if (y<0) {
      y=height;
    }
    if (x>width) {
      x=0;
    }
    if (x<0) {
      x=width;
    }
  }
}

Flying Aaron Code:

Vehicle vehicleA;
PImage blackhole;


void setup() {
size(640, 360);

vehicleA = new Vehicle(width/2, height/2);
blackhole = loadImage("black hole.jpg");

}

void draw(){
 background(0);
 image(blackhole, 0, 0);
vehicleA.update();
vehicleA.seek(new PVector(mouseX, mouseY));
vehicleA.display();

}
class Vehicle {
  float maxSpeed;
  float maxForce;
  float r;
  PImage a;
  PVector location, target, desired, velocity, acceleration;
  boolean mouseClose;


  Vehicle (float x, float y) {
    maxSpeed = 4;
    maxForce = 0.1;
    mouseClose = false;
    acceleration = new PVector(0, 0);
    velocity = new PVector(0, -2);
    location = new PVector(x, y);
  }


  void update () {

    //updated velocity
    velocity.add(acceleration);

    //to limit the speed
    velocity.limit(maxSpeed);
    location.add(velocity);

    //(come back to zero)
    acceleration.mult(0);

    a = loadImage("aaron.png");
  }

  void applyForce(PVector force) {
    //Q
    acceleration.add(force);
  }

  void seek (PVector target) {

    PVector desired = PVector.sub(target, location);
    desired.normalize();
    desired.mult(maxSpeed);

    //steering = desired minus velocity
    PVector steer = PVector.sub(desired, velocity);
    steer.limit(maxForce);

    applyForce(steer);
  }
  void display() {
    float theta = velocity.heading();
    pushMatrix();
    translate(location.x, location.y);
    rotate(theta + PI/2);
    image(a, 0, 0, 50, 100);
    popMatrix();
  }
}

 

Generative Text: Net

For this assignment, we were asked to create a generative text or data visualization piece. I’m interested in both, but I especially wanted to experiment with text. In the beginning, I wanted to create some form of a playful horoscope generator but the structuring of words, their sentence placement, and concepts such as context-free grammar were a little bit too difficult to understand.

Instead, I created a piece where there is a “net” of letters, and you have to click on the sketch to generate the word “net”.  In the beginning, I thought of adding a scoreboard and turning it into a game where every time you generate the word, you earn a point–– but apart from the fact that it’s tricky, I realized it would defy the purpose of the sketch being a simple play on words where the user interaction is somewhat open-ended.

You can also refresh the letters by pressing the spacebar, the first press removes all the letters and the second press will rearrange them.

Here is the end result (I updated the video):

And here is an Arabic version:

And here is the code:

//Source: textArrayClass3-Bounce by Taylor Hedum on OpenProcessing


String[] character = {"N", "T", "E", "N", "T", 
"E", "T", "T", "T", "N", "E", "T", "N", "E", "T", "N", 
 "E", "T", "N", "T", "E"};
//  //"E", "B", "E", "E", "B"
//String[] character = {"N", "E", "T"};
//String[] character = {"ش", "ب", "ك", "ة", "ش", "ب", "ك", "ة", "ش", "ب", "ك", "ة", "ش", "ب", "ك", "ة"};
int tSize = 36;

ArrayList<Chara> charas = new ArrayList<Chara>();
int charaLim = character.length;
//int charaLim = 50;
int randoChara;

float spring = 0.3;
float gravity = 0.1;
float friction = -0.9;
int charaCounter;
boolean showLetters = true;


//PImage bg;

void setup() {
  size(500,500);
  textSize(tSize);
  textAlign(CENTER);
  //frameRate(4);
  
  for (int i=1; i<charaLim+1; i++) {
    
    //used to generate random character in character array
    randoChara = int(random(0, character.length));
    //bg = loadImage("8.png"); 
    
    //add all characters in character array to list of characters to get initial bouncing going
    charas.add(new Chara(i, randoChara, width/(charaLim+1)*i, random(height/2), tSize));
  }
}

void draw() {
   background(220,220,220);
  for (int i = 0; i < charas.size(); i++) {
    Chara chara = charas.get(i);
    chara.collide();
    chara.move();
    chara.display();
  }
  if (mousePressed) {
    //addOne();
  }
  for (int i = charas.size(); i > 0; i--) {
    
    //starts deleting characters when the set limit of characters is reached
    //deletes character at the beginning of list, the oldest character so to speak
    if (charas.size() > charaLim*2) {
      deleteOne(1);
    }
  }

}

void mousePressed() {
  addOne();
}

//adds new character upon mousePress
void addOne() {
  randoChara = int(random(0, character.length));
  
  //passes MouseX & MouseY to class constructor so that character is first drawn where the mouse is
  charas.add(new Chara(charas.size()+1, randoChara, mouseX, mouseY, tSize));
}


void deleteOne(int delid) {
  
  //removes first character in arrayList since delid is always passed as 1
  charas.remove(delid-1);
  
  //moves up the other character's IDs by one
  for (int i = delid-1; i<charas.size(); i++) {
    Chara chara = charas.get(i);
    chara.reOrder();

  }
}

void keyPressed(){
  if (key == ' '){
    showLetters = !showLetters;
  }
}

class Chara {
  int id;
  int whichChara;
  float x, y;
  float diameter;
  float vx = 0;
  float vy = 0;
  float xx = random (0, 500);
  float xS;
  int offSet = 250;
  float r;
  float rd = 1;

  Chara(int idint, int randoChara, float xin, float yin, float din) {
    id = idint; 
    whichChara = randoChara;
    x = xin;
    y = yin;
    diameter = din;
    r = random(width/4, width/2);
  }

  void collide() {
    for (int i = 0; i < charas.size(); i++) {
      Chara others = charas.get(i);
      if (others != this) {
   
       
        float dx = others.x - x;
        float dy = others.y - y;
        
        //pythogonal distance
        float distance = sqrt(dx*dx + dy*dy);
        
        //draws line between characters if they're close enough
        float minDist = others.diameter/4 + diameter/4;
        if (distance < minDist*8) { 
          line(x, y, others.x, others.y);
        }
        
        //makes characters bounce of each other if they come within minDist of each other
        if (distance < minDist) { 
          float angle = atan2(dy, dx); //angle determined by atan2 and distance between characters
          float targetX = x + cos(angle) * minDist;
          float targetY = y + sin(angle) * minDist;
          
          //acceleration 
          float ax = (targetX - others.x) * spring;
          float ay = (targetY - others.y) * spring;
          vx -= ax;
          vy -= ay;
          others.vx += ax;
          others.vy += ay;

        }
      } else {
        fill(0);
      }
    }
  } 
  
  void move() {
    vy += gravity;
    x += vx;
    y += vy;
    
    //if character hits/goes past right sides of the canvas,
    //reset x so it seems to bounce off the edge of canvas,
    //then change direction of x-movement
    if (x + diameter/2 > width) {
      x = width - diameter/2;
      vx *= friction;
      
    //likewise but for left side of canvas
    } else if (x - diameter/2 < 0) {
      x = diameter/2;
      vx *= friction;
    } //likewise but for height
    if (y + diameter/2 > height) {
      y = height - diameter/2;
      vy *= friction;
    } else if (y - diameter/2 < 0) {
      y = diameter/2;
      vy *= friction;
    }
  } 

  void display() {
  fill(0);
  
    //if showLetters is true (toggled by space bar), draw the letter
    if (showLetters) {
      text(character[int(whichChara)], x, y+diameter/3);
    }

    stroke(135,206,235);
    strokeWeight(1);

  }
  void reOrder() {
    id-=1;
  }
}