I was a bit bored on Saturday, so I decided to do a little one-day coding challenge - create a Christmas Card for the blog using the Canvas API.
For the impatient, or those who don't to read the write-up, the card itself is down the bottom of the post, or here
To follow along, the code is available on the blog's github repository
I set out to make an animation that was Christmassy, all drawn on a Canvas from scratch, no importing paths from illustrator etc.
To start with I created a few classes to base all the effects on. I made a render loop, that runs requestAnimationFrame repeatedly, and then renders all the layers it knows about each frame. The renderers all inherit from the same class - although I didn't really get a lot of benefit out of this, it could make future edits easier.
Snow was a pretty basic effect to add, especially given that Paul Lewis did a video on this recently:
Whilst I didn't watch the video again before starting out, I was definitely influenced by this, as he has a pretty nice way of making random snow. In essence a hundred circles of random size are drawn above the top of the canvas, and then moved at a random speed toward the bottom. I thought about varying the x (left-to-right) speed, but it looked pretty good without it, so I kept it simple. Every time a snowflake moves past the bottom of the canvas it is re-spawned at the top, with new random size, speed etc. This prevents repetitive snow.
The first time I ran it, I had x and y the wrong way round - a stupid mistake, but easily spotted and fixed. Aside from this, it didn't need much adjustment. I ended up putting two sets of snow in, one in the background and one in the foreground. I thought about doing some parallax and/or perspective, but this needed too much refactoring so, again, I left it simple.
Next up I drew a Christmas tree. This is defined mathematically, with a pair of loops drawing each tier of branches. There were a couple of tricky bits here, like making sure the right side didn't display upside-down - in fact, during various bits of debugging, I had every part in every possible orientation. I tried various forms of easing, to make the tree a little less triangular, but in the end I just used a quadratic ease-in on the outer corners, easing on the y-axis or inner corners didn't really work.
I put a nice little gradient together for the tree too - it's generated programmatically, so will change itself if the number of tiers changes.
A key animation I wanted to do was some twinkling lights on the tree. These are thrown randomly into a triangle surrounding the tree, with a bias toward the bottom by adding a slight exponent to the vertical position. I made them wbhb-yellow, because branding. They each count a random number of frames, and turn off between 50 and 100% of that period. I originally just didn't draw them when they were off, but then changed this to use a different gradient, which felt more realistic. I'm not completely happy with the result, so keep en eye out for if I improve it next year.
Finally I added a logo as the tree-topper and some text.
The Canvas runs at 60 frames-per-second on both my laptop and phone, with quite a lot of idle time, which seems suitably performant, and leaves plenty of scope for next year. I'm considering adding a couple of characters, or doing something with video from a webcam.