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:

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?

]]>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:

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?

]]>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")
```

]]>the resulting animated gif

]]>```
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

]]>```
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: