This little canvas demo, like most of my little demos, grew from a random thought traipsing across my brain: I wonder how easy it would be to draw a crystal lattice in canvas?
The key to this demo, like almost all of my demos, is I’m too lazy to look up any sort of mathematical property/formulae/anything at all that might help me understand how this stuff works in real life. Instead, I guessed and eyeballed it.
The result is… well, I don’t know. It looks a little bit like a crystal lattice, I guess. It reminds me more of a circuit board pattern or something. Either way, I think it’s pretty interesting, and there’s some neat JS going on to make it happen.
As usual, I’m using Sketch.js, which simplifies a lot of the setup so I can get down to business.
What makes this demo different from a lot of ones I’ve posted previously, is instead of using canvas’s draw methods, I’m writing the pixel data directly to the canvas: I’m manipulating the canvas at a pixel level.
I’m creating a bunch of points and placing them randomly at whole-number x/y coordinates. Each of those points is set to move exactly one pixel in one of the eight cardinal directions. Any time one of those pixels encounters a line that’s already been drawn, it chooses at random a new cardinal direction to travel. That’s where having the pixel-perfect data comes in handy: I can just check the opacity of the canvas at that particular pixel. Because I’m using solid pixels, an opacity of 0 means nothing has been drawn there, and an opacity of 255 means there’s a solid pixel.
So every frame, works like this:
- Grab the pixel data from the canvas and put it in an array.
- Loop through all of my points and find their new position.
- If the point’s new position is already drawn, choose a new direction at random and update the number of times we’ve “intersected”
- If the point’s position is empty, draw a pixel to the array at that spot.
- Destroy any points that have hit the maximum number of intersections.
- Draw the new pixel data from the array to the canvas.
- Rinse/repeat until we’re out of points (they’ve all intersected the maximum number of times.
There are probably better ways to do this that would yield better (or at least differently interesting) results. I sort of like this one — it’s got a retro-pixel feel to it.