perjantai 29. maaliskuuta 2019

JS1k 2019 writeup part 1 - Cruising The 80s

When I did a blog post about my "Cyber Auroras" demo a year ago the conclusion I wrote was this:
Inspiration and personal connection to the subjects will drive you to better performance and leave you a much happier programmer!
I had forgotten about writing that but luckily I had not forgotten the lesson learned. What that mentality has allowed me to achieve in the past year as a programmer is nothing short of amazing on a personal level. I went on to write countless 140 byte demos learning more about code golfing than in my previous years combined. It also made me go back to the fundamentals of JavaScript programming and I filled some important gaps in my understanding of them. This made me a better software developer in all areas - not just in code golfing.

When the 10th (and hopefully not final) JS1k came along I had many ideas and tricks to choose from. This resulted in the release of four very different demos which I'll now introduce to you one by one...

1. Retrowave

I went through a period last winter where I was really into the retrowave visuals and atmosphere. I spent one weekend trying to find the smallest possible snippets of code for producing each of the synthwave art cliche elements. I had a lot of fun combining some of them into dwitter demos.

When JS1k 2019 started I went back to that bag of tricks first and put the grid and the sunset as the backdrop for the demo. I wanted to add palm trees and a Lamborghini Countach to go all out on the theme...

2. Compressing SVG paths

I had previously experimented with Path2D drawing and finding ways to heavily compress the data. The approach I chose is based on the ability to scale and mirror the paths. The shape needs to be symmetrical and simple enough to draw half of it with a 10 x 10 grid. We will then need only one byte for each coordinate and only half of the coordinates need to be defined. I drew both the palm tree and the car with an online SVG Path Builder and compressed the data by hand.

Here's the code that draws the chassis of the Lamborghini with the coordinate range of 0-9 for both axes...

c.fill(P=new Path2D('M'+[...'944000014163040989']))

And here's how the path looks...

The data is a string of coordinates. M is the moveto command, but it turns into lineto automatically if you add more coordinates after the initial position. I've crammed all numbers together to save space and I use the spread operator to separate them. This goes as input for the array literal syntax that creates an array that has our coordinates as elements. When we add this array to the string "M" it is converted back to a string by the JS engine.  Below is this process step by step from the Chrome console so you can see what the interpreter does with our data...

Since we use fill it will close the path automatically for us. We don't need to define the last coordinate of the path.

For some special cases this approach could be taken even further by using relative coordinates and packing them inside 3-4 bits each. But that's for another demo in the future. :)

3. Adding details

To make the car look more authentic I added details around the chassis. The mirrors and the spoiler are done with simple rects drawn before the chassis and in slightly different shade of grey. This adds depth. The windscreen reuses a section of the chassis path and is slightly transparent. To mask the blockiness of the design I used a linear gradient to paint the car. It cost a lot of bytes but also makes a big difference. The glowing lights are a stack of scaled transparent white rects with shadowBlur.

4. Making music

You can't have a synthwave demo without music, right? As a longtime guitarist and songwriter I was very excited to start working on audio.  I had never done anything with the audio context in the past and sadly my initial excitement was soon gone after realizing the limitations of it. Not only does setting it all up take a lot of space but the basic sounds are just plain awful. I had to drop my dreams of a good sounding track and try to create something that was bad but hopefully bad in a good way.

The song itself I had composed years ago for the unfinished game called Owl Invasion. It was just one track of fingerstyle acoustic guitar produced into an electronic song. I split the bassline and melody to different oscillators and broke down the song into a code logic rather than trying to compress the data. I eventually managed to fit the parts in surprisingly small space but it really is just a complex set of brute force code golfing without a clear idea behind it. It worked but it's not pretty nor easily explainable.

I initially connected two oscillators to the same destination. After posting the demo I was informed that in some environments the sounds were painful to listen to. I replaced my first version with one that uses two destinations and also used less distorting oscillators. Luckily I managed to fit the changes without making any sacrifices in the visuals. I really like how during the chorus the background is animated to change into a desert scene.

Follow me on Twitter if you want to hear of new demos and blog updates - @jylikangas

Ei kommentteja:

Lähetä kommentti