To paint a watercolor in JavaScript, we need paper, water, and ink. Step one is paper. Credit: Jared Last week I introduced the concept of generative art, P5.js, and some of the setup woes with P5.js. I left you with a scaffolding repository that gets all the project setup headache out of the way, but we didn’t dig into making anything yet. This week, we’ll begin the process of actually making some art. We’re going to start simple by introducing some basic API concepts and build in just the right amount of randomness while we create the “paper” for our watercolor effect. Getting the look and feel of the paper just right is important with any watercolor. It’s also going to help get us get into the mindset of emulating the real world in a digital space. The goal of the rest of this post is to create the effect of real paper for the background of our watercolor. I’d like our paper to be an off-white, cream, or beige color, and it should have a little texture to it. Note that I’m calling our background “paper” (the thing I’m trying to mimic) and not “the canvas element” (the implementation terminology). Thinking in terms of the real world rather than the digital space is a little mental trick to get me out of the implementation details and help guide my intuition. Create a color background in P5.js Our scaffolding already has a bit of P5 code in it, so we can use the existing setup function to get started. p5.setup = () => { p5.createCanvas(CANVAS_WIDTH, CANVAS_HEIGHT); p5.colorMode(p5.HSB, 100); p5.frameRate(5); p5.background(10); p5.textSize(46); p5.fill(90); p5.text('Hello (Info)World!', 120, 280); }; We don’t need the last three lines of the p5.setup function body because we’re not writing text, so let’s remove those lines and step through the rest of the code. First, we create a canvas of a certain width and height specified by constants we defined earlier in the file. This code actually creates the canvas element and adds it do the DOM. Next, we set the color mode of P5 to HSB with a range of 0 to 100. As a developer, you’re probably much more familiar with hexadecimal color codes (#FF2304), but hex codes are pretty tricky to reason about. For example, how do you make a hex code just a little lighter? HSB, which stands for Hue, Saturation, and Brightness, gives you a more intuitive mechanism for dealing with color. Hue changes the color while saturation changes how deep the color appears (think pastel yellow versus highlighter yellow). Brightness has to do with the amount of light the color gives off. It’s a little like putting your color, highlighter yellow for example, in a room full of lights on a dimmer. Is the color you’re seeing highlighter yellow with the lights turned all the way up or half-dim? If you turn the lights off, every color becomes black. I chose a sort of mustard yellow hue for our canvas, er, paper, which at a very low saturation gives me the cream color I’m looking for. IDG In HSB with a scale of 0 to 100: 15, 100, 100 on the left, versus 15, 10, 100 on the right. We can use our existing p5.background method, which takes a single argument for a grayscale background, but can also take three arguments for the color mode P5 is in. p5.background(15, 10, 100); Add texture to a color background in P5.js Our light mustard background is fine, but I’d like it to feel a little more like a homemade paper, a one where you can actually see the fibers going in all sorts of directions. For example: IDG Some brown craft paper I got last year to make bottle labels. In order to emulate the paper fibers, let’s randomly sprinkle short lines all over the place, each pointed in a random direction. The lines should have some variation in color and length, so let’s add a component of randomness there, too. We’ll use the Math.random() function provided by JavaScript. Math.random() generates a random pseudo-number between 0 and 1. If we want a random value between 10 and 15, we can take the output of Math.random() and multiply it by the difference between the two numbers, 5. That will give us a random number between 0 and 5. Then we just add 10 to get a random number between 10 and 15. 10 + Math.random() * 5; // Gives you a random number between 10 and 15 Creating line segments that point in various directions will require some trigonometry, so for the sake of isolating the randomness equation, let’s just draw a bunch of random dots first. We’ll want to randomize our X and Y positions of those dots to be somewhere between 0 and the width and height of the canvas, respectively. The code for that looks like this: const NUM_DOTS = 400; for(let i = 0; i < NUM_DOTS; i++) { let x = Math.random() * CANVAS_WIDTH; let y = Math.random() * CANVAS_HEIGHT; p5.ellipse(x, y, 10, 10); } IDG You can increase the NUM_DOTS constant to increase the density of circles. IDG And you can introduce some variety into the circle sizes by creating another random number, say between 5 and 15, and plugging that into the third and fourth arguments to the P5.ellipse() function instead of the hard-coded values in the example above. The result: IDG Create a paper background in P5.js Let’s get back to paper fibers. I’ll spare you the trigonometry lesson, but suffice it to say that the general process goes like this: Calculate random x and y coordinates for the start of the line segment. Calculate a random angle between 0 and 2 pi that the line will follow. Calculate a random length of the line segment. Given the starting point, length, and angle, do math to get the ending point. The code for that looks like this: let x1 = Math.random() * CANVAS_WIDTH; let y1 = Math.random() * CANVAS_HEIGHT; let theta = Math.random() * 2 * Math.PI; let segmentLength = Math.random() * 5 + 2; let x2 = Math.cos(theta) * segmentLength + x1; let y2 = Math.sin(theta) * segmentLength + y1; Then we use the p5.line() function, passing in our four coordinates. p5.line(x1, y1, x2, y2); Here is an example of what you get by drawing 30,000 little lines: IDG That’s kind of what we want, but the lines are way too overbearing because they’re a solid black. In order to change the color of the lines, we can call the p5.stroke() method with a new color before calling the p5.line() method. For our textured paper effect, we need to incorporate some variation in color around the base color we chose before. I wanted the hue to be about the same, so I only played with the saturation and brightness. I added an optional fourth parameter to the p5.stroke() method that adds a little variation in opacity, too. p5.stroke( BASE_H, BASE_S - Math.random() * 5, BASE_B - Math.random() * 8, Math.random() * 10 + 75 ); Et voilà : IDG I can almost feel the texture! We have paper! Feel free to play around with this code before next week, when we’ll have to draw on even more math in our attempt to move on from the paper to the ink. Any questions, comments, or cool variations? Please share them in the comments or on Twitter: @freethejazz. JavaScriptDevelopment ToolsLibraries and FrameworksSoftware Development