ICM – idea for finals

This week was spent on coming up with ideas for the ICM final. I knew I wanted to do something related to data-visualization. I was thinking about doing a geolocation tracking game. My first thought was to use the Mappa or Google maps to create the scene and use GPS data from peoples phones to track the position and somehow turn it into a competitive game. However after talking to Aidan a couple of times I realized that we had some similar ideas in mind and that I would like to work with somebody for this assignment. We discussed different options including NYC open data for visualization of buildings and streets in New York or historical data to inform users about events taking place at different locations in New York. We wanted to make sure that the project had some interactivity to it and that users would be included in the idea. When discussing  potential ideas we stumbled  upon “Walker” by Chino Kim. Basically what he did was to send a bot on a random walk through america. This bot would post different random images on twitter based on its location. We liked that idea and came up with a project to do something similar. We wanted to create a project with a bot (picture of the user) that based on a budget would travel to a “random” place in the world and capture photos of the user in those settings. The higher the budget the further it could go. And based on the costs of living in that particular country it could stay only for a given amount of time. This way you could follow your bot and see photos of you in different locations as long as your budget would allow you to.

To do this we discussed the idea of using a flight API to find destinations the bot could travel to (based on its budget). We would use random twitter or google street view images from the destination country and layer the profile picture of the user on top of that. We would find information about living expenses in that particular country and based on those we would determine the length of the stay.

We will present the idea in class today.

To see more detailed information about our thoughts, ideas and concerns see:

Presentation slides

ICM week 7 – Data visualization – Copenhagen

This weeks homework was to create a sketch using online data. This could be csv, JSON or any other data information that we would like. Copenhagen has a comprehensive data collection that they share on open data Copenhagen. I wanted to use that data to see if a certain dataset like trees or streets would give a picture of what the city looks like. However, last thursday we went to a flyby with Cvalenzuela on geomapping. He created this “mappa” function. A layer that you can apply to sketches so you can actually scroll around the world – similar to google maps. I wanted to try to combine the two. The result was a sketch of Copenhagen where a 1000 trees are pointed out with green circles and trash bins are colorcoded depending on their current condition (new, used, old). One big change in this weeks sketch is that it is taking place in the index. file. Apparently this is necessary if you want to use the “mappa” function. Making my way through this code took some time – but with a lot of help from the console.log I managed to find my way through the data.

Data collected from “open data Copenhagen” – Trees are green

Trashbins are colored according to their current state:

New trashbin – white,
Decent trashbin – blue,
Old/ugly trashbin – black

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<!DOCTYPE html>
<html lang="en">

<head>
  <title>Simon Jensen Data</title>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.16/p5.min.js" type="text/javascript"></script>
  <script src="https://unpkg.com/mappa-mundi/dist/mappa.min.js" type="text/javascript"></script>
</head>

<body>
  <script>
 
var myMap;
var canvas;
var mappa = new Mappa('Leaflet');
var options = {
  lat: 55.687344,
  lng: 12.562719,
  zoom: 13,
  style: "http://{s}.tile.osm.org/{z}/{x}/{y}.png"
}
var urlaffald = "https://wfs-kbhkort.kk.dk/k101/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=k101:affaldskurv&outputFormat=json&SRSNAME=EPSG:4326"
var urltræer = "http://wfs-kbhkort.kk.dk/k101/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=k101:gadetraer&outputFormat=json&SRSNAME=EPSG:4326"
var affald = [];
var træer = [];

function preload() {
    loadJSON(urlaffald, makeTable);
    loadJSON(urltræer, makeTable2);
}
   
function makeTable(trash) {
    for (i = 0; i < 1000; i++) {
        affald.push({
            lat: trash.features[i].geometry.coordinates[0][0],
            long: trash.features[i].geometry.coordinates[0][1],
            condition: trash.features[i].properties.kurv_tilstand
        })
    }
}

function makeTable2(tree) {
    for (j = 0; j < 1000; j++) {
        træer.push({
            lat: tree.features[j].geometry.coordinates[0],
            long: tree.features[j].geometry.coordinates[1]
        })

    }
}    
   


function setup(){
  canvas = createCanvas(640,640);
  myMap = mappa.tileMap(options);
  myMap.overlay(canvas)
  fill(200, 100, 100);
  colorMode(HSB,255,255,255);

  // Only redraw the point when the map change and not every frame.
  myMap.onChange(drawPoint);
}

function draw(){
}


function drawPoint(){
  clear();
   for (let j = 0; j < 1000; j++) {
  var trees = myMap.latLngToPixel(træer[j].long,træer[j].lat);
  var trash = myMap.latLngToPixel(affald[j].long,affald[j].lat);
     fill('GREEN');
     ellipse(trees.x, trees.y, 5, 5)
      let cond = affald[j].condition;
        if (cond == "Rimelig/god stand") {
            fill('BLUE')
        } else if (cond == "Slidt/grim") {
            fill('BLACK');
        } else if (cond == "Ny/velholdt") {
            fill('WHITE');
        }
     ellipse(trash.x, trash.y, 5, 5)
}
}
   
  </script>
</body>

</html>

;

ICM week 6 – Introduction to DOM/HTML/CSS

Update with code coming up!

code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
var isInside = false;
var outlineSpeed = 0.025;
var total = 3;
var circles = [];
var circlesClicked = [];
var CircleIsSelected = false;
var Canvas;
let button;
var bgColor = 0;
var frontColor = 255;

function setup() {
canvas = createCanvas(windowWidth, windowHeight);
canvas.position(0, 0);
canvas.style('z-index', '-1')

&nbsp;

for (var i = 0; i &lt; total; i++) {
circles.push(new Circle(random(width), random(height), 30));
circlesClicked.push(false);
}

button = createButton("colorshift");
button.mousePressed(colorChange);
button.position(0,height-100);

}

&nbsp;

function draw() {
background(bgColor);

&nbsp;

//Circles are blinking
if (circles[0].outline &gt; 3 || circles[0].outline &lt; 0.2) {
outlineSpeed = outlineSpeed * -1;
}

for (var i = 0; i &lt; total; i++) {
circles[i].outline = circles[i].outline + outlineSpeed;
}

//Creating a shape between the circles
beginShape();
strokeWeight(1);
fill(frontColor);

for ( i = 0; i &lt; total; i++) {
vertex(circles[i].x, circles[i].y);
}
endShape(CLOSE);

&nbsp;

fill(255);
for (i = 0; i &lt; total; i++) {
circles[i].display();
}

&nbsp;

for (i = 0; i &lt; total; i++) {
if ((mouseIsPressed &amp;&amp; circles[i].containsMouse() &amp;&amp; CircleIsSelected == false) || circlesClicked[i] == true) {
circles[i].drag();
circlesClicked[i] = true;
CircleIsSelected = true;
}
}

}

function mouseReleased() {
for (var i = 0; i &lt; total; i++) {
circlesClicked[i] = false;
}
CircleIsSelected = false;
}

function colorChange() {
bgColor = bgColor == 255 ? 0 : 255;
frontColor = frontColor == 255 ? 0 : 255;

ICM week 5 – Arrays and objects

This week in class we were introduced to objects and arrays. Objects it turns out, has changed slightly – so that it is now a class and a constructor you use to create an object. After becoming more familiar with this it now makes perfect sense. I spent a lot of time on this weeks quiz. I found it very difficult. Especially the challenge and the SuperDuperChallenge – with some help i managed to sort it out.

This weeks assignment was to design a sketch in an object oriented fashion. We were also allowed to reorganize an already existing sketch.

I decided to create a new sketch to play around with the array functions – but also to get better at communication between objects.

My intentions were to create a sketch where boxes would land and stack on each other. The sketch has some flaws as I couldn’t sort out the formula for when the boxes collide. *UPDATE* The code should now be fixed. Instead of using a dist function to calculate the distance between the squares I did two separate disx and disy calculations with absolute(). This worked a lot better as you can see.

The code looked as follows:

sketch:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//create an array
var squares = []
var x;

function setup() {
createCanvas(400, 400);
//initialize squares
for (var i = 0; i &lt; squares.length; i++) {
squares.push(new Square());
}
}

function draw() {
background(220, 100, 100);

for (var i = 0; i &lt; squares.length; i++) {
squares[i].display();
squares[i].falling();
squares[i].collide(squares);

if (keyIsPressed) {
squares[i].removes();
}
}
}

function mousePressed() {
squares.push(new Square(mouseX, mouseY, 30, 30));

}

object (with the new class syntax) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Square {

    constructor(x, y, w, h) {

        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.speed = 1;
    }
    display() {
        rectMode(CENTER);
        stroke(1);
        rect(this.x, this.y, this.w, this.h);
    }
    falling() {
        this.y = this.y + this.speed;

        if (this.y > height - this.w / 2) {
            this.y = height - this.w / 2;
        }
    }
    collide(otherSquare) {
        //othersquare is stand in for other balls in sketch array
        for (var i = 0; i < otherSquare.length; i++) {
        //if the ball is not itself
            if (otherSquare[i] !== this) {
                    //calculate distance between objects and determine if they collide. If they do, stop moving.
                var dis = dist(this.x, this.y, otherSquare[i].x, otherSquare[i].y);
                if (dis < this.x + this.h / 2 + otherSquare[i].x + otherSquare[i].h / 2 && dis < this.w / 2 + otherSquare[i].w / 2) {
                    this.speed = 0;
                }
            }
        }
    }

    removes() {
       //drive squares out of view
        if (this.speed == 0 || this.y == height - this.w / 2) {
            this.x = this.x + 5;

        }

    }
}

*note to self. Remember to include the class in the sketch through index

A lot of question came up this week. At first I was trying to remake the snake game – but could only make it so far.
– how do you apply a function such as function mousePressed() into an object function? – if it is even possible?
Basically I want to be able to control an object without holding down the key (As in keyIsPressed).
– how do you create a nested loop of objects?

ICM week 4. Functions and objects.

For this weeks class we worked on organizing our code. We used functions and got introduced to objects to get a better structure for our code. For this weeks assignment we could either “clean” up one of our previous sketches or we could make a new one.
I decided to try to recreate the game “PONG” using two objects a brick and a ball. The game is embedded on this page.

I met some struggles along the way. One is that I don’t know how to make the ball bounce back in a natural way after colliding with either of the bricks. If I just turn the Xspeed and Yspeed around it creates a strange bounce. Another problem was configuring the game so that both “players” can press keys at the same time.

According to the assignment of keeping the code clean and structured. I think it went well. Aside from the text, there are very limited information in the setup() function and draw function().

Code can be seen here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
var Brick = function(x, y) { //Brick object
  this.x = x;
  this.y = y;
  this.diameter = 60;
  this.display = function() {
    ellipse(this.x, this.y, this.diameter, this.diameter);
  }
  this.move = function(up, down) { //Move with arraykeys
    this.up = up;
    this.down = down;
    if (keyIsPressed && keyCode == this.up) {
      this.y = this.y - 2;
    } else if (keyIsPressed && keyCode == this.down) {
      this.y = this.y + 2;
    }
  }
}


var Ball = function(x, y) { //Ball object
  this.x = x;
  this.y = y;
  this.speedx = -1.5;
  this.speedy = random(-1.4, 1.4);
  this.diameter = 30
  this.display = function() { //display
    ellipse(this.x, this.y, this.diameter, this.diameter)
  }
  this.move = function() { //move
    this.x = this.x + this.speedx;
    this.y = this.y + this.speedy;
    this.speedx = this.speedx + 0.001;
  }
  this.borders = function() { //When outside change direction
    if (this.y > height || this.y < 0) {
      this.speedy = this.speedy * -1;
    }
  }
  this.intersects = function(other) { //when ball hits brick
    var dis = dist(this.x, this.y, other.x, other.y);
    if (dis < this.diameter / 2 + other.diameter / 2) {
      return true;
    } else {
      return false;
    }
  } //go back
  this.changeDirection = function() {
    this.speedx = this.speedx * -1;
    this.speedy = this.speedy * -1;
  }
}



function setup() {
  createCanvas(500, 500);
  brick = new Brick(0, height / 2);
  brick2 = new Brick(width, height / 2);
  ball = new Ball(width / 2, height / 2);


}

function draw() {
  background(160, 100, 100);
  push();
  strokeWeight(10);
  stroke(255);
  line(width / 2, 0, width / 2, height);
  pop();

  push();
  textAlign(CENTER);
  text("Control player 1: arrowkeys \n \n \n player 2: SHIFT and OPTION", width / 2, height / 7);
  pop();

  brick.display();
  brick.move(UP_ARROW, DOWN_ARROW);

  brick2.display();
  brick2.move(SHIFT, OPTION)

  ball.display();
  ball.move();
  ball.borders();

  if (ball.intersects(brick2)) {
    ball.changeDirection();
  }

  if (ball.intersects(brick)) {
    ball.changeDirection();
  }

  push();
  if (ball.x < 0) {
    stroke(255);
    textAlign(CENTER);
    textSize(50);
    text("GAME OVER \nPLAYER 2 WINS", width / 2, height / 2)
  }

  if (ball.x > width) {
    textAlign(CENTER);
    textSize(50);
    text("GAME OVER \nPLAYER 1 WINS", width / 2, height / 2)
  }
  pop();
}

ICM blogpost week 2 – Conditionals and Functions

This week we worked with loops and conditionals. Our homework assignment was to create a sketch that included the following:

  • One element controlled by the mouse.
  • One element that changes over time, independently of the mouse.
  • One element that is different every time you run the sketch.

The extra material this week was a link to ProgrammingDesignSystems by Rune Madsen. I decided to try to replicate one of the illustrations that was provided on the website, as I imagined it would contain many of the functions we went over in class as well as conditions, if statements and loops.

   

The image shows the illustration by Rune. It is a shape where you can drag each corner to a new location and the coordinates will update accordingly on the right side. 

I decided to approach this task using a “Circle” Object. My theory was that using a “isInside” and “mouseIsPressed” function you would be able to drag the circle around on the screen. I then initialized 3 additional circle-objects. These served as the corners of my square. The 4 circles were connected using a “beginShape” / “Endshape” function and the “fill” function was utilized to visualize the shape.

The code can be seen here: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//object circle
var Circle = function(x, y, d) {
this.x = x;
this.y = y;
this.diameter = d;
this.time = 0;
this.outline = 1;
this.display = function() {
strokeWeight(this.outline);
fill(200,100,100,50);
ellipse(this.x, this.y, this.diameter, this.diameter);
}
this.isInside = function() {
var d = dist(mouseX, mouseY, this.x, this.y)
if (d &lt; this.diameter / 2) {
return true;
} else {
return false;
}
}
this.drag = function() {
ellipse(mouseX, mouseY, this.diameter, this.diameter);
}
}

&nbsp;

var isInside = false;
var time = 0;
var outlineSpeed = 0.025;

function setup() {
createCanvas(400, 400);

circle1 = new Circle(random(width / 2), random(height / 2), 30);
circle2 = new Circle(random(width / 2, width), random(0, height / 2), 30);
circle3 = new Circle(random(width / 2), random(height / 2, height), 30);
circle4 = new Circle(random(width / 2, width), random(height / 2, height), 30);

}

&nbsp;

function draw() {
background(220, 200, 200);

time++;

&nbsp;

circle1.outline = circle1.outline + outlineSpeed;
if (circle1.outline &gt; 3 || circle1.outline &lt; 0.2) {
outlineSpeed = outlineSpeed * -1;
}

circle2.outline = circle2.outline + outlineSpeed;
if (circle2.outline &gt; 3 || circle2.outline &lt; 0.2) {
outlineSpeed = outlineSpeed * -1;
}

circle3.outline = circle3.outline + outlineSpeed;
if (circle3.outline &gt; 3 || circle3.outline &lt; 0.2) {
outlineSpeed = outlineSpeed * -1;
}

circle4.outline = circle4.outline + outlineSpeed;
if (circle4.outline &gt; 3 || circle4.outline &lt; 0.2) {
outlineSpeed = outlineSpeed * -1;
}

&nbsp;

beginShape(QUADS);
strokeWeight(1);
fill(200, 100, 100)
vertex(circle1.x, circle1.y)
vertex(circle2.x, circle2.y)
vertex(circle4.x, circle4.y)
vertex(circle3.x, circle3.y)
endShape(CLOSE);

&nbsp;

fill(255);
circle1.display();
circle2.display();
circle3.display();
circle4.display();

&nbsp;

strokeWeight(1);
if (mouseIsPressed &amp;&amp; circle1.isInside()) {
circle1.x = mouseX;
circle1.y = mouseY;
text("Circle x:" + int(circle1.x) + " y:" + int(circle1.y), circle1.x + 20, circle1.y);
}

if (mouseIsPressed &amp;&amp; circle2.isInside()) {
circle2.x = mouseX;
circle2.y = mouseY;
text("Circle x:" + int(circle2.x) + " y:" + int(circle2.y), circle2.x + 20, circle2.y);
}

if (mouseIsPressed &amp;&amp; circle3.isInside()) {
circle3.x = mouseX;
circle3.y = mouseY;
text("Circle x:" + int(circle3.x) + " y:" + int(circle3.y), circle3.x + 20, circle3.y);
}

if (mouseIsPressed &amp;&amp; circle4.isInside()) {
circle4.x = mouseX;
circle4.y = mouseY;
text("Circle x:" + int(circle4.x) + " y:" + int(circle4.y), circle4.x + 20, circle4.y);

&nbsp;

}

}

 

And the sketch looked like this.

  • I met a lot of problems with this sketch. One thing was that I couldn’t get the code to work with a “for loop”, which meant I had to initialize each circle for itself and define all functions for each of the circles 4 times (circle1.display, circle2.display etc).
  • Another problem occured when I was dragging the circle to fast. When doing so the mouse (mouseX,mouseY) would go outside the circle and the dragging would stop. I felt like there needed to be some sort of “mouseReleased” function to solve this. But couldn’t get it to work.

With the code doing its job – I met with one of the residents. 1: To simplify the code. 2. To get the dragging optimized.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//object circle
var Circle = function(x, y, d) {
this.x = x;
this.y = y;
this.diameter = d;
this.time = 0;
this.outline = 1;
this.display = function() {
strokeWeight(this.outline);
fill(200, 100, 100, 50);
ellipse(this.x, this.y, this.diameter, this.diameter);
}
this.containsMouse = function() {
var d = dist(mouseX, mouseY, this.x, this.y)
if (d &lt; this.diameter / 2) {
return true;
} else {
return false;
}
}
this.drag = function() {
this.x = mouseX;
this.y = mouseY;
}
}

var isInside = false;
var outlineSpeed = 0.025;
var total = 6;
var circles = [];
var circlesClicked = [];
var CircleIsSelected = false;

function setup() {
createCanvas(500, 500);

for (var i = 0; i &lt; total; i++) {
circles.push(new Circle(random(width), random(height), 30));
circlesClicked.push(false);
}
}

function draw() {
background(220, 200, 200);

if (circles[0].outline &gt; 3 || circles[0].outline &lt; 0.2) {
outlineSpeed = outlineSpeed * -1;
}

for (var i = 0; i &lt; total; i++) {
circles[i].outline = circles[i].outline + outlineSpeed;
}

beginShape();
strokeWeight(1);
fill(200, 100, 100)

for (var i = 0; i &lt; total; i++) {
vertex(circles[i].x, circles[i].y);
}
endShape(CLOSE);

fill(255);
for (var i = 0; i &lt; total; i++) {
circles[i].display();
}

for (var i = 0; i &lt; total; i++) {
if ((mouseIsPressed &amp;&amp; circles[i].containsMouse() &amp;&amp; CircleIsSelected == false) || circlesClicked[i] == true) {
circles[i].drag();
text("Circle x:" + int(circles[i].x) + " y:" + int(circles[i].y), circles[i].x + 20, circles[i].y);
circlesClicked[i] = true;
CircleIsSelected = true;
}
}

}

function mouseReleased() {
for (var i = 0; i &lt; total; i++) {
circlesClicked[i] = false;
}
CircleIsSelected = false;
}

This is how the sketch worked after.

Untitled from Simon Jensen on Vimeo.

This was how we managed to simplify the code. One of the main reasons I couldn’t get the “for loop” to work I think had to do with me forgetting to define the array in the beginning (circles = [ ]). I kept getting errors telling me that the function “circles[i]” was unidentified.

Another thing we talked about was the push function and how that is a very neat method to add to the array.

For the dragging we declared some extra boolean functions: CircleIsSelected & CircleClicked. However my head needs some playing around with that to make perfect sense of it all.

ICM Blogpost – week 1

This week we had our first session of: Introduction to Computational Media.
After a brief introduction to each other – we talked about the themes we will be covering over the next weeks. We were introduced to different projects that have previously been produced with programming languages. Projects that may serve as an inspiration to future assignments.

We were introduced to things going on behind the screen when using java and javascript – servers, browsers, clients, HTML and CSS etc. as well as the meaning of high-level/low-level programming languages.

We went over functions such as setup() and draw() – and created a “code” for everyone in class to stand up – imagining how we would tell a program to perform this task. This assignment highlighted the importance of providing the rights queues to a system.

I’m excited for the weeks to come in this class. My background in biology and movement has often presented me with large datasheets that I would like to analyze, present and visualize in new ways. Also I would like to work on projects that analyzes signals from the body: EEG, ECG, EMG, MotionCapture etc. In order to do this it is vital to know how to manage the presented data. Aside from all the practical things I want to do with coding, I find programming very interesting and enjoyable – being able to create projects/visuals/programmes with basically nothing but a computer is very pleasing. Learning how to code is certainly something I will spend much time on during my time at ITP. I have some previous experience with processing. Therefore I also try to challenge myself with a few projects aside from the projects in class. This week it has mainly been on uploading JSON files in P5.js and visualizing them – still working on that. However, it is great to have things refreshed in class and I am sure this class will teach me many new interesting skills.

This weeks assignment was very straightforward – I did not post any issues to Github as I am still trying to figure out exactly how that works. So far I feel more comfortable using the downloaded version of P5.js as I feel like the web.editor version sometimes erases something or starts over. Maybe it’s just a matter of habit and getting used to the online version.