Why I Code In My Spare Time

October 14, 2020

  •  Christy Vojvodich
Reading Time: 7 minutes

My name is Taylor. I am a Front End Dev for Turbine Labs, which is pretty great. Turbine gives me the opportunity to work with exciting, and somewhat cutting-edge technologies. It’s nice to be able to be so hands-on with modern technologies.

Typically, I learn by doing. I can read documentation all day long, but I won’t truly figure something out until I try it a couple of times. Why read 5 minutes of documentation when I can spend 5 hours brute-forcing it?
(For real though documentation writers, you are the realest.)

Image for post

So, naturally, I make millions of personal projects. Bit by bit I build them up and then abandon them. And that’s okay. People who are able to complete projects are the coolest. But if you’re like me and you have many unfinished dreams, don’t dread it! Each and every single one of those projects has grown my experience and taught me something I didn’t know.

For me, working on personal projects is a space where I can play with a new framework like Crank.js, or play with a new library, like Lerna. With each new project, I learn a little more. I gain a bit more knowledge on how things work and I can take that with me and grow to be a better developer.

For example, a while ago I was playing around with Unity. I was following a tutorial that generated endless land-maps using Perlin noise. Which got me thinking, maybe I could make a website with my beloved Javascript, that would use Perlin noise to generate maps for Dungeons and Dragons.
— Yeah. There’s a whole lot of nerd in that paragraph. —

A gif of my first Unity game experiment; A chicken dramatically walking out from swaying grass

My first Unity Experiment: Suddenly Chicken

So I set off to find myself a nice Perlin noise Javascript library. I ended up finding this repo by Joseph Gentle which was exactly what I was looking for. But it also held more than I intended. In the repo’s README was a link showcasing how pretty Perlin noise could really be.

I was absolutely floored. This was such a beautiful display of code. So I decided to do what any sane, rational, content adult developer would do. I decided to reverse engineer it.

Now I’ve worked with HTML Canvas before. HTML5 made excellent additions and improvements to browsers rendering graphics. I just never had a need to use it before. I’ve had plenty of experience with simple SVGs, but had never seen anyone animate something to the canvas like this. It was so cool!

I took the Perlin noise script that Gentle had written in javascript and made a new version with Typescript. As I did, I tried to make sure I was able to understand what each piece was doing. At least a little bit. Typically I would do this by adding a comment before each line, explaining to myself what it was doing.

After I broke the Perlin noise script down, I took a look at the script that was creating the animation. I did the same thing there. Line by line I tried to figure out what was happening and recreate the same effect. Present Taylor now knows that some of Past Taylor’s understandings were incorrect, but most of the time they were correct enough to help me digest the concepts I was learning.

Let’s show an example. The script itself creates a series of “particles” and sprinkles them across the canvas (which happens to be the size of the browser window).

// 2000 "particles" to be exact!
for (_i = 1; _i <= 2000; _i++) {
  p1 = {
    x: Math.random() * w,              // w is canvas.width
    y: h / 2 + Math.random() * 50,     // h is canvas.height
    a: 0
  };
  particles.push(p1);
  particles.push({
    x: p1.x,
    y: p1.y,
    a: TAU / 2
  });
}

One thing I didn’t understand yet was the a property here. I knew it had something to do with angles because of “a” and because of TAU. But not why we needed it. Further in the code we actually draw the “particles”:

for (_j = 0, _len = particles.length; _j < _len; _j++) {
    p = particles[_j];
    v = noise.perlin2(p.x * period, p.y * period);
    ctx.fillStyle = "hsla(" + (Math.floor(v * 360)) + ", 95%, 20%, 0.05)";
    ctx.fillRect(p.x, p.y, 1.5, 1.5);
    p.h++;
    a = v * 2 * Math.PI + p.a;
    p.x += Math.cos(a);
    _results.push(p.y += Math.sin(a));
  }

From my breakdown, I could see that we creating rectangles at the particle’s x and y positions. And that something with the particle’s angle, and that oh so dreaded trigonometry, updated the particle’s position. At this point, I felt like I knew enough to have a basic understanding of what the script was doing.

It would create 2000 “particles”, and then using the values generated by the Perlin noise it would draw them and update their position. Lather, rinse, repeat.

Pretty cool. I learned a lot about noise generation and a little bit about animating to the canvas. I would consider that a successful little adventure.

Flash forward to earlier this month. I had it in my brain that I wanted to create a website that would randomly generate a landscape like you might see in a Studio Ghibli film.

A background screen from the movie: Kiki’s Delivery ServiceKiki’s Delivery Service will always hold a special place in my heart.

I figured by using the HTML Canvas API I could draw shapes using Javascript. This would allow me to create shapes that are more unique and random that sampling SVGs. So I set forth in trying to draw a simple leaf-like shape to the canvas.

A simple leaf-like shape that took entirely too long

Wow. There it is.

That wasn’t too bad! I had to learn how to use the bezierCurveTo function, but ultimately drawing something that was vaguely leaf-shaped wasn’t too hard. But now I need to rotate it so I can make many of them in all different directions.

That actually turned out to be way harder than I thought. See Canvas allows you to rotate things, but it’s actually technically rotating the coordinate system of the canvas. Not the SVG itself. This isn’t ideal when trying to draw multiple paths to that canvas. So instead, I had to turn to… math.

Image for post

Me desperately trying to figure out how to calculate rotation points. Also please enjoy my drawing on the reverse side bleeding through.

I knew that I knew the starting point of the leaf. I knew that I knew the length of the leaf. So if I know the hypotenuse of the triangle, how do I figure out the rise and run? This would likely give me the rotation. After some poking and prodding and Googling, I was able to come up with the following function:

const CalculateRotationPoint = (
  rotationalAngle: number,
  sizeOfItem: number,
  startingPoint: CanvasPoint
): CanvasPoint => {
  const resultingPoint: CanvasPoint = {
    x: startingPoint.x,
    y: startingPoint.y + sizeOfItem,
  };  if (rotationalAngle !== 0) {
    const oppositeLength = 
      Math.round(
        Math.sin((rotationalAngle * Math.PI) / 180) * sizeOfItem * 10000) / 10000;
    
    const adjacentLength =
      Math.round(
        (oppositeLength / Math.tan((rotationalAngle * Math.PI) / 180)) * 10000) / 10000;    resultingPoint.x = startingPoint.x + oppositeLength;
    resultingPoint.y = startingPoint.y + adjacentLength;
  }  return resultingPoint;
};

I did it! Now I was able to pass each leaf a rotation and it would correctly calculate the ending point. That’s pretty awesome. I have the beginnings of a bush happening here. Next I added fluctuation to the length of each leaf, fluctuation to the Bezier Curve’s control points, and fluctuation (to a degree) of the color of each leaf.

But before I could use these leaves in any real way, I need a good way to place them. I wanted to find a way that would resemble the relative randomness of tree branches. Oh hey, kind of like how the Perlin Noise creates those beautiful curves!
— Look at that! Elements from the first act are colliding in the third act! —

So I grabbed my handy-dandy Perlin Noise generator and did a happy fusion-dance to create branches!

Generated Vines

Perlin Vines containing an arrangement of leafs

Hey, that’s pretty cool! Not quite what I was going for, but it’s pretty. Now I just need a way of controlling where they start from, and reversing the direction, and chopping them off at a certain length and voila!

Image for post

A randomly generated tree

There it is. And honestly, I’m really proud of this. I was able to learn a lot more on how the HTML Canvas works, and how to properly utilize Perlin Noise. For example, do you remember how earlier in the article I mentioned:

I could see that we creating rectangles at the particle’s x and y positions. And that something with the particle’s angle, and that oh so dreaded trigonometry, updated the particle’s position.

I’m talking about this code from the original Gentle Perlin script:

// After the script draws the particles, it updates their positions like so:a = v * 2 * Math.PI + p.a;
p.x += Math.cos(a);
_results.push(p.y += Math.sin(a));

Well now given my time with triangles, and calculating rotational angles, I now understand what this is doing. It calculates a new angle using the noise, which gives us that nice flowly Perlin curve. It uses that calculated angle, and multiplies it times the particle a property which is either 0 or TAU / 2. All this does is reverse the direction of that angle so that we have some particles traveling in one direction, and some traveling in the other. We then use that angle, cos and sin to calculate the rise and run of the triangle to determine the next particles position. It’s more or less the same method I was using in my rotation calculation to figure out the point. My angle came from rotation degrees, and their angle came from Perlin noise.

I’m still a very long way to go before I am able to make some beautiful Ghibli scenery; My trees still don’t quite have that “tree” shape to them.

Ultimately though, this is why I code in my spare time. It gives me an absolute freedom to try brand new things and what they can teach me. I get a chance to strengthen my skills and be a more all-around capable dev. I hope it can maybe help you too.

If you want to generate random tree-like shapes my code (currently) lives at: https://seabound.pridgey.dev

If you’d like to see the actual code itself, you can find the repo here: https://github.com/pridgey/seabound.pridgey.dev
Though, I’m sorry that you want to read my messy personal coding habits.

I hope something about this might spark interest in you to go play with something you’ve never tried before. Be safe! Have fun! Learn something!