Compare commits

...

47 Commits

Author SHA1 Message Date
gauthiier f076d0469d review 2023-12-18 10:16:50 +01:00
gauthiier 0d0c667d01 review 2023-12-18 08:15:58 +01:00
gauthiier 5374cc530a review 2023-12-18 08:14:32 +01:00
gauthiier 4a2fafc8d7 review 2023-12-18 07:25:32 +01:00
gauthiier 3c41d2cbc0 review 2023-12-18 07:24:04 +01:00
gauthiier 17ab94aed0 review 2023-12-18 07:14:05 +01:00
gauthiier 657209f22d review 2023-12-18 07:11:47 +01:00
gauthiier 6ba906075c review 2023-12-18 07:10:06 +01:00
gauthiier 031fa9297d linkbump 2023-12-17 19:06:07 +01:00
gauthiier faa84cae1e dir name 2023-01-18 16:19:26 +01:00
gauthiier f9074de87d exercises 2023-01-18 16:18:38 +01:00
gauthiier de06ae0897 collection 2023-01-18 16:08:26 +01:00
gauthiier 6d4b077d6e cleanup 2023-01-18 13:15:19 +01:00
gauthiier 39b69aa920 quotes 2023-01-17 11:51:26 +01:00
gauthiier 7fa56986fd quotes 2023-01-17 11:50:28 +01:00
gauthiier affaf34975 fix images 2023-01-17 01:17:49 +01:00
gauthiier 2e62bf93d8 save canvas 2023-01-17 01:14:42 +01:00
gauthiier 415ddbe6ab imgs for 3 [lfs] 2023-01-17 01:14:02 +01:00
gauthiier bc4e649a8b exercises and defaults 2023-01-16 22:17:59 +01:00
gauthiier 99cf7fa284 letter output 2023-01-16 21:41:45 +01:00
gauthiier 09dfcae945 letter output 2023-01-16 21:41:14 +01:00
gauthiier 24d49e2d63 letter output 2023-01-16 21:39:41 +01:00
gauthiier 317e343a36 letter-output [lfs] 2023-01-16 21:38:45 +01:00
gauthiier 14a561b3d1 Love letter code 2023-01-16 21:29:52 +01:00
gauthiier e30d4097dd Love letter algo 2023-01-16 21:04:31 +01:00
gauthiier 953780d09e Love letter 2023-01-16 10:43:25 +01:00
gauthiier 641a48ed4d Love letter 2023-01-16 10:05:54 +01:00
gauthiier 60793487cb Love letter 2023-01-16 09:36:14 +01:00
gauthiier cb0a22d55e Love letter 2023-01-16 09:27:57 +01:00
gauthiier 1013350c52 Love letter 2023-01-16 09:18:52 +01:00
gauthiier 64dc00df15 Link et al. 2023-01-15 19:01:45 +01:00
gauthiier f1e31dd06f Strachey 1 2023-01-15 17:55:16 +01:00
gauthiier 51ae4990f8 Strachey 0 2023-01-15 15:47:46 +01:00
gauthiier d8bb137ad2 Strachey 0 2023-01-15 15:44:40 +01:00
gauthiier 3e08c94efd Strachey [lfs] 2023-01-15 15:39:57 +01:00
gauthiier 8ccd8d0cf7 exercise 2.2 2023-01-15 14:49:48 +01:00
gauthiier 51c5be2bfc in-text code (bis) 2023-01-15 14:23:32 +01:00
gauthiier b5d0e5f878 in-text code (bis) 2023-01-15 14:21:11 +01:00
gauthiier 946306b727 in-text code 2023-01-15 14:19:02 +01:00
gauthiier 0c53817f75 random 2023-01-15 14:15:14 +01:00
gauthiier 8e9af8b04c random 2023-01-15 14:13:18 +01:00
gauthiier 96de810c75 loop exercise 2023-01-15 12:34:36 +01:00
gauthiier 6f0ddc2595 loop 2023-01-15 12:22:25 +01:00
gauthiier ee6c80b7ad loop 2023-01-15 12:21:11 +01:00
gauthiier cc23f7c914 loop 2023-01-15 12:17:36 +01:00
gauthiier d731bd9375 who is undefined 2023-01-15 11:40:47 +01:00
gauthiier 0a3e10a93e undefined [lfs] 2023-01-15 11:39:49 +01:00
26 changed files with 1365 additions and 31 deletions
+29 -3
View File
@@ -1,14 +1,40 @@
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/autopilot-creativity.png" alt="autopilot creativity" width="350" style="display: block; margin: 0 auto;" /> <p align="center">
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/autopilot-creativity.png" alt="autopilot creativity" width="350" style="display: block; margin: 0 auto;" />
</p>
# Framing the (art historical) debate: (Pre-, Post-) Modern? # Framing the (art historical) debate: (Pre-, Post-) Modern?
> The history of the digital and computer-aided arts could be told as a history of ignorance against programming and programmers. Computer programs get locked into black boxes, and programmers are frequently considered to be mere factota, coding slaves who execute other artists concepts. (Cramer 101-102) Cramer, Florian. “Concepts, Notations, Software Art.” In *Signwave, Auto-Illustrator Users Guide*, 10112. Liquid Press/Spacex, 2002.
> To discuss “software art” simply means to not take software for granted, but pay attention to how and by whom programs were written. If data doesnt exist without programs, it follows that the separation of processed “data” (like image and sound files) from “programs” is simply a convention. (Cramer 105) > The history of the digital and computer-aided arts could be told as a history of ignorance against programming and programmers. Computer programs get locked into black boxes, and programmers are frequently considered to be mere factota, coding slaves who execute other artists concepts. (Cramer 1)
> A computer program is a blueprint and its execution at the same time. Like a pianola roll, it is a score performing itself. [...] Computer programming collapses, as it seems, the second and third of the three steps of concept, concept notation and execution. (Cramer 4)
> Contrary to conventional data like digitized images, sound and text documents, the algorithmic instruction code allows a generative process. It uses computers for computation, not only as storage and transmission media. [...]
> There is, after all, no such thing as data without programs, and hence no digital arts without the software layers they either take for granted, or design themselves. To discuss “software art” simply means to not take software for granted, but pay attention to how and by whom programs were written. If data doesnt exist without programs, it follows that the separation of processed “data” (like image and sound files) from “programs” is simply a convention. (Cramer 5)
> If software is generally defined as executable formal instructions, logical scores, then the concept of software is by no means limited to formal instructions for computers. (Cramer 5)
_Work 0: [Sol LeWitt's "Plan for a Concept Art Book"](https://www.sollewittprints.org/artwork/lewitt-raisonne-1971-18)_
Cox, Geoff, Alex McLean, and Adrian Ward. “Coding Praxis: Reconsidering the Aesthetics of Code.” In *Read_me: Software Art & Cultures*, edited by Olga Goriunova and Alexei Shulgin, 16174. Aarhus: Aarhus University Press, 2004.
> The paper argued that any separation of code and the resultant actions would simply limit the aesthetic experience [...] Speech and its repre- sentation in writing together form a language that we appreciate as poetry. In the essay we speculated whether code could be seen to work in a similar way? (Cox et al. 161)
> The written form is merely a computer-readable notation of logic, and is a representation of this process. Yet the written code isnt what the computer really executes, since there are many levels of interpreting and compiling and linking taking place. [...] But software itself relies on the deferred action of its author — the code operates on behalf of the programmer, so it is more accurate to consider this as part of a continuing performance. (Cox et al. 164)
Galloway, Alexander R. “Jodis Infrastructure.” *E-Flux*, no. 74 (June 2016).
> Two basic activities emerge. A person may work "on" the digital or "within" it. In the former, one's attention is directed from the outside in, taking the medium itself as its object, while in the latter one takes the perspective of the medium itself, radiating attention outward to other contexts and environments. To generalize from this, the first position (working "on") is labeled modern or, when applied to art and aesthetics, modernist. And the latter position (working "within") is labeled non-modern, be it premodern, postmodern, or some other alternative (Galloway, 1-2). > Two basic activities emerge. A person may work "on" the digital or "within" it. In the former, one's attention is directed from the outside in, taking the medium itself as its object, while in the latter one takes the perspective of the medium itself, radiating attention outward to other contexts and environments. To generalize from this, the first position (working "on") is labeled modern or, when applied to art and aesthetics, modernist. And the latter position (working "within") is labeled non-modern, be it premodern, postmodern, or some other alternative (Galloway, 1-2).
_Work 1: http://㐃.net_
_Work 2: [Ed Atkins, Ribbons](https://www.youtube.com/watch?v=3EkqVWXBVOQ)_
_Other works: https://constantdullaart.com/, https://arambartholl.com_
> Where does the work reside? (Galloway, 5)
> Jodi are thus stubbornly out of step with the dominant rhythms of contemporary art. Less obsessed with the cultural or social effects of new media, Jodi orient themselves toward the specificities of hardware and software. The resulting aesthetic is, in this way, not entirely specified by the artists subjective impulses. Instead, the texture of code and computation takes over, and computing itself—its strange logic, its grammar and structure, and often its shape and color—produces the aesthetic. (Galloway 3). > Jodi are thus stubbornly out of step with the dominant rhythms of contemporary art. Less obsessed with the cultural or social effects of new media, Jodi orient themselves toward the specificities of hardware and software. The resulting aesthetic is, in this way, not entirely specified by the artists subjective impulses. Instead, the texture of code and computation takes over, and computing itself—its strange logic, its grammar and structure, and often its shape and color—produces the aesthetic. (Galloway 3).
+42 -17
View File
@@ -3,17 +3,17 @@
## 👋 p5js Editor ## 👋 p5js Editor
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/editor.p5js.png" alt="autopilot creativity" height="650"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/editor.p5js.png" alt="autopilot creativity" height="650"/>
</p> </p>
## 🤔 How does code work/act? ## 🤔 How does code work/act?
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/raw/branch/main/img/compiler.svg" alt="autopilot creativity" height="150"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/raw/branch/main/img/compiler.svg" alt="autopilot creativity" height="150"/>
</p> </p>
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/raw/branch/main/img/interpreter.svg" height="150"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/raw/branch/main/img/interpreter.svg" height="150"/>
</p> </p>
## Sketch: 0. Hello World ## Sketch: 0. Hello World
@@ -23,11 +23,11 @@
// This is a comment // This is a comment
function setup() { function setup() {
createCanvas(400, 400); createCanvas(800, 800);
} }
function draw() { function draw() {
background(220); background("yellow");
print("Hello World"); // see the console below ↓ print("Hello World"); // see the console below ↓
} }
``` ```
@@ -35,7 +35,7 @@ function draw() {
## 🤔 What kind of "Errors"? ## 🤔 What kind of "Errors"?
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/error.png" height="200"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/error.png" height="200"/>
</p> </p>
## Sketch: 1.0 Key Events ## Sketch: 1.0 Key Events
@@ -44,28 +44,33 @@ function draw() {
// Key Events! // Key Events!
function setup() { function setup() {
createCanvas(400, 400); createCanvas(800, 800);
} }
function draw() { function draw() {
background(220); background("yellow");
// Only when keyIsPressed? // Only when keyIsPressed?
print("Hello World"); print("Hello World");
} }
// Reference: https://p5js.org/reference/ // Reference: https://p5js.org/reference/
``` ```
### 📚 Exercise
1. Modify the sketch 1.0 so that "Hello World" is printed only when a key is pressed. To do so have a look at the [p5js reference](https://p5js.org/reference/)
## Sketch: 1.1 Mouse Events ## Sketch: 1.1 Mouse Events
```javascript ```javascript
// Mouse Events! // Mouse Events!
function setup() { function setup() {
createCanvas(400, 400); createCanvas(800, 800);
} }
function draw() { function draw() {
background(220); background("yellow");
if(mouseIsPressed) { if(mouseIsPressed) {
print("Pressed: " + mouseX + " - " + mouseY) ; // see the console below ↓ print("Pressed: " + mouseX + " - " + mouseY) ; // see the console below ↓
} }
@@ -78,6 +83,11 @@ function mouseMoved() {
// Reference: https://p5js.org/reference/ // Reference: https://p5js.org/reference/
``` ```
### 📚 Exercises
1. Modify sketch 1.1 so that a circle is drawn on the canvas at the location where the mouse is located each time it moves. To do so have a look at [p5js reference](Reference: https://p5js.org/reference/).
2. What can you observe with the circle being drawn on the canvas? Can you modify the sketch so that a trace of the movement of the mouse stay on the canvas and erase itself when the mouse is pressed?
## 🤔 What are (x,y) coordinates (in p5js)? ## 🤔 What are (x,y) coordinates (in p5js)?
@@ -94,11 +104,11 @@ var previous_mouseX_pressed = 0; // global "var" variable
var previous_mouseY_pressed = 0; // global "var" variable var previous_mouseY_pressed = 0; // global "var" variable
function setup() { function setup() {
createCanvas(400, 400); createCanvas(800, 800);
} }
function draw() { function draw() {
// background(220); // background("yellow");
if(mouseIsPressed) { if(mouseIsPressed) {
let current_mouseX_pressed = mouseX; // local "let" variable valid within "{" brackets "}" let current_mouseX_pressed = mouseX; // local "let" variable valid within "{" brackets "}"
let current_mouseY_pressed = mouseY; // local "let" variable valid within "{" brackets "}" let current_mouseY_pressed = mouseY; // local "let" variable valid within "{" brackets "}"
@@ -118,6 +128,12 @@ function mouseMoved() {
// Reference: https://p5js.org/reference/ // Reference: https://p5js.org/reference/
``` ```
### 📚 Exercises
1. Modify sketch 1.2 so that a line is drawn between the location of the current mouse press and the previous location. To do so have a look at [p5js reference](Reference: https://p5js.org/reference/).
2. Modify the sketch further and try erasing what is drawn on the canvas each time a key is pressed.
### Sketch: 1.3 Distance and Text ### Sketch: 1.3 Distance and Text
```javascript ```javascript
@@ -128,11 +144,11 @@ var previous_mouseY_pressed = 0;
var distance_previous_current = 0; var distance_previous_current = 0;
function setup() { function setup() {
createCanvas(400, 400); createCanvas(800, 800);
} }
function draw() { function draw() {
background(220); background("yellow");
distance_previous_current = dist(previous_mouseX_pressed, previous_mouseY_pressed, mouseX, mouseY); // calculate distance distance_previous_current = dist(previous_mouseX_pressed, previous_mouseY_pressed, mouseX, mouseY); // calculate distance
@@ -156,8 +172,17 @@ function draw() {
// Reference: https://p5js.org/reference/ // Reference: https://p5js.org/reference/
``` ```
### 📚 Exercise
1. Modify sketch 1.3 so that:
* if the calculated distance between the previous and current mouse pressed locations is less than 300 then display "🍕" as text at the current mouse location and "PIZZA" at the previous location
* if the calculated distance between the previous and current mouse pressed locations is less than 600 then display "🍍" as text at the current mouse location and "ANANAS" at the previous location
* Otherwise display "😵‍💫" as text at the current mouse location and "WOOOOO" at the previous
## 🤔 What are conditional statements (i.e. if-statements)? ## 🤔 What are conditional statements (i.e. if-statements)?
Below are what is commonly called "if-statements":
```javascript ```javascript
if(conditionX) { if(conditionX) {
// if conditionX is true then // if conditionX is true then
@@ -180,14 +205,14 @@ if(conditionX) {
} }
``` ```
Ok ok, but what are "conditions" then? Ok, but what are "conditions" (i.e. conditionX, conditionY, conditionZ, etc.) then?
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/comp-operators.png" width="100%"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/comp-operators.png" width="100%"/>
</p> </p>
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/logic-operators.png" width="100%"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/logic-operators.png" width="100%"/>
</p> </p>
+687 -8
View File
@@ -1,7 +1,7 @@
# Ghost Writing: Text, Arrays, Randomness # Ghost Writing: Text, Arrays, Loops, and Randomness
<p align="center"> <p align="center">
<img src="https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/love-letter.png" alt="autopilot creativity" width="80%"/> <img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/love-letter.png" width="80%"/>
</p> </p>
## Sketch: 2.0 Array + Index ## Sketch: 2.0 Array + Index
@@ -37,13 +37,692 @@ function keyTyped() {
0 1 2 3 4 5 <--- indices (var INDEX) 0 1 2 3 4 5 <--- indices (var INDEX)
``` ```
### 📚 Exercice ### 📚 Exercise
1. Modify sketch 2.0 so that: 1. Modify sketch 2.0 so that:
* When key 'k' is pressed then "Hi Karin!" is printed on the console * When key ```'k'``` is typed then ```"Hi Karin!"``` is printed on the console
* When key 's' is pressed then "Hi Sigrid!" is printed on the console * When key ```'s'``` is typed then ```"Hi Sigrid!"``` is printed on the console
* When key 'n' is pressed then "Hi Nanna!" is printed on the console * When key ```'n'``` is typed then ```"Hi Nanna!"``` is printed on the console
* When key 'm' is pressed then "Hi Maaike!" is printed on the console * When key ```'m'``` is typed then ```"Hi Maaike!"``` is printed on the console
2. Modify sketch 2.0 so that: 2. Modify sketch 2.0 so that:
* Every time key 'x' is pressed then print the name of the following person in the array ("Hi David!", "Hi Karin!", "Hi Sigrid!", and so forth) * Every time key ```'x'``` is typed then print the name of the following person in the array (```"Hi David!"```, ```"Hi Karin!"```, ```"Hi Sigrid!"```, and so forth)
### 🤔 Who/what is "undefined"?
<p align="center">
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/undefined.png">
</p>
## Sketch: 2.1 Array + Index + Loop
```javascript
// Array + Index + Loop!
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
var INDEX = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
function keyTyped() {
if(key == 'x') {
for(let i = 0; i < ACTIVITIES.length; i++) {
print(NAMES[INDEX] + " likes to play " + ACTIVITIES[i]);
}
}
}
// Reference: https://p5js.org/reference/
```
### 🤔 How do for-loops work?
```javascript
for(let i = 0; i < X; i++) {
// do_somethings();
}
```
where
```javascript
let i = 0
// is the declaration and initialisation of the control variable (i)
i < X
//is the loop continuation condition: if the condition is true, the statement in the loop [do_something();] is executed, otherwise exit the loop when the condition is false
i++
//is the incremental (update) statement that is executed at the end of the loop (i.e. just after the loop statement [do_something();] as been executed)
```
### 📚 Exercise
1. Modify sketch 2.1 so that every name listed in the ```NAMES``` array have all activities listed in the ```ACTIVITIES``` array printed out on the console when key ```'x'``` is typed. The console output should look like this:
```
Karin likes to play piano
Karin likes to play tennis
Karin likes to play chess
Karin likes to play records
Sigrid likes to play piano
Sigrid likes to play tennis
Sigrid likes to play chess
Sigrid likes to play records
Nanna likes to play piano
Nanna likes to play tennis
Nanna likes to play chess
(etc.)
```
## Sketch: 2.2 Array + Index + Randomness
Randomness in p5js is based on generating a random number between 0 and a specified maximum.
Typically a random number is produced with the ```random``` function:
```javascript
random(X); // generates a random number between 0 and X
````
Here is an example of how to use the function with a variable:
```javascript
let random_number = random(10); // assign a random number between 0 and 10 to variable random_number
````
Rudimentary indeed, but there are many things we can build with this simple function!
### 🤔 How to select a random element in an array?
Since we access elements of an array with indices, we can generate a random index between 0 and the length of an array to select a random element in it.
The first problem we must solve though is that the ```random``` functions generates a "real" number (ex: 4.993319470244624, 1.9486631456631776, 7.1841821754535813, etc.) while the indices of an array are "integer" (whole) numbers (5, 2, 7, etc.). We thus need to round the "real" numbers produced by random to get an “integer” (4.993319470244624 -> 5, 1.9486631456631776 -> 2, 7.1841821754535813 -> 7).
We do this with the ```floor``` function that simply rounds a number down (4.993319470244624 -> 4) to the nearest integer. Here is an example:
```javascript
let random_number = floor(random(10)); // assign a random integer number between 0 and 10 to variable random_number
````
With this we can generate a random index (integer) between 0 and the length of a given array. Below is an example that picks a random name in the ```NAMES``` array.
```javascript
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
let random_index_names = floor(random(NAMES.length));
print(NAMES[random_index_names]);
````
This snippet of code will indeed print a random name in the array ```NAMES``` each time it is executed.
But what if we would like to print a random activity from the ```ACTIVITIES``` array as well?
```javascript
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
let random_index_names = floor(random(NAMES.length));
let random_index_activities = floor(random(ACTIVITIES.length));
print(NAMES[random_index_names] + " likes to play " + ACTIVITIES[random_index_activities]);
````
This will work, but it is not "elegant"... Why?
Because we have here two variables (```random_index_names```, ```random_index_activities```) that are assigned a random value with the respective arrays' length (```NAMES.length```, ```ACTIVITIES.length```). What if we had many arrays? Then we would need as many variables as there are arrays to select from right? Consequently, the code would be very long!
To remediate this tedious need to write too much code, how about writing a custom function that selects a random element from an "generic" array? Writing custom functions is central in writing programs that are structured and “modular.”
Here is an example of a custom ```choice``` function taking a “generic” array as input ```array_to_choose_from``` and returns a randomly selected elements from this array:
```javascript
// function selecting a random element from an array
function choice(array_to_choose_from) {
let random_index = floor(random(array_to_choose_from.length));
return array_to_choose_from[random_index];
}
````
Now with this custom ```choice``` function it is rather simple to select random names or activities from the ```NAMES``` and ```ACTIVITIES``` arrays. In fact, we can start inventing sentences whose constituting phrases or words can be randomised.
Here is an example:
```javascript
// Array + Index + Randomness!
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
// function selecting a random element from an array
function choice(array_to_choose_from) {
let random_index = floor(random(array_to_choose_from.length));
return array_to_choose_from[random_index];
}
function keyTyped() {
if(key == 'x') {
print(choice(NAMES) + " likes to play " + choice(ACTIVITIES) + " with " + choice(NAMES));
}
}
// Reference: https://p5js.org/reference/
````
### 📚 Exercise
1. Modify sketch 2.2 by adding a day of the week when an activity is taking place. For example, the output could look like this:
```
David likes to play records with Karin on Tuesday
```
2. Come up with your own random sentences! Remember you can add as many arrays to select from as you wish. Most languages are structured "systems" having nouns, verb, adjectives, adverbs, etc. Below is the output of a random sentence generator I came up with yesterday (can you guess what my code might look like?):
```
Laura wears a blue sweater when Sigrid plays tennis
Karin wears a black cap when Karin plays records
Laura wears a expensive scarf when Karin plays records
Karin wears a yellow jacket when Sigrid plays chess
David wears a ridiculous scarf when Sigrid plays records
Karin wears a black jacket when Maaike plays chess
```
## ✍️ Christopher Strachey's Love Letters
<p align="center">
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/Strachey-Mark1.png" width="100%"/>
</p>
So now that we have a better understanding of how arrays, indices, randomness, and functions work, let's write love letters!
One of the first non-scientific computer program that was ever written is Christopher Strachey's Love Letters program devised for the Manchester Mark I (the so called [Baby](https://content.presspage.com/uploads/1369/1920_themanchestermk1computerbuiltbyextendingthebaby.jpg?10000)). In fact, this computer program (written in 1952 and making use of randomness) is arguably the first art-inspired program!
Christopher Strachey was/is a computer programming pioneer who worked along Alan Turing in the very early days of computing at the University of Manchester. Strachey's story is fascinating. There is a great article about [him and the love letters on Rhizome's Queer History of Computing written by Jacob Gaboury](https://rhizome.org/editorial/2013/apr/9/queer-history-computing-part-three/). For those who are interested in researching Strachey's work, please have a look at his [papers and correspondences at the Bodleain library's archive](https://archives.bodleian.ox.ac.uk/repositories/2/resources/2561).
Strachey's Love Letters have been studied before. [David Link](http://www.alpha60.de) did a colossal reconstitution of the Love Letters program on a simulator of the Manchester Mark I computer. [The work was exhibited circa 2010](http://www.alpha60.de/art/love_letters/). Strachey's program does not look at all like the code we are writing now! The picture on the right side of the image above (☝️) is from Link's simulator. Early computers did not have the compilers and interpreters we have now (remember compilers and interpreters?) and thus the code was written in a rather cryptic way (believe me, way more cryptic than what we are writing now).
The program we are about to write in a "modern" computing language (i.e. javascript/p5js) is a modified version of [Nick Montfort](https://nickm.com)'s letter.py code written in python (another programming language). Montfort's letter.py was based on Noah Wardrip-Fruin's article ["Digital Media Archaeology."](https://www.degruyter.com/document/doi/10.1525/9780520948518-016/html)
### Analysing Love Letters' structure
First, let's have a look at love letters to see what they look like.
David Link has generated an [archive of simulated letters](http://www.alpha60.de/art/love_letters/archive/muc/).
Here are five examples:
```
HONEY MOPPET
YOU ARE MY AMOROUS RAPTURE.: MY KEEN LOVE. MY COVETOUS
INFATUATION THIRSTS FOR YOUR FERVENT LIKING. YOU ARE MY
CRAVING LIKING. MY CURIOUS RAPTURE FONDLY THIRSTS FOR YOUR
ANXIOUS ENCHANTMENT.
YOURS COVETOUSLY
MUC
```
```
DEAR DARLING
MY ADORABLE FELLOW FEELING WANTS YOUR SWEET INFATUATION
. MY ADORABLE ARDOUR LOVINGLY WISHES YOUR FERVOUR. MY
UNSATISFIED FELLOW FEELING EAGERLY HUNGERS FOR YOUR IMPATIENT
DESIRE. YOU ARE MY LOVING FERVOUR. MY WINNING WISH YEARNS FOR YOUR
KEEN HEART.
YOURS FERVENTLY
MUC
```
```
HONEY HONEY
MY BURNING FANCY EAGERLY TEMPTS YOUR INFATUATION.
YOU ARE MY FERVENT YEARNING. MY LIKING BEAUTIFULLY YEARNS FOR YOUR
LOVE. MY APPETITE TENDERLY CHERISHES YOUR BEAUTIFUL WISH.
YOU ARE MY EROTIC ADORATION.
YOURS SEDUCTIVELY
MUC
```
```
DARLING LOVE
YOU ARE MY AMOROUS ENCHANTMENT.: MY KEEN EAGERNESS.
YOU ARE MY DEVOTED ENCHANTMENT. MY YEARNING FERVENTLY LIKES
YOUR AMOROUS PASSION. MY EAGERNESS TENDERLY YEARNS FOR YOUR
PASSION.
YOURS ARDENTLY
MUC
```
```
HONEY LOVE
MY AVID CHARM EAGERLY LOVES YOUR LOVING ENTHUSIASM. MY
AMBITION LUSTS AFTER YOUR LOVE. MY HUNGER THIRSTS FOR YOUR
ENTHUSIASM. MY ADORABLE LONGING AFFECTIONATELY PINES FOR YOUR
DEVOTION. MY FONDNESS PASSIONATELYFTER YOUR IMPATIENT
FERVOUR.
YOURS KEENLY
MUC
```
Can you decipher certain word patterns in the above formulations? If so, what are they?
Consider the following sentences:
```
MY YEARNING FERVENTLY LIKES YOUR AMOROUS PASSION.
MY APPETITE TENDERLY CHERISHES YOUR BEAUTIFUL WISH.
```
Are there common words here? Yes, the "MY" and "YOUR" right?
What about the other words, do they have something in common? Yes. They are sequences of nouns, adverbs, verbs, and adjectives. And these have indeed a particular position in each sentence.
We can thus devise a "code" or "template" of the sentences as follow:
MY + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
We could even add an ```adjective``` before the first ```noun``` as to make it even more "wordy" yet still valid linguistically speaking:
MY + ```adjective``` + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
Are there other types of sentences in the letter above?
Consider this sentence, whose structure seems to come up often:
```
YOU ARE MY AMOROUS RAPTURE.
```
Let's "code" this like:
YOU ARE MY + ```adjective``` + ```noun``` + .
There is also this small phrase:
```
MY KEEN EAGERNESS.
```
Which can be "coded" as:
MY + ```adjective``` + ```noun``` + .
So overall we have two types of sentences:
* 1x long form: MY + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
* 2x short forms: YOU ARE MY + ```adjective``` + ```noun``` + . / MY + ```adjective``` + ```noun``` + .
Also, in terms of composition or sentences sequencing we can notice that:
1. A letter always starts with a certain opening {HONEY or DEAR or DARLING} + {MOPPET or DARLING or HONEY or LOVE}
2. the short form MY + ```adjective``` + ```noun``` + . always follows the other short form YOU ARE MY + ```adjective``` + ```noun``` + . This short form never follows the long form.
3. short form YOU ARE MY + ```adjective``` + ```noun``` + . is never followed by the same short form YOU ARE MY + ```adjective``` + ```noun``` + .
4. A letter comprises between 4 and 5 sentences (long or short form)
5. A letter is always closed with YOURS + ```adverb```
6. A letter is always signed by MUC (which means Manchester University Computer)
### Reconstituting Love Letters' algorithm
Now that we have an idea of the structure of Strachey's letters, let's get to work in formalising their algorithmic generation.
Luckily, in terms of vocabulary, we can start with Monfort's archaeological work that gives the following vocabulary in an array forms:
```javascript
// vocabulary
const first = ['DARLING', 'DEAR', 'HONEY', 'JEWEL'];
const second = ['DUCK', 'LOVE', 'MOPPET', 'SWEETHEART'];
const adjectives = ['ADORABLE', 'AFFECTIONATE', 'AMOROUS', 'ANXIOUS', 'ARDENT', 'AVID', 'BREATHLESS', 'BURNING', 'COVETOUS', 'CRAVING', 'CURIOUS', 'DARLING', 'DEAR', 'DEVOTED', 'EAGER', 'EROTIC', 'FERVENT', 'FOND', 'IMPATIENT', 'KEEN', 'LITTLE', 'LOVEABLE', 'LOVESICK', 'LOVING', 'PASSIONATE', 'PRECIOUS', 'SWEET', 'SYMPATHETIC', 'TENDER', 'UNSATISFIED', 'WISTFUL'];
const nouns = ['ADORATION', 'AFFECTION', 'AMBITION', 'APPETITE', 'ARDOUR', 'CHARM', 'DESIRE', 'DEVOTION', 'EAGERNESS', 'ENCHANTMENT', 'ENTHUSIASM', 'FANCY', 'FELLOW FEELING', 'FERVOUR', 'FONDNESS', 'HEART', 'HUNGER', 'INFATUATION', 'LIKING', 'LONGING', 'LOVE', 'LUST', 'PASSION', 'RAPTURE', 'SYMPATHY', 'TENDERNESS', 'THIRST', 'WISH', 'YEARNING'];
const adverbs = ['AFFECTIONATELY', 'ANXIOUSLY', 'ARDENTLY', 'AVIDLY', 'BEAUTIFULLY', 'BREATHLESSLY', 'BURNINGLY', 'COVETOUSLY', 'CURIOUSLY', 'DEVOTEDLY', 'EAGERLY', 'FERVENTLY', 'FONDLY', 'IMPATIENTLY', 'KEENLY', 'LOVINGLY', 'PASSIONATELY', 'SEDUCTIVELY', 'TENDERLY', 'WINNINGLY', 'WISTFULLY'];
const verbs = ['KICKS', 'ADORES', 'ATTRACTS', 'CARES FOR', 'CHERISHES', 'CLINGS TO', 'DESIRES','HOLDS DEAR', 'HOPES FOR', 'HUNGERS FOR', 'IS WEDDED TO', 'LIKES', 'LONGS FOR', 'LOVES', 'LUSTS AFTER', 'PANTS FOR', 'PINES FOR', 'PRIZES', 'SIGHS FOR', 'TEMPTS', 'THIRSTS FOR', 'TREASURES', 'WANTS', 'WISHES', 'WOOS', 'YEARNS FOR'];
```
We can randomly select from these arrays with our ```choice``` function we devised earlier:
```javascript
// function selecting a random element from an array
function choice(array_to_choose_from) {
let random_index = floor(random(array_to_choose_from.length));
return array_to_choose_from[random_index];
}
```
With both these elements (arrays and ```choice```) we can start devising the code of the long form we identified above.
MY + ```noun``` + ```adverb``` + ```verb``` + YOUR + ```adjective``` + ```noun``` + .
Let's do this coding by devising a custom function again. Let's name it ```long```:
```javascript
// function that randomly generates a long form sentence
function long() {
return "MY " + choice(nouns) + " " + choice(adverbs) + " " + choice(verbs) + " YOUR " + choice(adjectives) + " " + choice(nouns) + ".";
}
````
This will certainly work. Yet I would like to have more variation with the sentences the function returns. As it stands it will always follow the long form structure. Is there a way we can achieve this with injecting some randomness in the structure?
How about we make ```adjective``` and ```adverb``` non mandatory, meaning they might be printed or not. What I have in mind is something like:
```javascript
// function that randomly generates a long form sentence
function long() {
return "MY " + maybe(adjectives) + " " + choice(nouns) + " " + maybe(adverbs) + " " + choice(verbs) + " YOUR " + maybe(adjectives) + " " + choice(nouns) + ".";
}
````
Notice the ```maybe``` that replaces ```choice```?
Let's write this ```maybe``` function that randomly chooses true or false if an element should be chosen from a given array, which in our case will be adjectives or adverbs.
```javascript
// function that randomly decides if an element from an array should be selected or not
function maybe(array_to_choose_from) {
// choose between true or false
if(choice([true, false])) {
// if true then return an element from the array
return choice(array_to_choose_from);
} else {
// otherwise return and empty sentence (i.e. nothing)
return "";
}
}
````
With this ```maybe``` function we now have a way to diversify the letter's sentences and thus produce more variations of our generated long forms.
How about the short forms?
YOU ARE MY + ```adjective``` + ```noun``` + .
MY + ```adjective``` + ```noun``` + .
We can simply write a ```short``` function like this:
```javascript
// function that randomly generates a short form sentence
function short() {
return choice(adjectives) + ' ' + choice(nouns) + '. ';
}
```
And prefix it with YOU ARE MY or MY when we are in the midst of writing the sequence of sentences. This might become clearer below.
How about the opening? Notice the ```first``` and ```second``` arrays in the vocabulary. These are exactly what we need:
```javascript
// function that randomly an opening
function opening() {
return choice(first) + ' ' + choice(second);
}
```
And the closing?
YOURS + ```adverb```
Simple:
```javascript
// function that randomly a closing
function closing() {
return "YOURS " + choice(adverbs);
}
```
Great. Now we have most of the ingredients in place with the functions ```choice```, ```maybe```, ```long```, ```short```, ```opening```, ```closing``` right?
How about sequencing ```long``` and ```short``` forms? Remember what we observed above (points 2, 3, 4):
2. the short form MY + ```adjective``` + ```noun``` + . always follows the other short form YOU ARE MY + ```adjective``` + ```noun``` + . This short form never follows the long form.
3. short form YOU ARE MY + ```adjective``` + ```noun``` + . is never followed by the same short form YOU ARE MY + ```adjective``` + ```noun``` + .
4. A letter comprises between 4 and 5 sentences (long or short form)
Following these observation here is a skeleton of an algorithm doing just that:
```javascript
// start with an empty text
var text = "";
// did we just wrote the short form with "YOU ARE MY" (points #2 and #3)
let YOU_ARE_MY = false;
// loop 5 times to generate 5 sentences (point #4)
for(let i = 0; i < 5; i++) {
// choose if the next sentence is a short or long
let sentence_form = choice(['short', 'long']);
if(sentence_form == 'short') {
// there's two types of short to switch from
// (#2) the short form MY + ```adjective``` + ```noun``` + .
// always follows the YOU ARE MY + ```adjective``` + ```noun``` + . one
// and
// (#3) the short form YOU ARE MY + ```adjective``` + ```noun``` + . one
// can never follow itself
// this means we need keep track of when "YOU ARE MY" is generated
// and switch to the other form next time. This is what the variable
// YOU_ARE_MY is doing
if(YOU_ARE_MY) {
// the ": MY" can only follow a "YOU ARE MY" (point #2)
text += ": MY " + short();
YOU_ARE_MY = false;
} else {
text += "YOUR ARE MY " + short();
// the "YOU ARE MY" cannot follow another "YOU ARE MY"(point #3)
YOU_ARE_MY = true;
}
}
else if(sentence_form == 'long') {
text += long();
// make sure the next sentence is not ": MY"
YOU_ARE_MY = false
}
}
````
### Putting it all together
Ok, let's formalise what we have sketched above and write a custom ```write_letter``` function that returns and full love letter.
```javascript
// function returning a love letter
function write_letter(){
// the letter's text we will fill in
var text = "";
// write the letter's opening
text += opening();
text += "\n"; // this is a new line!
// did we just wrote the short form with "YOU ARE MY"
let YOU_ARE = false;
// write 5 sentences
for(let i = 0; i < 5; i++) {
// choose if the next sentence is a short or long
let sentence_form = choice(['short', 'long']);
if(sentence_form == 'short') {
// there's two types of short to switch from
if(YOU_ARE) {
// the ": MY" can only follow a "YOU ARE MY"
text += ": MY " + short();
YOU_ARE = false;
} else {
text += "YOUR ARE MY " + short();
// the ": MY" can only follow a "YOU ARE MY"
YOU_ARE = true;
}
} else if(sentence_form == 'long') {
text += long();
// make sure the next sentence is not ": MY"
YOU_ARE = false;
}
}
text += "\n"; // this is a new line!
// write the letter's closing
text += " " + closing();
text += "\n"; // this is a new line!
// sign
text += "MUC";
// return the letter's text
return text;
}
```
This function follows the algorithm we wrote above and adds the opening and closing sequence.
If you followed me during the session, you should have a sketch looking more or less like the one below comprising all the functions we wrote.
Here the letter is printed when ```x```is typed.
```javascript
// Strachey's Love Letter generator!
// vocabulary
const first = ['DARLING', 'DEAR', 'HONEY', 'JEWEL'];
const second = ['DUCK', 'LOVE', 'MOPPET', 'SWEETHEART'];
const adjectives = ['ADORABLE', 'AFFECTIONATE', 'AMOROUS', 'ANXIOUS', 'ARDENT', 'AVID', 'BREATHLESS', 'BURNING', 'COVETOUS', 'CRAVING', 'CURIOUS', 'DARLING', 'DEAR', 'DEVOTED', 'EAGER', 'EROTIC', 'FERVENT', 'FOND', 'IMPATIENT', 'KEEN', 'LITTLE', 'LOVEABLE', 'LOVESICK', 'LOVING', 'PASSIONATE', 'PRECIOUS', 'SWEET', 'SYMPATHETIC', 'TENDER', 'UNSATISFIED', 'WISTFUL'];
const nouns = ['ADORATION', 'AFFECTION', 'AMBITION', 'APPETITE', 'ARDOUR', 'CHARM', 'DESIRE', 'DEVOTION', 'EAGERNESS', 'ENCHANTMENT', 'ENTHUSIASM', 'FANCY', 'FELLOW FEELING', 'FERVOUR', 'FONDNESS', 'HEART', 'HUNGER', 'INFATUATION', 'LIKING', 'LONGING', 'LOVE', 'LUST', 'PASSION', 'RAPTURE', 'SYMPATHY', 'TENDERNESS', 'THIRST', 'WISH', 'YEARNING'];
const adverbs = ['AFFECTIONATELY', 'ANXIOUSLY', 'ARDENTLY', 'AVIDLY', 'BEAUTIFULLY', 'BREATHLESSLY', 'BURNINGLY', 'COVETOUSLY', 'CURIOUSLY', 'DEVOTEDLY', 'EAGERLY', 'FERVENTLY', 'FONDLY', 'IMPATIENTLY', 'KEENLY', 'LOVINGLY', 'PASSIONATELY', 'SEDUCTIVELY', 'TENDERLY', 'WINNINGLY', 'WISTFULLY'];
const verbs = ['KICKS', 'ADORES', 'ATTRACTS', 'CARES FOR', 'CHERISHES', 'CLINGS TO', 'DESIRES','HOLDS DEAR', 'HOPES FOR', 'HUNGERS FOR', 'IS WEDDED TO', 'LIKES', 'LONGS FOR', 'LOVES', 'LUSTS AFTER', 'PANTS FOR', 'PINES FOR', 'PRIZES', 'SIGHS FOR', 'TEMPTS', 'THIRSTS FOR', 'TREASURES', 'WANTS', 'WISHES', 'WOOS', 'YEARNS FOR'];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
// function selecting a random element from an array
function choice(array_to_choose_from) {
let random_index = floor(random(array_to_choose_from.length));
return array_to_choose_from[random_index];
}
// function that randomly decides if an element from an array should be selected or not
function maybe(array_to_choose_from) {
// choose between true or false
if(choice([true, false])) {
// if true then return an element from the array
return choice(array_to_choose_from);
} else {
// otherwise return and empty sentence (i.e. nothing)
return "";
}
}
// function that randomly generates a long form sentence
function long() {
return "MY " + maybe(adjectives) + " " + choice(nouns) + " " + maybe(adverbs) + " " + choice(verbs) + " YOUR " + maybe(adjectives) + " " + choice(nouns) + ".";
}
// function that randomly generates a short form sentence
function short() {
return choice(adjectives) + ' ' + choice(nouns) + '. ';
}
// function that randomly an opening
function opening() {
return choice(first) + ' ' + choice(second);
}
// function that randomly a closing
function closing() {
return "YOURS " + choice(adverbs);
}
// function returning a love letter
function write_letter(){
var text = "";
// write opening
text += opening();
text += "\n"; // this is a new line!
let YOU_ARE = false;
// write 5 sentences
for(let i = 0; i < 5; i++) {
// choose if the next sentence is a short or long
let sentence_form = choice(['short', 'long']);
if(sentence_form == 'short') {
// there's two types of short to switch from
if(YOU_ARE) {
// the ": MY" can only follow a "YOU ARE MY"
text += ": MY " + short();
YOU_ARE = false;
} else {
text += "YOUR ARE MY " + short();
// the ": MY" can only follow a "YOU ARE MY"
YOU_ARE = true;
}
} else if(sentence_form == 'long') {
text += long();
// make sure the next sentence is not ": MY"
YOU_ARE = false;
}
}
text += "\n"; // this is a new line!
// write closing
text += " " + closing();
text += "\n"; // this is a new line!
// sign
text += "MUC";
// return the letter
return text;
}
function keyTyped() {
if(key == 'x') {
let letter = write_letter();
print(letter);
}
}
// Reference: https://p5js.org/reference/
```
The output of our program looks like this:
<p align="center">
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/letter-output.png"/>
</p>
There might be minor formatting issues with the code above. I'll let you fix them as you inspect what the code does when it prints to the console.
+177
View File
@@ -0,0 +1,177 @@
# Drawing with numbers: Drawing primitives & image manipulation
## Sketch: 3.0 Drawing text
So far, we have mainly dealt with text printed on the console. Pretty 1980 is you ask me. It is an aesthetic (of course) though we can also display text on the canvas as well!
Consider the following sketch using the ```text ``` function.
```javascript
// Drawing text!
const sentence = "YOU ARE MY AMOROUS ENCHANTMENT.: MY KEEN EAGERNESS. YOU ARE MY DEVOTED ENCHANTMENT. MY YEARNING FERVENTLY LIKES YOUR AMOROUS PASSION. MY EAGERNESS TENDERLY YEARNS FOR YOUR PASSION."
function setup() {
createCanvas(800, 800);
}
function draw() {
background("yellow");
text(sentence);
}
```
What do you observe when you run the sketch?
### 📚 Exercises
To complete the following exercices, have a loot at the section Typography in the [p5js reference](https://p5js.org/reference/).
1. Modify the sketch 3.0 and enlarge the text's font size.
2. Create a "text box" in which the text can be displayed in full (i.e. wrapped in the box).
3. Can you change the font of the text?
4. How about the font colour?
5. And the text's alignment (left, center, right)?
6. Homework: Using p5js' typography functionality, write Love Letters on the canvas resembling the original letter from the MUC.
## Sketch: 3.1 Simple colour animation
Let's play with colours with the following sketch.
```javascript
// Colour animation!
const sentence = "I DON'T LIKE PIZZA\n(I just don't)";
function setup() {
createCanvas(800, 800);
}
function draw() {
background("yellow");
textSize(45);
textAlign(CENTER, TOP);
noStroke();
fill(0, 0, 255);
text(sentence, 800/2, 800/2);
}
````
Remember sinusoidal waveforms in your Mathematics class in school? Well they are fabulous!
Sinus and Cosinus are great trigonometric functions to play with as they can help produce simple animations. Sinusoidals (sinus or cosinus) have interesting properties that can easily be parametrised.
<p align="center">
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/sinusoidal.png"/>
</p>
In our p5js environment there is a ```sin``` function that can be used along a special ```frameCount``` counter that literally keeps track of the number of frames that have been drawn on the canvas. By inputting ```frameCount``` to the ```sin``` function it will return a real number between -1 and 1 (see figure above). In fact this real number will “oscillate” between -1 and 1, following the sinusoidal waveform.
A statement like to one below will roughly oscillate between 0 and 255 each time ```frameCount``` is incremented.
```javascript
let osc = 128 + sin(frameCount) * 127;
```
### 📚 Exercises
1. Can you explain why there is a 128 and a 127 in the statement above?
2. Modify sketch 3.1 and change the colour of the text with the ```osc``` variable above.
3. What do you observe? How can the speed of colour change be slower? In other words, is there a way to slow down the ```frameCount``` input of the ```sin``` function?
## Sketch: 3.2 Keeping track of clicks with arrays and animate shapes
In sketch 1.1 we drew circles on the canvas when we pressed the mouse. One problem we had was with the background remember? The ```background``` function was erasing our circles.
Now that we understand arrays we can fix this problem by "recording" the location where the mouse was pressed. To do so we will produce a "record" of each mousse press y adding the location of the mousse when pressed to an array. This "record" will be a [p5js vector](https://p5js.org/reference/#/p5/createVector) having a X and Y coordinate.
```javascript
// Capture mouse pressed and record locations!
var circles = []; // this is the array in which we will add p5js vectors
function setup() {
createCanvas(800, 800);
}
function draw() {
background("yellow");
if(mouseIsPressed) {
let v = createVector(mouseX, mouseY); // create a vector with the current mouseX and mouseY coordinates
circles.push(v); // add the vector to our array with the "push" function
}
// now for each vector in our array, draw a circle at its location
for(let i = 0; i < circles.length; i++) {
let c = circles[i];
circle(c.x, c.y, 10);
}
}
```
The drawing produced by the sketch looks very much like sketch 1.1 right?
True. But with this code we can draw more interesting things than we could in sketch 1.1. Since we have a global array (```circles```) we can access each circle and animate them in different ways, something that was practically impossible in sketch 1.1.
### 📚 Exercises
1. Modify sketch 3.2 and make the circle oscillate (i.e. changing each circle's X and Y position) using the ```sin``` function and p5js' ```frameCount```
2. Add randomness to your circles' oscillation so that each individual circle moves slightly differently than its neighbours.
## Sketch: 3.3 Image
With p5js we can also work with images. The way this works is to upload them to our online environment by opening the "Sketch files" and the left side of the page and select upload files.
<p align="center">
<img src="https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/img/upload.png"/>
</p>
When the image is uploaded, we can display it on the canvas as follow (for this sketch I am using [this image](https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/src/branch/main/img/alan-turing.png)):
```javascript
// Image!
var alan_img; // global image variable
var img_x, img_y; // coordinates of the image on the canvas
// special function that loads the image to our global variable
function preload() {
alan_img = loadImage("alan-turing.png")
}
function setup() {
createCanvas(800, 800);
// to draw the image at the center of the canvas
// we need to offset the image coordinates with
// the half of image's width and height
img_x = 400 - alan_img.width/2;
img_y = 400 - alan_img.height/2;
}
function draw() {
background("yellow");
// draw the image as the specified coordinate
image(alan_img, img_x, img_y);
}
```
Now this is rather simple. You can of course play with the coordinates of the image as we did with our circles above but have a look the Image section in the [p5js reference](https://p5js.org/reference/) and consider the simple manipulations you can use on your image.
### 📚 Exercises
1. Modify sketch 3.3 so that the "alpha" channel of the image changes when the mouse is moved to the right (X coordinate). The ```tint``` function will help you do that.
2. Now do the same for the B channel (RGB) when the mouse is moved up and down (Y coordinate). Again, the ```tint``` function will help you do that.
3. There is a way to save your canvas as an image with p5js' ```saveCanvas``` function. Add this functionality to your sketch and save it when the key ```s``` is typed.
+3 -3
View File
@@ -9,9 +9,9 @@ In this workshop we will address the underlying texts and infrastructural contex
In preparation for the workshop we ask you to read the following texts and get acquainted with the programming environment we will be using during the session. The listed manual and tutorials are here for you to get a grasp of the programming environment and the practice of programming more generally. The manual by Winnie Soon and Geoff Cox has some interesting critical reflections at the beginning of each chapter that are worth reading in preperation for our session. In preparation for the workshop we ask you to read the following texts and get acquainted with the programming environment we will be using during the session. The listed manual and tutorials are here for you to get a grasp of the programming environment and the practice of programming more generally. The manual by Winnie Soon and Geoff Cox has some interesting critical reflections at the beginning of each chapter that are worth reading in preperation for our session.
Texts: Texts:
* Cramer, Florian. “Concepts, Notations, Software Art.” In *Signwave, Auto-Illustrator Users Guide*, 10112. Liquid Press/Spacex, 2002. [Link](https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/texts/Cramer_2002_Concepts_Notations_Software_Art.pdf) * Cramer, Florian. “Concepts, Notations, Software Art.” In *Signwave, Auto-Illustrator Users Guide*, 10112. Liquid Press/Spacex, 2002. [Link](https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/texts/Cramer_2002_Concepts_Notations_Software_Art.pdf)
* Cox, Geoff, Alex McLean, and Adrian Ward. “Coding Praxis: Reconsidering the Aesthetics of Code.” In *Read_me: Software Art & Cultures*, edited by Olga Goriunova and Alexei Shulgin, 16174. Aarhus: Aarhus University Press, 2004. [Link](https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/texts/Cox-McLean-Ward_2004_Coding_Praxis.pdf) * Cox, Geoff, Alex McLean, and Adrian Ward. “Coding Praxis: Reconsidering the Aesthetics of Code.” In *Read_me: Software Art & Cultures*, edited by Olga Goriunova and Alexei Shulgin, 16174. Aarhus: Aarhus University Press, 2004. [Link](https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/texts/Cox-McLean-Ward_2004_Coding_Praxis.pdf)
* Galloway, Alexander R. “Jodis Infrastructure.” *E-Flux*, no. 74 (June 2016). [Link](https://git.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/texts/Galloway_2016_Jodi_Infrastructure.pdf) * Galloway, Alexander R. “Jodis Infrastructure.” *E-Flux*, no. 74 (June 2016). [Link](https://grrrit.le-club-des-sans-sujets.org/gauthiier/Revisiting-Concepts-Notations-Software-Art/media/branch/main/texts/Galloway_2016_Jodi_Infrastructure.pdf)
Programming environment: Programming environment:
* P5.js: https://p5js.org/ * P5.js: https://p5js.org/
+14
View File
@@ -0,0 +1,14 @@
// Sketch 1.0: Key Events!
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
if(keyIsPressed) {
print("Hello World"); // see the console below ↓
}
}
// Reference: https://p5js.org/reference/
+20
View File
@@ -0,0 +1,20 @@
// Sketch 1.1: Mouse Events!
function setup() {
createCanvas(800, 800);
}
function draw() {
// background("yellow");
if(mouseIsPressed) {
print("Pressed: " + mouseX + " - " + mouseY) ; // see the console below ↓
background("yellow"); // 2
}
}
function mouseMoved() {
print("Moved: " + mouseX + " - " + mouseY) ; // see the console below ↓
circle(mouseX, mouseY, 10);
}
// Reference: https://p5js.org/reference/
+28
View File
@@ -0,0 +1,28 @@
// Sketch 1.2: Variables!
var previous_mouseX_pressed = 0; // global "var" variable
var previous_mouseY_pressed = 0; // global "var" variable
function setup() {
createCanvas(400, 400);
}
function draw() {
// background(220);
if(mouseIsPressed) {
let current_mouseX_pressed = mouseX; // local "let" variable valid within "{" brackets "}"
let current_mouseY_pressed = mouseY; // local "let" variable valid within "{" brackets "}"
print("Pressed: " + current_mouseX_pressed + " - " + current_mouseY_pressed) ;
previous_mouseX_pressed = current_mouseX_pressed;
previous_mouseY_pressed = current_mouseY_pressed;
}
}
// this is a special p5 function
function mouseMoved() {
print("Moved: " + mouseX + " - " + mouseY) ; // see the console below ↓
}
// Reference: https://p5js.org/reference/
+47
View File
@@ -0,0 +1,47 @@
// Sketch 1.3: Distance and Text!
var previous_mouseX_pressed = 0;
var previous_mouseY_pressed = 0;
var distance_previous_current = 0;
function setup() {
createCanvas(800, 800);
}
function draw() {
background("yellow");
distance_previous_current = dist(previous_mouseX_pressed, previous_mouseY_pressed, mouseX, mouseY);
circle(previous_mouseX_pressed, previous_mouseY_pressed, 5);
line(previous_mouseX_pressed, previous_mouseY_pressed, mouseX, mouseY);
circle(mouseX, mouseY, 5);
// text(distance_previous_current, mouseX, mouseY);
if(distance_previous_current < 200) {
text("🍕", mouseX, mouseY);
text("PIZZA", previous_mouseX_pressed, previous_mouseY_pressed);
} else if (distance_previous_current < 350) {
text("🍍", mouseX, mouseY);
text("ANANAS", previous_mouseX_pressed, previous_mouseY_pressed);
} else {
text("😵‍💫", mouseX, mouseY);
text("WOOOOO", previous_mouseX_pressed, previous_mouseY_pressed);
}
if(mouseIsPressed) {
let current_mouseX_pressed = mouseX;
let current_mouseY_pressed = mouseY;
print("Pressed: " + current_mouseX_pressed + " - " + current_mouseY_pressed) ;
previous_mouseX_pressed = current_mouseX_pressed;
previous_mouseY_pressed = current_mouseY_pressed;
}
}
// Reference: https://p5js.org/reference/
+21
View File
@@ -0,0 +1,21 @@
// Sketch 2.0: Array + Index!
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
var INDEX = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
function keyTyped() {
if(key == 'x') {
print("Hi " + NAMES[INDEX] + "!");
INDEX++;
}
}
// Reference: https://p5js.org/reference/
+25
View File
@@ -0,0 +1,25 @@
// Sketch 2.1: Array + Index + Loop!
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
var INDEX = 0;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
function keyTyped() {
if(key == 'x') {
for(let j = 0; j < NAMES.length; j++) {
for(let i = 0; i < ACTIVITIES.length; i++) {
print(NAMES[j] + " likes to play " + ACTIVITIES[i]);
}
}
}
}
// Reference: https://p5js.org/reference/
+28
View File
@@ -0,0 +1,28 @@
// Sketch 2.2: Array + Index + Randomness!
var NAMES = ["David", "Karin", "Sigrid", "Nanna", "Laura", "Maaike"];
var ACTIVITIES = ["piano", "tennis", "chess", "records"];
var ADJ = ["blue", "yellow", "black", "orange", "fabulous", "expensive", "ridiculous"];
var CLOTHES = ["jacket", "sweater", "cap", "scarf"];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
// function selecting a random element from an array
function choice(array_to_choose_from) {
let random_index = floor(random(array_to_choose_from.length));
return array_to_choose_from[random_index];
}
function keyTyped() {
if(key == 'x') {
print(choice(NAMES) + " wears a " + choice(ADJ) + " " + choice(CLOTHES) + " when " + choice(NAMES) + " plays " + choice(ACTIVITIES));
}
}
// Reference: https://p5js.org/reference/
+24
View File
@@ -0,0 +1,24 @@
// Sketch 3.0: Drawing Text!
const sentence = "YOU ARE MY AMOROUS ENCHANTMENT.: MY KEEN EAGERNESS. YOU ARE MY DEVOTED ENCHANTMENT. MY YEARNING FERVENTLY LIKES YOUR AMOROUS PASSION. MY EAGERNESS TENDERLY YEARNS FOR YOUR PASSION."
function setup() {
createCanvas(800, 800);
}
function draw() {
// backgroud colour (click on swatch)
background("rgb(101,240,101)");
// font
textFont('Courier');
// font stroke colour
stroke(0, 0, 255);
// font fill colour
fill(255, 140, 0);
// text size
textSize(30);
// aligment
textAlign(CENTER, TOP);
// creates a 800 by 800 text box
text(sentence, 0, 10 , 800, 800);
}
+25
View File
@@ -0,0 +1,25 @@
// Sketch 3.1: Colour animation!
const sentence = "I DON'T LIKE PIZZA\n(I just don't)";
function setup() {
createCanvas(800, 800);
}
function draw() {
background("yellow");
textSize(45);
textAlign(CENTER, TOP);
noStroke();
let osc = 128 + sin(frameCount * 0.1) * 127;
// print(variation);
let R = osc;
let G = 255 - osc;
let B = osc;
fill(R, G, B);
text(sentence, 800/2, 800/2);
}
+24
View File
@@ -0,0 +1,24 @@
// Sketch 3.2: Capture mouse pressed and record locations!
var circles = [];
function setup() {
createCanvas(800, 800);
}
function draw() {
background("yellow");
if(mouseIsPressed) {
let v = createVector(mouseX, mouseY);
circles.push(v);
}
for(let i = 0; i < circles.length; i++) {
let c = circles[i];
let x = c.x + cos(frameCount * 0.1) * random(3);
let y = c.y + sin(frameCount * 0.1) * random(3);
circle(x, y, 10);
}
}
+31
View File
@@ -0,0 +1,31 @@
// Sketch 3.3: Image!
var alan_image;
var img_x, img_y;
function preload() {
alan_image = loadImage("alan-turing.png")
}
function setup() {
createCanvas(800, 800);
img_x = 400 - alan_image.width/2;
img_y = 400 - alan_image.height/2;
colorMode(RGB, 255, 255, 255, 255);
}
function draw() {
background("yellow");
image(alan_image, img_x, img_y);
let R = 255;
let G = 100;
let B = mouseY / 800.0 * 255;
let A = mouseX / 800.0 * 255;
tint(R, G, B, A);
}
function keyTyped() {
if(key == 's') {
saveCanvas("yeah", "png");
}
}
+113
View File
@@ -0,0 +1,113 @@
// Strachey's Love Letter generator!
// vocabulary
const first = ['DARLING', 'DEAR', 'HONEY', 'JEWEL'];
const second = ['DUCK', 'LOVE', 'MOPPET', 'SWEETHEART'];
const adjectives = ['ADORABLE', 'AFFECTIONATE', 'AMOROUS', 'ANXIOUS', 'ARDENT', 'AVID', 'BREATHLESS', 'BURNING', 'COVETOUS', 'CRAVING', 'CURIOUS', 'DARLING', 'DEAR', 'DEVOTED', 'EAGER', 'EROTIC', 'FERVENT', 'FOND', 'IMPATIENT', 'KEEN', 'LITTLE', 'LOVEABLE', 'LOVESICK', 'LOVING', 'PASSIONATE', 'PRECIOUS', 'SWEET', 'SYMPATHETIC', 'TENDER', 'UNSATISFIED', 'WISTFUL'];
const nouns = ['ADORATION', 'AFFECTION', 'AMBITION', 'APPETITE', 'ARDOUR', 'CHARM', 'DESIRE', 'DEVOTION', 'EAGERNESS', 'ENCHANTMENT', 'ENTHUSIASM', 'FANCY', 'FELLOW FEELING', 'FERVOUR', 'FONDNESS', 'HEART', 'HUNGER', 'INFATUATION', 'LIKING', 'LONGING', 'LOVE', 'LUST', 'PASSION', 'RAPTURE', 'SYMPATHY', 'TENDERNESS', 'THIRST', 'WISH', 'YEARNING'];
const adverbs = ['AFFECTIONATELY', 'ANXIOUSLY', 'ARDENTLY', 'AVIDLY', 'BEAUTIFULLY', 'BREATHLESSLY', 'BURNINGLY', 'COVETOUSLY', 'CURIOUSLY', 'DEVOTEDLY', 'EAGERLY', 'FERVENTLY', 'FONDLY', 'IMPATIENTLY', 'KEENLY', 'LOVINGLY', 'PASSIONATELY', 'SEDUCTIVELY', 'TENDERLY', 'WINNINGLY', 'WISTFULLY'];
const verbs = ['KICKS', 'ADORES', 'ATTRACTS', 'CARES FOR', 'CHERISHES', 'CLINGS TO', 'DESIRES','HOLDS DEAR', 'HOPES FOR', 'HUNGERS FOR', 'IS WEDDED TO', 'LIKES', 'LONGS FOR', 'LOVES', 'LUSTS AFTER', 'PANTS FOR', 'PINES FOR', 'PRIZES', 'SIGHS FOR', 'TEMPTS', 'THIRSTS FOR', 'TREASURES', 'WANTS', 'WISHES', 'WOOS', 'YEARNS FOR'];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
}
// function selecting a random element from an array
function choice(array_to_choose_from) {
let random_index = floor(random(array_to_choose_from.length));
return array_to_choose_from[random_index];
}
// function that randomly decides if an element from an array should be selected or not
function maybe(array_to_choose_from) {
// choose between true or false
if(choice([true, false])) {
// if true then return an element from the array
return choice(array_to_choose_from);
} else {
// otherwise return and empty sentence (i.e. nothing)
return "";
}
}
// function that randomly generates a long form sentence
function long() {
return "MY " + maybe(adjectives) + " " + choice(nouns) + " " + maybe(adverbs) + " " + choice(verbs) + " YOUR " + maybe(adjectives) + " " + choice(nouns) + ".";
}
// function that randomly generates a short form sentence
function short() {
return choice(adjectives) + ' ' + choice(nouns) + '. ';
}
// function that randomly an opening
function opening() {
return choice(first) + ' ' + choice(second);
}
// function that randomly a closing
function closing() {
return "YOURS " + choice(adverbs);
}
function write_letter(){
var text = "";
// write opening
text += opening();
text += "\n"; // this is a new line!
let YOU_ARE = false;
// write 5 sentences
for(let i = 0; i < 5; i++) {
// choose if the next sentence is a short or long
let sentence_form = choice(['short', 'long']);
if(sentence_form == 'short') {
// there's two types of short to switch from
if(YOU_ARE) {
// the ": MY" can only follow a "YOU ARE MY"
text += ": MY " + short();
YOU_ARE = false;
} else {
text += "YOUR ARE MY " + short();
// the ": MY" can only follow a "YOU ARE MY"
YOU_ARE = true;
}
} else if(sentence_form == 'long') {
text += long();
// make sure the next sentence is not ": MY"
YOU_ARE = false;
}
}
text += "\n"; // this is a new line!
// write closing
text += " " + closing();
text += "\n"; // this is a new line!
// sign
text += "MUC";
// return the letter
return text;
}
function keyTyped() {
if(key == 'x') {
let letter = write_letter();
print(letter);
}
}
// Reference: https://p5js.org/reference/
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.