Transcripts

1. Introduction: Hello, everyone. I'm Hadeel, and this is Intro to Generative Art. In this class, we'll learn the basic concepts of programming and some processing specific functions to create this generative art piece. Processing is a Java-based language, and it's one of the simplest ways to learn how to go. Not only does it grants the opportunity to learn a widespread language, but it also provides instant visual results. We'll also reference the processing documentation page to demonstrate how to get the most out of Processing, which will surely help you as you create your project. Additionally, I'll show you how to make use of a Processing library to export the results into a vector format. A great way to either save high-quality images or manipulate the work further using software like Adobe Illustrator. By the end of this class, you should be able to program and produce an original piece. They will be your fancy certificate to showcase to the world. Let's get started. 2. Coding Basics: First things first, you need to know the basic concepts of any programming language to be able to go through this class. They're very easy to understand and with practice you'll be able to create a generative design per day with these. Hard coding every precision values, size, or color can turn into a tedious task at time, especially when you need to edit values for an array of shapes, that's why we need something called variables. A variable is simply a name you set for a value to save it in memory, to use it throughout the program. In general, for example, if you want to set circle's radius, you type circleRadius equals 100, as in a 100 pixels. Now the program understand that circleRadius is a 100 pixels because we defined it. In processing however, this statement is missing a very important keyword, which means your program can throw an error because of it. The keyword is int. Int stands for integers, and it's one of processing's datatypes. There are several datatypes in processing that you can use in your programs, such as int for integers, float for decimal numbers, string for text, char for characters, boolean for true and false values, color for hues, arrays for ordered lists, and dictionaries for key value lists. In this course we'll only use integers, floats, arrays, and colors. Since we're creating a grid, it means we will be drawing a bunch of shapes on the canvas, which seems like a lot of work until you learn about loops. Loops are a great way to do the same task multiple times without the hassle of typing that task over and over again. One way to create a loop is by using the ''For keyword'' like this. The first part of the statement specifies the beginning of the loop, the second part states when to stop a loop, and third part is your increment value, and whatever code you want to repeat those inside the loop body. Sometimes inside loops or any other part of the sketch, we need to control the flow of our code by using "If conditionals". This is useful if you want to execute a block of code only when a statement evaluates to true, wanting to only color shapes if they're an even numbered columns. The last thing we need to know about in this lesson are functions and methods, these two statements are somewhat the same. Methods are basically functions that belong to a class, so they're not defined directly inside the program like functions. We don't need to know a ton about functions for this course other than, it's a statement that holds a block of code that you can call anywhere in your program by typing its name and passing in the appropriate type and amount of arguments. As you go through this course, you'll grasp all of the information in this lesson and don't worry about memorizing anything right now, everyone goes back to the documentation every now and then, especially in the beginning. 3. Intro to Processing: Processing has three main components that you need to be aware of: The text editor, where you write your code, the console, where you usually debug your code and Canvas, where you can view your design. Also each processing file is conventionally referred to as a sketch. In each sketch we have two functions forming the basis workout. One is called setup, and the other is called draw. The setup function encompasses the settings of your sketch and it's called once when you run the program. While the draw function includes the rest of your code and it's executed for every frame until you stop the program. Now that we have all that information, let's explore the functions that we can use to set up our environment. First, we have the size function which determines the size of our Canvas. For the project, I suggest a three by two ratio or a square. The scale itself doesn't matter, mainly because we'll be exporting our sketch into a vector file that can be easily adjusted after export. I'll be using 600 by 400 for the duration of this course. Another function we can call in setup is the background function, which determines the background color of the Canvas. The background color to use is of course, up to you. I'll be using this color. We'll also use the noLoop function to stop the draw function from looping. This is because we want to create a static design. Instead, you can create static designs by writing the full code inside of the set up function. But this seems a bit counterintuitive, and a little confusing, so we'll be using the noLoop function. Another processing function that we'll be using throughout this course is the ellipse function. This is specific to the design that we are creating. However, there's an assortment of shape functions that you can use to create other shapes like squares, arcs and lines. Let's head onto processing to demonstrate what we just learned. Before we do anything with processing, we need to download the software. The way to do that is by going to processing.org, and then going to the download processing link. Now you can find the operating system that you need and download it, for me it's Mac OS. I'm going to just click on that. The file should be downloaded. Unzip the file, and install it. Now let's open processing. Once you open processing, you should see a blank file like this. To set up the environment, we first define the setup and draw functions. To do that, we just do void setup. The reason why we're using void, is because this function doesn't return anything, and so void, as in empty doesn't return anything, and void draw. Now that we defined the setup and draw function, we can set up the environment by setting the size of the Canvas. We can do that by using the size function, as we saw previously in the video. Size function expects two arguments. We said we're going to use 600 by 400. Feel free to choose whatever size you like. Then we'll do a background of zero for now. Now inside the draw function, we're going to draw the ellipse. We can do that by using the ellipse function, which expects four arguments. We can pass four arguments. The first two are going to be the position of the center of that ellipse. The second two arguments are going to be the width and height of that ellipse. Because we want to create a circle, the width and height are going to be equal. In our coordinate system, we have the x and y-axis. We want that to be in the center of the page, so zero for x and zero for y, which is the center of our coordinate system, is on the top left of our canvas. If we wanted to go to the center of that canvas, we basically tell it to go to the width divided by half, and then the height divided by half. Processing has very useful variables called width and height. They get their values from the size function. Since 600 is the width of our Canvas, and 400 is the height of our canvas, width is going to be 600 and height is going to be 400. If you want to center it horizontally, then we divide the width by two. Then if we wanted to do it vertically, we divided height by two. For the width and height, let's just do 100 by 100. The width and height are basically the diameter of the circle. If we run it, you can either click the Run button over here or you can do Command R. Now we can see that we have a circle on a background that is black. 4. Perusing the Documentation: I mentioned in a previous video that we can use a different shape instead of just using the ellipse that I'm using. So we can do that by going to the Reference page, and this is basically the Documentation page for all things processing. So whatever functions you need, whatever operators you need, anything that you need that is related to processing, you can find in this page. If you go to the Shape section in the Documentation page, and you go down to the 2D Primitives, you can see that there are several shapes that you can use. There's an Arc function, there is a Circle function, there is a Line function, there's also a Rect function, so feel free to choose whatever you like. So I am going to demonstrate with the Ellipse function that we just used. If you go to the Ellipse Function page and you go down here, you can see that this is the syntax of this function. This is how you write a function in your code. Then in the Argument section in the function, so A, B, C, and D, which are the arguments for the Ellipse function, you can see the definition of them down here. So for A, it's a float, and it's the X-coordinate of the ellipse. And then B is the Y-coordinate of the ellipse. Then C and D are the width and height of that ellipse. I use this to create circles, but feel free to choose the actual Circle function to create your own circles. If you go back and see how we can write that, you can see an example, and then you can see that it has an X and Y as the first two arguments. For the third argument, you can see that this is the extent of the circle. There are a lot more shapes that you can use, as you saw in the 2D Primitives section, and feel free, of course, to use whatever you like to make your project as unique as possible. 5. Planning the Grid: To create a grid, you'll first need to understand how the concept works. Usually, before programming something, you plan it on a piece of paper or mentally, then you write your pseudocode and finally you start coding. This makes the task at hand a lot easier. As we said before, the zero-zero point on our coordinate system lies on the top left corner of our canvas. Besides, another thing to note is that the coordinate system is flipped vertically. So the Y positives are at the bottom, as opposed to how we learned it in math. So if we need to move down the canvas, you add to the Y value. If you need to move up, you subtract from the Y-value. The x-axis in programming works precisely like in math. Going to the right is positive and going to the left is negative. Let's visualize a grid. To draw a grid, we need to know the number of columns and rows. Let's say we want a 15 by 10 grid. Now we know that we need to define the number of columns and rows to create a grid. Those are our first two variables. Next we know that we need to figure out the width and height of each cell in that grid to determine the maximum size of our shapes. We can do that by dividing the width by the number of columns and the height by the number of rows. Those are the dimensions of our cells and there are our next two variables. The last thing that we need to figure out are the X and Y positions of each shape. If we draw a circle at zero, zero it'll be positioned at the top left corner of the first cell, which is on the top op left corner of the first cell, which is on the top left corner of the canvas. Now if you want to push that circle to the center of that cell, I can simply to add half the width of that cell to the X position of that circle and add half of the height of that cell, do the Y position of that circle. This will push our shape to the center of that. So this works because circles and ellipses are drawn from the center. For rectangles and squares, however, they're drawn from the top left corner. So we don't need to put them anywhere to center them. Head on to the next lesson to see how we can do this programmatically. 6. Creating the Grid: Now that we have conceptualized how to create grids using processing, let head on to processing and start applying those concepts. First, let's define all the variables we need for this design. There are four variables we need to initialize. The first two are the number of columns and rows and they should be integers because we can't have half a column or row. The second two are the dimensions of each cell. To avoid having unnecessary gaps on the right and bottom side of the grid, we have to make those variables floats because we're dividing two numbers that may not result in a whole number. I'll declare the variables outside of the functions to make them global so that I can use them everywhere in the program. If I declared the variables inside either the setup or the draw function. I make them local variables. I can only access inside of their respective functions. Now that the variables are declared, I can initialize them inside of the setup function by passing in the values I require. I chose to have a grid of 15 by 10 for now. So I'll make the columns 15 and the rows 10 and you can use shortcuts for your variables. I used cols to refer to columns. Next, I'll initialize the cell width and the cell height variables by dividing width, which is the width of the canvas, by the number of columns, and dividing height by the number of rows. I'll do cell width, and again, I'm saying cell W or I'm typing cell W to refer to cell width and that'll be the width divided by columns. Then cell height will be the height divided by rows. I can do something else to make this code shorter which is, instead of writing int over here and over here, I can remove the second one and add a comma between columns and rows. So now I know that columns is an int and row is an int, and the program knows that as well. I'll do the same thing for the floats. Let's make use of loops to be able to draw a bunch of rectangles to create our grid. To do that, we can use the for loop syntax, which goes like this for int i equals 0. This is our variable or our initializer and then the condition is i is less than the columns and lastly, incrementing the i variable by doing i plus plus, which means i is incrementing by one. Then we close the parentheses and we open the code block. Now, if we create a rectangle inside of this, and we gave it a position of zero, zero. Lets give it cell width and cell height and run our program. So now we actually have 15 squares on top of each other. We need to move across the canvas, how can we do that? We can utilize the i variable to move each rectangle to its position. Instead of zero, which is hard-coded, we have to use the variable i. But if you used i without multiplying it by the cell width, then we'll only incrementing by one. So if I run this right now, we'll see that there are only moving one point or one pixel. If I needed to move by the width of the cell, then I need to multiply it by the cell width and now we have our columns. But how do we create the rows for each column? We can do that by looping through each column and adding a bunch of for loops for it. The way we can do that is by using a loop inside of our other loop. If I do for int and I have to choose a different variable because it can't use i anymore since it's used already in this for loop. So I'll choose j and make it equal to zero and then the condition for this is going to be less than rows because we want to move across the height of the canvas and then j plus plus to increment it, close the parentheses and close the curly braces. Now we'll have to invent this to understand that it's inside of two for loops. Now if I run this again, we'll see that nothing has changed. However, something has changed because now we have 10 rows on top of each other, but we need to move them across the height of the canvas. We'll do the same thing that we did with the columns but this time we'll use the j variable because a j is referring to each row. So I'll multiply j by the cell height and now if I run it, it should work. Now that we have created our grid, let's change those rectangles into circles because that's the design that we're looking for. If I go over here and change rect to ellipse, this should work because they have the same amount of arguments in the same arrangement. The x and y position for the first two and the width and height for the second or for the ellipse here, its diameter. If I run this, I can see that all my ellipses have shifted to the left and the top. The reason for that is because they're drawn from the center. As we said before in the previous lesson, we have to add half of the width of the cell to the x position and half the height of the cell to the y position of that ellipse to center it. So if you go back over here and add cell width divided by two and here, cell height divided by two. This should center in the cells and we have our grid of circles. 7. Adding Color: There are generally two color models to use in processing, RGB and HSB. RGB stands for red, green, and blue, while HSB stands for hue, saturation, and brightness. Throughout this course, I'll be focusing mainly on RGB. RGB values go from 0-255, zero being the darkest and 255 being the brightest. Each of the functions concerning color like background, stroke, and fill take three arguments, red, green, and blue respectively. If all three values are identical, then you get a grayscale color mode. For instance, if you pass in zeros, you get black, and if you pass in 255s you get white. You can achieve comparable results using one argument of a value from 0-255. Otherwise, combine the quantity you need of each color to get the shapes you require. Let's say, you fancy a bright red color, in this case, you pass 255 to only the first argument, and if you require an orange, then you add in a bit of green. You can experiment with colors as much as you want until you perceived the concept. Though there is a more straightforward approach to choosing color values for your designs, and that is by using a color wheel. One way to do that is by using Adobe Color. Choose colors using the Adobe Color website, you type in color.adobe.com, and it'll take you to the Adobe Color website. You can choose colors in the Explore Section by going over here where it says view all sources. If I go down and go to color theme, I can choose most popular, most used, and then once I open a palette, I can see that I can copy and paste the hexadecimal values over here, that I can use. Hexadecimal values are exactly like RGB values. We can see this in the Create tab over here, so if I go to the color wheel that we have over here, and go down to color mode, we can see that it's an RGB. If I choose for the first color to scroll all of these to zero, we can see that because they're all zeros now the value is black. You can see that this is red and this is green, this is blue. You can scroll through all of these colors to choose the colors that you like, or you can choose them from the color wheel itself. If you look over here in the hexadecimal values, when I haven't add zeros, then all of these are zeros. So the first two numbers are for red values, the second two are for green, and the third are for blue. The values go from 0-9, and then from A-F. If I want it to be white, the last value is F, so I have to do all Fs. I can see that it's 255 like we did before. This is a great way to choose colors. I usually go to the Explorer tab in Adobe colors, but I can also go to the trends tab, and I can scroll down to graphic design, and if I view more, I can see the trendy colors in the graphic design industry. Then, if I open it I can copy and paste the values and add them to my generative RPC. Hold on to the next lesson to see how we're going to use colors for our design. 8. Randomization: So far we've initialized our variables and nested loops to create 15 columns and 10 rows. By first creating a loop that iterates 15 times, then for each of these columns, we loop 10 times to create 10 rows. This is how our grid looks like now. It's a bit blank without any colors. Let's add a fill function inside of the loop. Whatever color we assign to that fill will be applied to all shapes. We always add the fill function or any coloring function before the shapes that we want to color. Otherwise they won't apply it to that shape. We'll do fill and let's do zero for black. If we run our program right now, we'll see that all of our circles are black. However, we want a bit of randomization. We can do that by using the random function. The random function takes one or two arguments. When you pass in an argument to the random function, then you are only passing in the maximum number and the minimum number will default to zero. However, if you pass two arguments, then you are specifying the minimum and maximum numbers. Since we know that the color values go from zero to 255, we can pass into 255 to the random function. Now we'll get a random number from zero up to 255. Then we can store that value in a variable and use it in the fill function. Let's demonstrate in processing. The random function always returns a decimal numbers, so we'll create a float called col, as in color and assign it a value for random 255. Now we pass this value into the fill function. From what we know about colors, we know that one argument in the fill function means a color from a gray-scale mode. If we run our program, we can see a proof of that. See how the random, but they're all gray-scale. If you want to make the design colorful, then we need to get a random value for each of the R, G and B parameters. Let's instead create three variables, one called R another called G for green, and a third called B for blue and give it a random value also of 255. Now let's add these to the fill function. Let's run the program and now we should see a different color for each of the circles. Let's remove the stroke color to make it a bit more appealing. I'll go in the setup function and add a no stroke function to remove any strokes in our design. You have to always end with a semicolon. If I run my program right now, I can see that it's much better. This is a big step, however, we'd like this to be a bit more controlled, as in we want to choose a specific color theme to apply to the circles. We'll do this in the next lesson. 9. Randomization Continued: In the previous lesson, we created this design by using a random value for red, green, and blue values. But we want this to be more controlled, like we said. To have a more controlled color theme, we need to create an array. This is how arrays work. We have a variable like any other, but its datatype is followed by square brackets, to indicate that it's a list of values. Then to assign values, we opened curly braces and add the values of a datatype we specified before the square brackets. Now accessing these values requires a different syntax from normal variables as well. It starts exactly like variables. However, the variable name now is followed by square brackets. Inside of those square brackets, we pass in the position of that item. Now positions for arrays are called indices. If I want to get the first item in the array I have to pass in the index zero. Because in programming arrays indices start at zero. It's also one of the reasons why we usually start our for loop with an initial value of zero. Let's go and create our colors array. Okay, I have five colors in my color theme that I'm going to copy and paste over here that I want to use for my circles. So first I'll do color because that's the data type of the values, and then followed by square brackets and give that list a name. I'll just call it "colors. " Now I'll copy and paste my colors. These are the five colors that I'm going to choose. I'm using hexadecimal color values because they're shorter than braiding RGB values inside of color functions. Imagine how long this will be if I use the RGB values. Now that we know that the indices go from zero to one less than the length, we know that our colors array has five elements, and so it will start from zero and ends at four. Now we can use that in the random function. So instead of writing all of these, I will remove them and now our fill function will complain because there are no variables called R, G or B. I'll do a flow and give it a value of "r" for random, and I'll do a random of five because it'll go from zero up to five, it will never reach five. But now, when we pass in here using the colors array, and I use the square brackets. Now, I'll use the random function to pass in the index. I know it gets a number from zero up to five, and I'll pass in "r." But now there's an error here because it tells me that there's a type mismatch. "Float" doesn't match with "int." The reason for that is because in here in the array, the indices are only integers, so there are no float numbers. We can change the random function over here to become an integer by doing this. So if I say I want this to be an integer, but now this is complaining because the random function returns a float. So we need to convert it into an integer. The way we can do that is by using the "int" function, by passing the random function into the "int" function. Then now I get a random number from zero to four, or from zero up to five. But it'll round it down to the indices that I need. We can check what the "r" variable is returning by printing it in the console. So the way we can do that is by using the "println" function. Println basically prints the value that we pass it in to the console and it creates a new line for every value, so it's easier for us to see it. So if you print the "r" variable and run my program, I should first see that my colors are all passed in. I can see over here that I'm always getting a random value from zero to four. You can see here's a three, here's zero, here's four, and here as a two and there should be one somewhere over here. So we know that our random function works, and of course we can see it visually over here. That's why processing is a great way to learn programming for designers because it's more visual than any other programming language. Now let's get the background color that I was using in my project. So as you can see here, I have the background color and the brown color that I choose, and I have my specific color palette instead of arbitrary random colors. Now let's randomize the size of each of these circles. So if you go back to the program, we can see over here that the width and height of the ellipse is fixed. So we have to remove this and replace it with a random function. We can do random, and then I want it to go up to the cell width and also cell height. However, this is going to create a problem for us. Let's see what this is going to result in. So you see how it ellipses now not circles, because we're passing in a random function for each of the two. We need to create a variable for the size to get one random value for the width and height. So I'll do float, circleSize. Now we have a circleSize that has a random value of cell width, and we passed it in as an argument. If we run the program, we can see that we have circles of random size. We finally succeeded in creating the design that we want to create. However, in the design that I shared, we had some circles on top of other circles that had different sizes as well. So the way we can do that is by using an if conditional. We can get to that in the next lesson. 10. Controling the Flow: We saw in our last lesson that we created a grid of circles of different sizes and different colors. However, in the same project that I shared with you, I had some circles on top of other circles. The way we can do this as we said in the previous lesson, is by using if conditionals. If I go over here and write an if conditional, that checks if the column is an even number. We know that the columns are referred to with the variable i. I can say if i module two equals zero, and what this is doing is basically dividing i by two and checking if the remainder of that is zero. If it's zero, then it's divisible by two, which means it's an even number. The modulo sign returns the remainder of the division. Now we can open the brackets. We can put the ellipse function inside of the block. Now if we run it, we can see that we only see that circles are drawn inside as even number tolerance. The reason why it starts from the beginning is because our indices start from zero or our values in the i and j variables start from zero, and zero is divisible by two, and so it is considered an even number, even though it's not. We'll get zero and then this is going to be one, the column number one, so it's not even. There are no circles in there, and then we have two, four and so on and so forth. We can enhance our code by choosing a random number. Instead of having it too controlled, I wanted it to be a little bit more arbitrary. If I create a random number, let's call it random position, Pos for position, and I wanted to be an integer, and I'll show you why. I'll give it a random value from zero to two. I'll just pass into this will only get zeros or ones. Now I can check over here. If random position equal, and you have to be aware that, equal over here is an assignment operator because it's just one equal. However, when you have two equals signs, this is a comparing operator. If I check if random in position equals to zero, then I wanted to draw an ellipse else. Let's do the same thing, but a rectangle, just to see the difference. If I run the program, I can see that there are circles in some places, and rectangles in some other places. The only reason why this is a little bit weird is because square are pushed in like circles. We can remove the added solid and so height, and now we can see that it's a bit better. However, let's get back to the ellipses. Now, we'll see that we got back to the first results. However, the reason why I did this is because I want to create a different ellipse on top of those ellipses. If I go over here and I also do an ellipse, but this time, I want the random number for the size to be a little bit different. I'll do circle size divided by two, and circle size divided by two. I'll get random values, but then I'll divide it by two so it's smaller, and it's on top of the other circle. However, this is not going to change anything just because it's going to be the same color. We have to reassign a cell for this as well. Then seal these circles with this new assigned variable. Now we got our design. What we did here is that we reassigned the r variable that we have up here, and if we run it again, we can see that we get other random values. We can also reassign the circle size variable because now we're only getting this circle size and then we are dividing it by half, so we are always getting half of that circle. But I wanted it to be a bit more random. I wanted it to look like some of the bigger circles have very small circles inside of it, and some of the smaller circle are covered by bigger circles. I can also reassign the circle size variable by also assigning it a value of random cell width, and keep it as circle size. But this time because it's reassigned, we are going to get different values from this variable up here. We can see that we have different size. You can see the yellow part here is very small compared to the orange part that we can see, and you can see over here that there is a very small orange dot inside of our blue circle. 11. Exporting the Design: Now is the point where you add your final tweaks to your project. Because next, we'll be exporting the design. The way I prefer to export such a simple design is using the PDF Library and processing. To use this library we'll first need to import it into a sketch using this syntax. Import, processing, from the processing library I want to get the PDF library, and then I'll use the asterisk to get all of the functions inside of that PDF Library. Basically, the asterisk is indicating that we want to expose all of functionalities inside of that library to our sketch so that we can use it. You can otherwise specify what functions exactly you would like to import from that library. Let's explore what functions we can use to export our final generated art piece. To export our design into a PDF file, we have to begin the saving or the exporting before the background function or the noStroke function, because these are functionalities that are added to our design. I can record by using the beginRecord function. The beginRecord function takes in a type, so I'll give it a PDF type. Then the path where you want your designs to be saved. The files are going to be exported into the sketch folder. However, you can specify a folder that you want to add inside of that sketch folder, and that's what I like to do to make it a bit more organized. I like to call it output and then I'll give the file a name. I'll say, generative grids, and the extension. Now once we begin the recording, we'll have to end it. Because if we begin the recording and never end it, you will never get the file. The file will start saving, but it'll never end saving. I'll have to add it at the end over here. The endRecord function is basically endRecord with parentheses with no arguments inside of it. Now if I run my sketch, it's saved inside of my sketch folder. Let's go and check the sketch folder. They can find where you saved your files if you forgot by right-clicking on the title over here. I can click on the folder and it'll get me to where I saved it. If I double-click on the aperture to open the folder, then I can see that I have my design over here and saved as PDF. Now that we have our PDF file, we can open it in any imaging software. I'll open it and preview because I'm on Mac, but feel free to choose any program that opens a PDF and can save it to an image file. After opening and preview, I'll go to file, export, and then choose PNG. I have the resolution at 300 pixels per inch to get a very high quality image. You should choose where you want to save it, It's saved. Now if we go back over here and preview the file, we can see that the image is very high-quality. As in, there is no pixelation or there is minor pixelation when we scale it up. That's great. Now we have a PDF file and a PNG. 12. Editing the Design in Adobe Illustrator: Next, I'll show you how to open this in Illustrator to manipulate it further. You can right-click and choose, "Open with Adobe Illustrator." Now we have our file. If I double-click on the Clip Group, you can see that I can change every circle. However, opening PDF in Illustrator can be a little bit limiting. If you look in the swatches panel, you can see that there are no swatches over here. The way I would do this is open another file and copy and paste whatever is in here in another Adobe Illustrator file of the same ratio. But I'll show you here how to manipulate it further. If I click on the "Image", the whole image is actually moving because it's inside of a clipping mask. If I go to "Object" and then I go to "Clipping Mask", and I release the mask or use the shortcut Command option 7, and now I can select the circles individually. You can recolor the image, you can resize your shapes however you want. This is how I created my thumbnail for this projects by removing the middle part and adding text to it. So that's basically how you manipulate it in Adobe Illustrator. 13. Your Assignment: For your assignment, you'll create an authentic grid-based generative art piece. You can go above and beyond with your project. However, most importantly, you'll need some sort of randomization in your design. Here are three examples to show you several ways of implementing the random function. For the first example, I created rectangles, each spanning the width and height of a cell in the grid. Then I randomized the colors of these rectangles to get this result. The second example employed rotation to some of the squares drawn on canvas, which is a bit more advanced, since it creates a new matrix for each cell in the grid, then rotates it by 45 degrees or one-fourth of Pi. I also added various stroke weights to some of the squares and randomized the colors of each shape. Last but not least, I created same-sized circles with mixed stroke weights and colors to create this design. If you reference the 2D primitives in the shape section in the documentation page, you should be able to utilize some of them in your project.