Get started

It's easy to get started with Pts. Here we'll review the core concepts and build a fun thing together. Let's do this!


Here's a spolier of what we will build. Touch to play it, and take a look at the source code. The core code is only ~10 lines long.

Space, Form, and Point

Pts is built upon the abstractions of Space, Form, and Point. If that's too abstract, you can think of it like drawing: Space provides the paper, Form provides the pencil, and Point provides the idea.

Given an idea, you may express it in different forms in different spaces. Would it be expressed in pixels or LEDs? Is it visible or audible? Does it look like abstract art or ASCII art? As Pts develops, it will offer more Spaces and Forms that enable you to experiment with different ideas and their different expressions.

But enough of abstractions for now. Let's see how it works in a concrete example. In the following sections, we will create a quick sketch step-by-step and discuss the main features of Pts.

You may also be interested in this article which discusses the concepts of Space, Form, and Point.

Using pts with npm

If you use npm, first npm install pts and then import the classes you need:

import {CanvasSpace, Pt, Group} from "pts" 

And you're good to go!

Note that pts is an es6 library, so if you want to compile to es5, you'll need to configure babel accordingly. (Possibly with the builtin-extend babel plugin)

Using pts in a script

First go to the latest release and get pts.js (direct link or github). Include it in your html. Then create another js file for your script and add it too.

<script type="text/javascript" src="path/to/pts.js"></script>
<script type="text/javascript" src="path/to/my_script.js"></script>

When using as a script, we usually start by adding Pts into the global scope first.

Pts.namespace( window );

That means we can call all Pts classes like Group directly, instead of Pts.Group which is a bit clumsy to write.

And that's it. We can now have some fun.

Creating Space and Form

Pts provides a CanvasSpace which enables you to use html <canvas> as space. You can create a CanvasSpace like this:

var space = new CanvasSpace("#hello");
space.setup({ bgcolor: "#fff" });

This assumes you have an element with id="hello" in your html. If your element is <canvas id="hello">, CanvasSpace will target that canvas. Otherwise if your element is a container like <div id="hello">, a new canvas will be created and appended into it. You may also pass an HTMLElement instance directly into CanvasSpace.

The setup function allows you to initiate the space with an object that specifies some setup options, like background-color and auto-resize.

Next, you can get the default CanvasForm which, as we mentioned before, provides the "pencils". CanvasForm helps you draw lines, circles, curves and more on the html canvas.

var form = space.getForm();

Do you know you can create your own forms by extending CanvasForm or Form class? It's like making your own pencils. You can initiate your custom form like this:

// Initiate your own BeautifulForm class
var form = new BeautifulForm( space );

Now we have paper and pencil. What should we draw?

Drawing a point

The space, which we have created, contains some handy variables. For example, the pointer variable tells us the current position of pointer in space (ie, mouse or touch position). Let's use it to draw a point.

To render an animation continuously, we need to add a "player" to the space. A "player" can be a callback function to run your animation, or an object that specifies functions for start, animate, and action. You may add multiple players to a space.

At its simplest form, this is how we can draw the pointer.

space.add( () => form.point( space.pointer, 10 ) );

And here's the result. Touch the demo and move around.


So first we add a "player" as a function to space, and in that function, we use form to draw space.pointer with radius of 10. By default, the point is drawn as a square with red fill-color and white stroke-color.

The animate callback function actually provides 2 parameters: time which gives the current running time, and ftime which gives the time taken to render a frame.

Let's modify the code above to make the circle pulsate.

space.add( (time, ftime) => {
  let radius = Num.cycle( (time%1000)/1000 ) * 20;
  form.fill("#09f").point( space.pointer, radius, "circle" );


Success! The calculation (time%1000)/1000 maps the running time to a value between 0 to 1 every second. Then we use the Num.cycle function to make the value cycle between 0...1...0...1, and we multiply the value by 20 to get the radius. Finally, we draw the pointer with the radius as a blue circle. Pretty easy, right?

Drawing shapes

There are 3 basic structures in Pts

Pts provides many classes to work with these structures. For example, a rectangular boundary can be defined by two Pts -- one at top-left and one at bottom-right, and you can also get a Group of 4 Pts from its 4 corners.

Let's make this easier to understand with an example:

var rect = Rectangle.fromCenter(, space.size.$divide(2) );
var poly = Rectangle.corners( rect );
poly.shear2D( Num.cycle( time%5000/5000 ) - 0.5, );    

form.fillOnly("#123").polygon( poly );
form.strokeOnly("#fff", 3).rect( rect );


What's happening in these 5 lines of code? Let's find out.

The first line create a "rectangle" from a center point, and we specify that the center is space's center and the size is space's half-size. ($divide is a Pt function that calculates division and returns a new Pt.) The variable rect stores a Group of 2 Pts — its top-left and bottom-right positions.

The second line takes rect and get its corners. So the variable poly contains a Group of 4 Pts.

The third line use the Group's shear2D function to shear the polygon at space's center. The amount of shearing cycles between -0.5 to 0.5 every 5 seconds.

The 4th and 5th line just draw the rectangle and the sheared polygon.

Even though it takes words to explain, the code is acutally quite simple :)

Visibles from invisibles

From here on, it's up to you. Squint your eyes and see what shapes and structures hide between those invisible points, or what motions and interactions could generate unique and expressive forms.

For example, what if we take two corners of the rectangle, and join them with the pointer to draw a triangle?


And what if we also draw the inner circle of each triangle?


This is what you can do with pts in ~10 lines of code. Add another 10 lines and make it your own!

// animation
space.add( (time, ftime) => {

  // rectangle
  var rect = Rectangle.fromCenter(, space.size.$divide(2) );
  var poly = Rectangle.corners( rect );
  poly.shear2D( Num.cycle( time%5000/5000 ) - 0.5, );
  // triangle
  var tris = poly.segments( 2, 1, true ); (t) => t.push( space.pointer ) );
  // circle
  var circles = (t) => Triangle.incircle( t ) );
  // drawing
  form.fillOnly("#123").polygon( poly );
  form.fill("#f03").circles( circles );
  form.strokeOnly("#fff ", 3 ).polygons( tris );
  form.fill("#123").point( space.pointer, 5 );

Hope this gives you a quick and enjoyable walkthrough. But wait, there's more: Take a look at the other guides which will explain Pts features in details.

We appreciate your feedbacks and bug reports. Please file an issue at github or ping @williamngan on twitter.

Enjoy and have fun!