CFA.js

A javascript+canvas implementation of the Context Free Art design grammar: Put short code in, get pretty pictures out! How to use it. How it works. Implementation status.

If you have feedback of any kind, drop me a line or leave a comment. Thanks!

Reinventing the wheel.

Turns out, I'm not the first one to do this. Thankfully, I'm in good company. Check out Algorithm Ink by Aza Raskin, who happens to be the lead designer for Firefox.

There are some definite differences between our implementations.

Sorry, you need a browser that supports the HTML5 canvas for this.

How to use it

In a nutshell, you write a short script describing the scene you'd like, and you get a picture of the scene back. The tricky part is that the scripts can be incredibly powerful and thus unintuitive.

Thankfully, there is ample tutorial countent:

Implementation status

In general

Vs. contextfreeart.org

Vs. Algorithm Ink

Under the hood

For those of you who looked at the source and saw that it was underdocumented and overcomplicated: Sorry about that, it's a hack. As I have time I'll fix it up.

If you're a functional programming afficiando, you'll see a lot of friendly concepts below; if not, it will seem rather alien and unfamiliar.

Parsing

I used a technique from the functional programming language world called combinator parsing, where you build up a parser by composing lots of little functions together. (A "combinator" is, roughly, a function that combines other functions into a new function.)

This means the code starts with some ugly plumbing, but lets me specify the end grammar rather nicely once the plubming is out of the way:

var p_rule = seq([lit("rule"), ident, alt(number, succeed(1.0)) ,rbody], function(_,nm,wt,bdy) { return rule(nm,wt,bdy); });

Translated to english, this means that a rule definition consists of: The literal string "rule", then an identifier, then an optional number ('1.0' is the alternative, if the number is omitted), then the body of the rule.

Interpreting and drawing

Graphics commands and state

To a certain extent, this is the easy part: Drawing things on the canvas is reasonably straightforward, and ditto for keeping track of the transformation and color states.

Long-running scripts, browser interaction

These issues are potentially nasty ones for a naive implementation -- it can take a long time to render images, and the browser tab or entire browser will be frozen during that time. Further, the user will eventually be prompted to kill the script because it will appear unresponsive. Finally, as a matter of taste, the drawing process will be hidden -- it's far more fun to watch it progress, even at the expense of some speed.

There's a big hammer for these sorts of issues called continuation-passing style. If you've used AJAX, you've already done a little bit of it: Rather than giving you the contents of your request immediately as a return value, and potentially stalling your scripts and the browser while it your request goes out over the network, you instead provide a callback which receives the AJAX results.

Continuation-passing style (CPS) is this idea applied universally: You assume all functions work like an AJAX call: they never return, instead invoking a callback when they're done.

Yes, it's a headache. But look what you get in return: At any point during execution, a setTimeout can be inserted, allowing the browser to remain interactive, and execution will pick right back up where it was before after the timeout!

Recursion limits

Since my implementation is fairly direct, where recursion in the CDFG language translates into recursion in Javascript, it will also run into recursion limits in the browser's interpreter.

It turns out that we can solve this problem via a technique called trampolining. Due to our use of CPS, each function's last task is to invoke its continuation (the callback provided in lieu of returning).

However, instead of invoking the callback, it returns the callback, without running it.

This transforms our functions from ones that recurse to arbitrary depths into ones that return the 'next action' (the continutation) to its caller. The root caller's logic is simple: it repeatedly calls the continuation, getting a new one in return, until the program is finished. It's a neat trick: recursive calls in the tail position (calls that are the last ones a function makes) no longer increase the stack depth -- and due to the use of CPS, all function calls are in the tail position.

Seasons
-70,-30,70,50
/* * Seasons, by michael @ contextfreeart.org: * http://www.contextfreeart.org/gallery/view.php?id=519 */ background {b -.8 hue 230 sat .7 a-0.5} startshape SEASONS rule SEASONS { SKY {y 2 b 1 hue 180 z -100 sat .1} TRUNK {x 30 hue 30 alpha -.5 flip 90} TRUNK {x -30 hue 90 alpha -.5} } rule SKY { 80* {y 1 hue .6 sat .01} SQUARE {s 100 1.3} } rule TRUNK 50 { BARK {} TRUNK {y .2 r .1} } rule TRUNK { 2* {flip 90} LIMB {r -12 s .9} } rule LIMB 50 { BARK {} LIMB {y .2 r .1} } rule LIMB { 2* {flip 90} BRANCH {r 8 s .9} } rule BRANCH 10 { BARK {} BRANCH {y .2 hue -2 r .1} } rule BRANCH 10 { BARK {} BRANCH {y .2 r .1 hue 2} } rule BRANCH 10 { BARK {} BRANCH {y .2 r .1 z 1} } rule BRANCH 10 { BARK {} BRANCH {y .2 r .1 z -1} } rule BRANCH { 2* {flip 90 hue 30} BOUGH {r 10 s .7} } rule BOUGH { LEAVES {} TWIG {z -1} } rule TWIG 200 { BARK {} TWIG {y .2 r .1 s .999 a -.001} } rule TWIG { TWIG {r 12 s .8} TWIG {r -12 s .8 f 90} } rule TWIG { TWIG {r 8 s .9} TWIG {r -18 s .7 f 90} } rule TWIG { TWIG {r 25 s .6} TWIG {r -5 s .95 f 90} } rule LEAVES { 60* {r .2} LEAF {y 30 r -180 sat 1 b .6 s 4 hue -10} 100* {r .2} LEAF {y 50 r -180 sat 1 b .8 s 4 hue -10} 60* {r .2} LEAF {y 70 r -180 sat 1 b 1 s 4 hue 10} } rule LEAF 3 { LEAF {x 1 hue 1 b -.05 z -1 s .99} } rule LEAF 4 { LEAF {r 138 sat -.03 z 1} } rule LEAF { SQUARE {skew 20 20 hue -10} SQUARE {skew 30 30 sat .1} SQUARE {skew 40 40 hue 10 sat .2} SQUARE {skew 20 20 b -1 s 1.5 z -.1 alpha -.8} SQUARE {skew 20 20 b -1 s 2.2 z -.1 alpha -.9} } rule BARK { CIRCLE {a -.7 s 2} CIRCLE {a -.7 s 1.5 b .3 z .1 x .3} CIRCLE {a -.7 s 1 b .6 z .2 x .6} CIRCLE {a -.7 s .5 b .9 z .3 x .9} } rule BARK 3 { CIRCLE {a -.6 s 2} CIRCLE {a -.6 s 1.5 b .3 z .1 x .3} }
Tree
-15,-1,15,15
/* * Tree by ColorMeImpressed @ contextfreeart.org * http://www.contextfreeart.org/gallery/view.php?id=2180 */ startshape box rule box 20 { SQUARE {} box {s .99 r 3 y .8} } rule box 8 { SQUARE {} box {s .99 r 3 y .8 flip 90} } rule box { SQUARE {} box [s .5 r 10 y .8 b .07 z -.07] box {s .99 y .8} box [s .6 flip 90 r 10 y .8 b .07 z -.07] } rule box { SQUARE {} box [s .5 r 10 y .8 b .07 z -.07] box {s .99 y .8 flip 90} box [s .5 flip 90 r 10 y .8 b .07 z -.07] } rule box 3 { SQUARE {} box [s .8 r 10 y .8 b .015 z -.015] box [s .8 flip 90 r 10 y .8 b .015 z -.015] }
Hilbert
-1.1,-1.1,1.1,1.1
/* * Hilbert by mfm24 @ contextfreeart.org * http://www.contextfreeart.org/gallery/view.php?id=1112 */ startshape H rule H { 2* {flip 90} iline{r 90 x -.5} iline {y -.5} 2*{flip 90} H {s .5 r 90 x -.5 y .5} 2*{flip 90} H {s .5 x -.5 y -.5} } rule iline { line { } iline { s .5 y .25} } rule line { SQUARE{s 1 .01} }
Morse code forever
-2,-2,2,2
/* * Morse Code Forever, by Matt @ algorithmink */ startshape frame rule frame { shape {s .07 y -2} } rule shape{ dit {r 2 s .9997} } rule dit { CIRCLE {x .5 s .8} shape {x 1} } rule dit { SQUARE {x 1 s 1.6 .8} shape {x 2 r 2} } rule dit .7 { shape {x 1} }
SpiralThing
-2,-2,2,2
startshape shape rule shape{ test { s .05 } test { s .05 flip 90 } test { s .05 r 180 } test { s .05 r 180 flip 90 } } rule test 10 { SQUARE{} test{ y .5 s .99 r 2 } } rule test .06 { SQUARE{} test { y .5 s .99 r 2 } test { y .5 s .99 r 10 flip 90 } }
Chalk
-3,-3,10,10
/* * Chalk, by chris @ contextfreeart.org * http://www.contextfreeart.org/gallery/view.php?id=256 */ startshape blah background {hue 120 sat 1 b -0.5} rule blah { blah2 {alpha -1} blah2 {flip 90 alpha -1 x 5 b 1} blah2 {alpha -1 y -5 b 1} blah2 {flip 90 alpha -1 x 5 y -5} } rule blah2 { SQUARE { } blah2 {alpha 0.0001 r 10 x 1 s 0.9995} } rule blah2 { SQUARE { } blah2 {alpha 0.0001 r 9 x 1 s 0.9995} }