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.


[] Posted on 2008-11-13 by Dethe Elza

Previous: Bar Camp: Aesthetic programming for kids of all ages Next: Drawing with opacity