Tuesday, July 23, 2019

Making a scene with JS - Dwitter Intro

I'm back after a hiatus of many years - I recently came across dwitter.com which is a website where you make graphical demos with 140 bytes javascript

I really got hooked onto it, because it takes me back 30 years when I spent many hours on a BBC micro trying to get weird patterns drawn on the screen using SIN, COS etc.

For many of us, the entry into programming was because you could get the computer to draw stuff.
In a way this is one of the most purest and creative forms of programming - you have a fixed arena and you need to use it - no quarter given.

140 bytes seems very little, but believe me, a lot is possible - some of the demos there are unbelievably complex.

I made several in the past few days, and I've started picking up some of the tricks
I'm going to be writing a series of blog posts about each dweet along with the tips and tricks I'm discovering for this code-golf as an amateur

So without further ado - let's look at dweet framework provided:



It's simple enough - As you make more dweets you start cursing why the canvas method names are so long! But we work with what we have.


Here is the first dweet I made - Rain-bough-nut




For development I made my own HTML file based on the dweet github code - it works just like the original, except I added code to start and stop the timer on click - this is useful when debugging.



I write my code in a file called demo.js in normal style and then once it's working, I try my best to cut it down to 140 bytes - it's not always possible!

Let's look at how this multi-colored doughnut is rendered



There are two kinds of dweets - those that redraw the whole canvas every frame and those that keep drawing on the earlier frames content - this dweet is the latter kind.

The basic shape is created by drawing rectangles in an inward spiral with this

x.fillRect(780+r*S(b),420+r*C(b),80,90)


The 780 and 420 are approximately the center offset by the size of one rectangle - the center of the canvas is 960,540 and the rectangles are 80,90 in size - hence the spiral will be centered if draw rectangles all around at 960-80 = 880 and 540-90 = 450

This code has 780,420 left over from some experimentation and is does not center perfectly - too late to change now!

r * S(b) and r * C(b) obviously makes a circular path. Here we are reducing the radius from about 382 to 255 over the course of about 4.5 radians, turning the circular path into a mild spiral.
On each frame, the angle b is incremented at the rate of 1 radian per second.

The only remaining trick is the coloring - canvas supports alpha blending, so we can take full advantage of this.

sa=S(t)*z
x.fillStyle=R(z-sa,z-C(t)*z,sa,0.01)

Once again in my haste when making this, I completely ignored the fact that I was using RGB levels outside the valid range 0 to 255.
In this code R ends up cycling from 0 to 512, G from 0 to 512 (90 degrees out of phase with R) and B from 0 to 255 to 0 to 255 and back. A complete cycle takes 2*PI radians, and since we use the time variable as the angle, its about 6.28 seconds.

The alpha channel is set to 0.01 which is the lowest possible value - so each rectangle drawn merely tints the one below.
As the R G and B cycle out of phase, we end up getting all the hues and the semi-transparent rectangles overlapping create a fairly tasty looking doughnut effect.

I didn't really use any minification tricks in this code, except reusing the value 255 as much as possible. Every constant we define uses up valuable bytes, so making one of them do duty in many places is useful.

As I wrote more dweets, I learned a few more tricks of the trade - in future posts I will describe them