mike chambers | about

A Templated Approach for PaperJS projects.

Wednesday, April 11, 2018

Paper.js is currently the primary creative framework that I use for my creative coding. I really like its API, which is easy to use and extend, the ease in exporting vectors graphics from it (making it easy to create high resolution prints), and the general ease of development due to the use of JavaScript and running within the browser. While I do sometimes miss the higher performance that lower level frameworks like processing or openFrameworks provide, for the most part the advantages of Paper.js far outweighs the performance penalties of running in the browser.

I have put together what I feel is a pretty good template for quickly creating and iterating on Paper.js projects and experiments, and wanted to share some info about my approach in case anyone else might gather something useful from it.

There are a couple of things that are particularly important to me when developing the template:

  1. It has to be easy to quickly start a new project, and get right into iterating on an idea. I don’t want to fuss with a lot of setup.
  2. It needs to be easy to quickly configure and tweak settings, making it fast and easy to play around and experiment.
  3. I need to be able to capture and export images (png and svg) and / or videos at any time, so I can capture anything interesting that I create.
  4. Finally, I need the option to easily export settings for the project so I can save and reproduce them in the future.

I built my projects as configurable engines, that are controlled by parameters that I send in. This makes it easy to experiment and play around with different inputs and settings. My template is built around this idea.

Note, most of my projects are for generating images and video, and not for general web deployment. This means that I can take advantage of browser (in this case Google Chrome) specific functionality, and not worry about cross browser compatibility. Some of the functionality in the template may need some additional work to work consistently across browsers (particularly around media generation and download). In addition, the project cannot be loaded from the file system, but must be served via a web server (I used the built in python server).

If you look in my paperjs github directory, you will notice there is a folder called _projecttemplate. This is template for new paperjs projects. Creating a new project simply invovles copying that folder and giving it a name.

Within the folder are two files, index.html and scripts/main.js.

index.html

This is the main web page that loads required JavaScript and CSS, and contains the basic HTML markup to get started.

<!DOCTYPE html>
<html>
<head> 
	<link rel="stylesheet" type="text/css" href="../_styles/base.css">

	<script type="text/javascript" src="../_scripts/paperjs/paper-full.v0.10.3.min.js"></script>
	<script type="text/javascript" src="../_scripts/chromajs/chroma.js"></script>

	<script type="text/javascript" src="../_scripts/mesh/FileDownloader.js"></script>

	<!--
	<script type="text/javascript" src="../_scripts/mesh/PixelDataLoader.js"></script>
	<script type="text/javascript" src="../_scripts/mesh/PixelData.js"></script>
	-->

	<!--
	<script type="text/javascript" src="../_scripts/mesh/Utils.js"></script>
	-->

	<script type="text/javascript" src="scripts/main.js"></script>
</head>
<body>
	<div id="canvas_container"></div>
</body>
</html>

I keep all of my reusable libraries and code in a folder called scripts/ which is on the same level as my project file. By default, I load Paper.js, chroma.js, and my own FileDownloader class which I will talk more about later. I then load in my main.js file where all of my code will live. The commented out lines are classes I often use, and I keep them here for convince sake, so I just have to uncomment them if need them.

Note that I don’t hard-code the canvas element for Paper.JS. I dynamically create this in my initialization code, as it provides some flexibility on configuration which Ill go into in a bit.

scripts/main.js

The second main part of my template is the scripts/main.js file. This is the main file of each project, and generally contains all of the code for that project.

The main.js file is broken up into 4 section:

  1. DEFAULT CONFIGURATION. This contains default settings for all of my projects. If you want to change them for the project, change them in the next section.
  2. PROJECT CONFIGURATION. This is where I override default setting for my project, and add new setting specific to the project.
  3. PROJECT CODE. This is where I add all of the code for my project.
  4. DEFAULT INITIALIZATION. This is where all of the setup and initialization for Paper.js, canvas and my project happens. In general, I should never need to edit this.

Lets look at each section in more detail.

DEFAULT CONFIGURATION

The first section contains default configuration settings for all of my Paper.js projects.

/*********** Default Configuration Settings ******************/
let config = {

    //get the app name from the directory name
    APP_NAME: window.location.pathname.replace(/\//gi, ""),

    BACKGROUND_COLOR: "#FFFFFF", //web page color
    CANVAS_BACKGROUND_COLOR:"#111111",

    CANVAS_WIDTH: 640,
    CANVAS_HEIGHT: 640,

    TEMPLATE: null,
    ALLOW_TEMPLATE_SKEW: false,
    CACHE_PIXEL_DATA:false,

    ANIMATE: false,
    TRACK_MOUSE:false, //whether we listen for mouse move events
    
    //whether we enable Paper.hs hidpi setting
    //this changes canvas size when true (default) and causes issues when capturing video
    HIDPI:false,

    //whether we should record canvas to output as video
    RECORD_CANVAS: false
};

Any customized configuration settings, or changes to default for the specific project are not added here, but in the project configuration section below. This makes it easy to quickly glance at a project, and see what the main configuration parameters for that project are.

A couple of notes on the default settings. The config.APP_NAME parameter is used to automatically determine the name for the project, which is used later when creating ans saving files. The config.TEMPLATE settings are used for loading a template in the background to grab pixel / color data from. Finally, by default, the template does not listen for mouse events. You must set the config.ANIMATE property to true to capture these.

PROJECT CONFIGURATION

The next section is the project configuration section, and is used for project specific settings and new configuration options. For example, if I wanted to set a custom canvas size, listen for mouse events, and set default stroke settings, this section would look like:

/*********** Override Config defaults here ******************/

config.CANVAS_WIDTH = 1280;
config.CANVAS_HEIGHT = 1280;

config.TRACK_MOUSE = true;

config.STROKE_COLOR = "white";
config.STROKE_WIDTH = 2;
config.RADIUS = 6;

/*************** End Config Override **********************/

I would then access the values in my main code like so:

let c = new Path.Circle(new Point(100, 100), config.RADIUS);
c.strokeColor = config.STROKE_COLOR;
c.strokeWidth = config.STROKE_WIDTH;

Again, this makes it very easy to quickly tweak parameters that determine how your code runs. It also provides a simple API / view on what parameters you have to play with.

By putting all settings in a single config object, it also makes it easy to send and reuse those parameters in other parts of your code (such as custom classes), and also provides a single object that you can export which contains all of the settings for your project and code (more on that below).

PROJECT CODE

This is the main section of the template, and contains two functions where you add your code, as well as access to number of variables available throughout your code.

//PixelData available if config.TEMPLATE is not undefined
let pixelData;

let bounds;
let mousePos;

//main entry point for code. Called once when page
//loads
let main = function(){
    //ADD CODE HERE
};

//Called every frame
//note config.ANIMATE must be set to true in order for this
//to fire
let onFrame = function(event) {
    //ADD UPDATE CODE HERE
};

variables

There are three variables initialized which you have access to:

pixelData is available if config.TEMPLATE is set to the path of an image, and will contain the raw pixel data information for that image. bounds contains a Rectangle instance which defines the bounds for the canvas. mousePos If config.TRACK_MOUSE is set to true, then this will always contain the current mouse position. (For performance reasons, you should use this to track mouse movement.)

main()

This is the main entry point for your code, and is run once when your project is loaded. Use this to add any custom setup code, or if you are not doing any animation, to run all of your project code.

onFrame()

If config.ANIMATE is set to true, then this will be called periodically (60 frames per second). This can be used to animate items, or make changes over time.

DEFAULT INITIALIZATION

Finally, the last section is the default initialization section which contains initialization and setup code used for all of my Paper.js projects. In general, you should never need to make any changes here.

The code handles the following tasks:

The one area I want to call out here is the code around FileDownloader. This is a class that makes it easy to export PNGs, SVGs, Videos and configuration JSON files for the project. This is enabled by default, so at any time, you can hit the following keyboard shortcuts to export media from the project:

By default, canvas recording for video output is off. To enable, set the config.RECORD_CANVAS property to true.

At any time your project is running, you can capture its output as one of the media types specified above. This makes it super simple and convenient and ensures you can always capture some of those happy little accidents that may come up and surprise you.

You can download the template, along with all of my Paper.js projects from github.

twitter github flickr behance