This article should have gone public about two months ago. Sorry for the delay. Life happened.

So js13kgames is over.

As in the past years I took the chance to explore new concepts while having some fun in the past month :-)

This year I learned a bunch of things, which I want to share with you. This is the first part of a series of four articles:

  1. Painting on screen (you are here!)
  2. Rollup (published soon)
  3. Flow (coming soon)
  4. Redux (coming soon)

What is js13kgames?

For those who don’t know it, js13kgames is a game jam. There are rules attached, here are the most interesting ones:

  • Within one month write a game from scratch (usually you only have 48 hours for that!).
  • This game must be able to run under file:-protocol (a.k.a. be able to run when double-clicked in file browser).
  • At most it must be 13 KB zipped.
  • It has to adhere to a topic. this year it was “lost”.

You can find the others on the website.

For me, it serves as a playground to learn new topics and explore what is possible today.

The last years I went to SVG, which gives me scalability, DOM and events. The syntax for paths is a bit obscure, but can be easily abstracted away.

What did I aimed to learn this time?

Shortly before the contest started, I noticed that there are next-to-no circle based games on the web. So I decided to explore that space no matter the announced topic.

Why didn’t I rolled with SVG?

SVG has an arc attribute, I could use to draw … arcs. The idea was to build a circle maze. But I couldn’t wrap my head around how to draw arcs with a common center.

So I looked how to do that with canvas. The downside is a lack of accessibility. Because there is no DOM, a screenreader can’t traverse anything. Blind users are likely sadly out-of-luck. If somebody knows otherwise, please drop me an email!

Why is Canvas better suited here?

On the other hand, the API is a breeze. I had almost no problems. Only when the canvas got too small (height or width), canvas draw too short arcs for whatever reason. No matter whether you do it in SVG or Canvas, it always contains some maths :)

How to translate coordination systems

Oh, there was some math to do for painting. But don’t worry, it is not that much. Smashing Magazine has a nice article explaining trigonometry. Go have a look at it. It’s playful :)

Canvas counts from the top-left corner as (0/0), respective coordinate origin. I want that to be the center. So I wrote a helper, which mapped my „circle coordinates” to „canvas coordinates” and vica versa:

function coordinationSystemToCenter(p, q) {
  // (p, q) are measured from top-left corner
  // (x, y) are center of circle
  const x = p - World.WIDTH / 2;
  const y = q - World.HEIGHT / 2;
  return { x, y };
}
function coordinationSystemToVertex(x, y) {
  // (p, q) are measured from top-left corner
  // (x, y) are center of circle
  const p = x + World.WIDTH / 2;
  const q = y + World.HEIGHT / 2;
  return { p, q };
}

While I was it, there are two more helpers needed: One which translates between Cartesian coordination system we are used to and Polar coordination system which „thinks” in circles.

I want to express business logic in Polar coordinates here, but Canvas need it in Cartesian ones. The inverted direction is not needed, but explained down.

function mapPolarToCartesian(polar) {
  const { phi, r } = polar;
  const x = r * Math.cos(phi);
  const y = r * Math.sin(phi);
  return { x, y };
}
Theoretical background

Given a circle origin (0/0) as origin of a coordination system. You can consider every other point (x/y) as a a point on a circle with radius r. That is, you can compute r by solving the positive root of r² = x² + y². When you draw a line between (0/0) and (x/y) it creates an angle with the x-axis (horizontal line). You can compute the value of that angle using trigonometry: sin(φ) = y/r and cos(φ) = x/r. Well I would like to use r, so I reformat the equations to r = y/sin(φ) and r = x/cos(φ). Since the left hand is equal, I can write y/sin(φ) = x/cos(φ) which is equivalent to y/x = sin(φ)/cos(φ) = tan(φ). Since x and y are known, I can compute φ using atan2.

In other words, There are formulas to compute the representation in the other coordination systems. plus, JavaScript does the heavy lifting in its Math object.

How to translate circle units

That was one helper. The other one is transforming circle arcs measured in Radians into Degree and vice versa:

function mapDegreeToRadians(degree) {
  // Relationship: degree : 360 = radians : 2 * Math.PI
  return degree * Math.PI / 180;
}
function mapRadiansToDegree(radians) {
  // Relationship: degree : 360 = radians : 2 * Math.PI
  return radians * 180 / Math.PI;
}

Therefore I look at what is an arc in Radians. It is part of the circle line. When I start painting from where the circle crosses the x-axis and go counterclockwise.

The line between the origin and the end of the arc contains an angle with the x-axis.

That means b/π*d = φ/2*π, where d is the diameter. I can rephrase it as b = φ*d/2 or φ = 2*b/d.

N.B. My coordination system starts with the x-axis and goes counterclockwise. Canvas starts at x-axis and goes clockwise.

What’s next?

The next article in this series will explain, how to deal with the code spread across several files using Rollup.js.