Saturday 31 March 2018

P5 Simple.js - Update

Since my last post announcing that I started work on simple.js to try to simplify p5js for newcomers to coding, I've made a fair bit of progress.


simple.js

The library is on GitHub:


The library is documented on the wiki where I write a rationale for the feature/change and example usage:




Using simple.js

Simple.js is included in the html just like another other p5js libraries. The key is to include it after p5.js is referenced.

here's an example index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
    <style> body {padding: 0; margin: 0;} </style>
    <script src="../p5.min.js"></script>
    <script src="../simple.js"></script>
    <script src="sketch.js"></script>
  </head>
  <body>
  </body>
</html>


Circle, Square

The library provides a simple circle() command:

circle(x, y, diameter)

Some basic research suggested newcomers are more comfortable with diameter as a concept than radius.

Similarly a square() command is provided too:

square(x, y, size)


Integer Random Numbers

The library provides a randomNumber() function to return integer values. There are two modes of use:

randomNumber(n)

which returns a random integer between 0 and n, including 0 and n.  The second mode is:

randomNumber(a,b)

which returns an integer number between a and b, including a and b.


Easy Repetition

One of the most difficult things for new coders is the for loop for repeating instructions. For simple requirements it is unnecessarily complicated.

It isn't easy to implement something like Logo's REPEAT 5 [... ] in Javascript so a compromise  was required.

There are 2 forms of the repeat() command.

repeat(n,my_function)

This repeats a function my_function, n times. Of course if there is a need for more, such as using loop counters, then the for loop can be used.

repeat(start, end, step, my_function)

This calls a supplied my_function(x), passing it a parameter x which starts at start, increments by step, until it reaches end. The parameter x will include both the start and end values. The function must accept a parameter, but can choose to ignore it.


Friendlier Defaults

Some of the p5js defaults are not ideal for newcomers. It would have been

Here are the implemented changes so far:

  • noLoop() - looping draw() isn't expected by new coders, and causes confusion, for example when drawing with randomness
  • strokeWeight(2) - the default stroke is very thin
  • background('lightgrey') - an invisible canvas isn't as helpful as a visible one
  • fill('yellow') - filled shapes are more familiar than transparent ones



More

The library will be updated as obstacles and barriers in p5js are observed.

Thursday 29 March 2018

P5 Simple.js

Previously I wrote about my experience of using p5js with young coders, artists who perhaps had never coded before, and newcomers who were perhaps a little shy of technology.

Processing has a noble aim to be accessible to as many people as possible. This is important, not just because Processing wants to raise the number of users, but because digital literacy, the ability to code, and algorithmic thinking are important in this pervasively digital era.

In my (limited) teaching experience I found some key issues that were barriers to new or reticent coders:

  • No circle command. The word ellipse is enough to scare some people away. It just isn't as simple and friendly as circle. Children know about circles. Not every child knows about ellipses, never mind having to think about an ellipse as a more general case of a circle.
  • No square command. Again, children know what a square is, but the idea of a rectangle as a more general square is just too much to think about in those already overloaded early phases of learning.
  • No simple way to make random integers. When asked to think of a random number, most people will pick a whole numbers. Taking the next steps to using random numbers, again most people will naturally think in terms of whole numbers. Having to deal with floats and casting them to integers is too much to think about if introduced too early.
  • Loops are far too complicated. Compared to Logo's REPEAT command, the heavy boilerplate of the C-derived javascript for loop is a huge barrier to many new learners. In the last few weeks I've been teaching university students and they too have problems with for loops.



Solution: Simple.js

A discussion on the p5js GitHub on the usability of p5js for non-technical newcomers and younger learners (age 7-10) didn't convince many of the core developers:



But one person made a great suggestion - instead of trying to get the core developers to change p5js, why not create a new library. That way the core developers are happy, and anyone who wants to use the library can.


I've made a start:



Currently this library implements the following drawing functions.

  • circle(x,y, r) - draws a circle centred at (x,y) with a radius r. Note that the built in ellipse() command expects a diameter not a radius.
  • square(x,y,w) - draws a square at (x,y) with sides of width w.


There is also a helper function:

  • randomNumber(n) - picks a whole number (integer) between 0 and n. Unlike the built in random() function, this one includes n as a possible result.
  • randomNumber(a,b) - picks a whole number (integer) between a and b. Unlike the built in random() function, this one includes a and b as possible results.



Repeat Loop

Introducing a new kind of code structure is more of a challenge that I'm still working on.


Examples and Tests

Example sketches are included showing how to use the new functions.



These also act like tests too.

Make sure your index.html refers to the correct example sketch, they're not named as the default sketch.js. For example, the index.html for referring to the circle() example sketch is:

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
    <style> body {padding: 0; margin: 0;} </style>
    <script src="../p5.min.js"></script>
    <script src="../simple.js"></script>
    <script src="sketch_circle.js"></script>
  </head>
  <body>
  </body>
</html>


Here's an example sketch comparing random() and randomNumber():


  • The top row of circles have horizontal position based on random(). You can see they're properly random. 
  • The middle row have circles based on randomNumber(7) which only returns numbers 0, 1, 2, 3, 4, 5, 6 or 7.
  • The bottom row have circles based on randomNumber(3, 5) which only returns numbers 3, 4 or 5

Saturday 24 March 2018

The E-Book is Finally Out!

The ebook of Make Your Own Algorithmic Art is finally out on Amazon Kindle in TextBook format.


The print edition will be published soon using IngramSpark, because CreateSpace won't publish a book with more tha 480 pages.

The cover was changed from the original because people couldn't see what the "alien andscape" was in a small thumbnail.


Readers are always right!

Saturday 3 March 2018

Creating SVG Vector Drawings with p5js

The way p5js is mostly used results in a canvas in a web page, with your artwork rendered as a bitmap - made of pixels. This is fine and works well for many scenarios.

But sometimes it would be really useful to have your artwork, not approximated as a set of pixels, but as a vector drawing, made of actual shapes like lines and circles.

The benefits of vector drawings is that they can be scaled up without loss of accuracy, and when they're rendered at high resolution, they are rendered at the maximum possible resolution. In other words, we avoid seeing the pixels that make up a bitmap image.

Here's a visual explanation of the difference between pixel (raster) images and vector drawings [source].


A good open standard for vector drawings is SVG.

Right now, the official p5js doesn't render SVG.


p5.js-svg

There was a Google Summer of Code project which aimed to allow p5js code to render as SVG.



Sadly, the project appears to be unmaintained, and the last release was linked to p5js v0.5.2 from January 2016.

To use it, we have to download the p5.svg.js library, and a patched p5.js which needs to be used instead of the current latest p5js.

Despite the age - it seems to work .. mostly.


Simplest Example

Here's a very simple example which I tried first to see if I could get p5js rendering to SVG working.

The HTML file is:

<!DOCTYPE html>
<html>
  <head>
     <meta charset="UTF-8"> 
    <meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
    <style> body {padding: 0; margin: 0;} </style>
    <script src="../svg/p5.js"></script>
    <script src="../svg/p5.svg.js"></script>
    <script src="sketch.js"></script>
  </head>
  <body>
  </body>

You can see the direct references to the patched p5.js and the supporting p5.svg.js.

The p5js sketch is:

function setup() {
    createCanvas(800, 600, SVG);
    background(255);
    noLoop();
}

function draw() {
    ellipse(400, 300, 200, 200);
}

This is a really simple sketch, all it does is draw a circle. An important difference to normal p5js is the SVG parameter in the createCanvas() command, which tells this p5js to target SVG and not a pixel canvas.

The other difference is the ellipse command. I normally leave out the final parameter because modern p5js assumes you want a circle with the same horizontal and vertical diameter. With this older version of p5js we need to explicitly set both.

Here's the result:


The rendering didn't always work. Editing the sketch sometimes results in no change to the rendered image, or results in no image at all. Closing and opening a new tab to the sketch seems to be a workaround.


More Complex Example

In the book we develop some moderately sophisticated code and images. The last chapter on L-systems is a good example of this.


That's an interesting, fairly detailed image, made of quite a few lines and circles. The code for the image is online at https://www.openprocessing.org/sketch/514823.

Normally, if we wanted higher fidelity renders of that image, we'd have to increase the size of the canvas and adjust the size of the circles and length of the lines to scale up in proportion.

We can now modify the source code, like the simple example above, and see if we can successfully create an SVG vector drawing, made of actual circles and lines .. not pixels that approximate those lines.

... and it seems to work! The resulting SVG can be saved from the web page. I haven't found a simple way of doing that, like you can save an image. I had to copy the SVG element from the page source (using the web developer debugging console) and paste it into a plain text file, and saved with an .svg extension.

Here's the resulting SVG file: l-systems.svg. You can open it with most web browsers, file previewers and vector drawing editors like Adobe Illustrator, Affinity Designer and the open source Inkscape.

Comparision

Here's a zoomed a zoomed in section of the normal pixel image saved from the original p5js code.


You can see the poor fidelity as the pixels start to become apparent, resulting in "jaggies" instead of smooth edges.

Here's a zoomed in section of the vector drawing.


The circles are still smooth circles, and the lines are still smooth lines.

Here's an even deeper zoom, just to prove the point that vector drawings maintain render quality.


That's pretty amazing!


Conclusion

We've found a way to create SVG vector drawing from our p5js code - although the supporting library is a little outdated, and appears unmaintained.

The resulting vector drawings can be used to create very high fidelity renders - such as printing the cover image of a book!