in earth dreams

This is a collaboration that Daniela and I did together. Her words and voice, my scripting and adding some titles. The words to the poem can be found on her site here (or actually, on any page of her site since it is currently in her sidebar). The animation itself was done in NodeBox (so this example is Mac-only, but it could probably be adapted easily to Processing.

from math import radians, sin, cos
from random import seed

POEM = '''
in earth dreams
her limbs 		are all sky
her body		inhabited
by wild birds		and busy
an endangered 		species
she lost		 her head
where reason 		gives
the impression 		everything is
she motions 	to dance
a rhythm			spins
and turns		attracted
to light
if she had eyes 		I would see
the stars		she holds
then 		there are 		all
the words		she escapes
slips past 		their curved
seashell ears	as they listen
to capture 		her
on the page		 my words
are already	changing her
while she weaves 	gossamer
and soft moss		to hang
in autumn 	woods


class Vector(object):

    def __init__(self, idx):
        self._starting_angle = self.angle = radians(random(360))
        self.rate = random(0.5,2.5)
        self.distance = sin(radians(idx * 2) + 180) * 100
        self.x = 0
        self.y = 0

    def step(self):
       self.angle = self._starting_angle + FRAME * radians(self.rate)
       self.x = cos(self.angle) * self.distance
       self.y = sin(self.angle) * self.distance
       return self.rate, self.x, self.y

class Word(object):

    index = []

    def __init__(self, idx, word): = random()  = random(0.4, 0.75) = 0.4
		self.vector = Vector(idx)
		self.word = word
		self.size = 10 + 2 * len(word)
		self.duration = 3 * (len(word) + 2)
		Word.index += [idx] * self.duration

    def step(self, alpha=1.0):
		fill(,,, alpha)
		rate, x, y = self.vector.step()
		rotate(rate * FRAME)
		font('Georgia', self.size)
		text(self.word, x, y)

def setup():
    global words
    words = [Word(idx, word) for idx,word in enumerate(POEM)]

def draw():
    translate(WIDTH/2 -50,HEIGHT/2)
    background(1.0, 0.97, 0.86)
    # Add one word at a time, then show all words for 100 frames more
    if FRAME < len(Word.index):
        last = Word.index[FRAME]
        for word in words[:last]:
    # Now fade out and have blank screen for titles
    elif FRAME < len(Word.index) + 100:
        alpha = 1.0 - 0.01 * (FRAME - len(Word.index))
        for word in words:

I used iMovie '08 to mix the voice and animation and to add the titles. I wasn't very happy with the changes to iMovie, I found the earlier versions were much more flexible and easy to use. On the other hand, I tried Norrkross Movie, that I actually had to buy, and was unable to do it at all. Next time I will just add the titles in NodeBox and only use iMovie to add the soundtrack.

My Python script could probably be cleaned up too. This was what I had after many iterations and experiments to get the timing, color, and rotation where we were both happy with it.

This was my first time uploading to YouTube and the resulting movie is very jumpy, in the original movie I uploaded was not. If anyone has suggestions how to avoid that (whether pre-processing or a better movie hosting service), please let me know in the comments. Overall I was happy with how it turned out and I'm looking forward to our next collaboration.

Bar Camp: Aesthetic programming for kids of all ages

OK, Bar Camp was over a month ago and I'm finally getting around to posting my second set of slides. I've included notes right in the PDF this time, summarizing what I think I was talking about at the time.

Aesthetic Programming for kids of all ages (PDF)

The reason this took so long is that I wanted to illustrate the concepts I was exploring out loud by embedding a programming environment into this blog post. So, what you see above is a tiny turtle language for Javascript and some examples of how to use it. When you click the Run button, you should see the script run by having some drawing going on in the frame above it. I've used Google's excanvas, which hopefully will let it run in IE, but I haven't tested it much beyond Safari and have no idea if it will survive transliteration into Atom and beyond. Let me know if it doesn't work for you, or if you have ideas for how to improve it. I will be putting some more thought into these ideas soon.