Tutorial Request: Delay Animation



  • I'm trying to learn DrawBot (and Python) and I'm having a hard time trying to replicate an animation I saw on Twitter. Here it is: https://tixy.land (it's the first one)

    Here is what I wrote so far:

    canvasSize = 500
    circleCount = 10
    circleSize = canvasSize / circleCount
    offset = circleCount * circleSize
    frameCount = 24
    rowCount = 10
    
    for frame in range(frameCount):
        newPage(canvasSize, canvasSize)
        frameDuration(1/frameCount)
        circleScale = cos(pi * frame / frameCount)
    
        translate(canvasSize/2, circleSize/2)
        
        for row in range(rowCount):
            save()
            for i in range(circleCount + 1):
                save()
                translate(i * circleSize)
                scale(circleScale, center=(-circleSize/2 - offset/2, 0))
                oval(-circleSize - offset/2, -circleSize/2, circleSize, circleSize)
                restore()
            restore()
            translate(0, circleSize)
            
    saveImage("~/Desktop/circleTest.gif")
    

    And this is the output:
    circleTest.gif

    I'm not sure how to make the animation for each row start at a different frame so that it has that wave effect. Is it possible to progressively delay the start of each row animation? Or is that not the right approach here?


    Log in to reply
     

  • admin

    a lot is happening at the same time 🙂

    I hope the example is clear enough!

    # seperate width and height
    canvasWidth = 300
    rowCount = 10
    circleCount = 10
    # calculate circleSize based on the width and the amount circles
    circleSize = canvasWidth / circleCount
    # must be even
    frameCount = 24
    # calcualte the height based on the circle size and rows
    canvasHeight = circleSize * rowCount
    
    
    # start loop
    for frame in range(frameCount-1):    
        # calculate a factor, number between 0 - 1
        # going from 0 - 1 - 0
        frameFactor = frame / (frameCount) * 2        
        if frameFactor > 1:
           frameFactor = 2 - frameFactor 
        # create a page
        newPage(canvasWidth, canvasHeight)
        # draw a white background
        with savedState():
            fill(1)
            rect(0, 0, canvasWidth, canvasHeight)
        # translate half of the circle size
        translate(circleSize/2, circleSize/2)
        # start a loop for each row
        for row in range(rowCount):
            # get the scale base factor, a number between 0 - 1
            circleScale = row / (rowCount - 1)
            # add the frame factor
            circleScale += frameFactor
            # normalize the circle size
            if circleScale > 1:
                circleScale = 2 - circleScale
            # adding some easein
            circleScale = circleScale * circleScale
            # start loop for each column
            for i in range(circleCount):
                # save and restore        
                with savedState():
                    # translate to the x, y of the oval
                    translate(i * circleSize, row * circleSize)
                    # scale
                    scale(circleScale)
                    # draw the oval
                    oval(-circleSize/2, -circleSize/2, circleSize, circleSize)
    # save the image
    saveImage("test.gif")
    

  • admin

    test.gif

    the resulting animated gif



  • I found this very interesting so I tried to do it without a lot of success, I ended with something like this:

    w, h = 1000, 1000
    divs = 10
    colSize, rowSize = w//divs, h//divs
    fps = 12
    seconds = 1
    duration = 1 / fps
    totalFrames = seconds * fps
    
    def circles(step):
        for x in range(0, w, colSize):
            for y in range(0, h, rowSize):
                d = rowSize * sin(y/(divs/2)+step)
                if d > 0:
                    fill(1)
                else:
                    fill(1, 0, 0)
                oval(x + colSize/2 - d/2, y + rowSize/2 - d/2 , d, d)
     
    for frame in range(totalFrames):
        newPage(w, h)
        frameDuration(duration)
        fill(0)
        rect(0, 0, w, h)
        circles(frame)
            
    saveImage("~/Desktop/circleTest.gif")
    

    I'm not understanding how the time works in the reference to achieve the smooth variation



  • Thank you frederik and eduairet! It's nice to see your approach. I tried a few more times after submiting the topic and this is what I ended up with:

    CANVAS = 500
    MARGIN = 60
    CIRCLES = 10
    CSIZE = (CANVAS / CIRCLES) - (MARGIN / CIRCLES)
    FRAMES = 96
    ROWS = CIRCLES
    
    for frame in range(FRAMES):
        newPage(CANVAS, CANVAS)
        fill(0)
        rect(0, 0, CANVAS, CANVAS)
        frameDuration(1 / 24)
        translate(0, CSIZE / 2)
        fill(1)
        
        for row in range(ROWS):
            for circle in range(CIRCLES):
                save()
                translate(circle * CSIZE)
                scale(sin(pi * frame / FRAMES + circle / CIRCLES), center=(CSIZE / 2 + MARGIN / 2, MARGIN / 2))
                oval(MARGIN / 2, -CSIZE / 2 + MARGIN / 2, CSIZE, CSIZE)
                restore()
            translate(0, CSIZE)
            
    saveImage("~/Desktop/circleTest.gif")
    

    The resulting .gif:
    circleTest.gif


  • admin

    cool !



  • @vitorcarvalho wow, this is lovely!!!


Log in to reply