Some weeks ago, I wrote about how I made blinking MishMash bubbles. Today, I wanted to see if I could create more variations on this and make a longer animation. This was inspired by the dynamic RITMO emblem, which reconfigures itself once in a while:
That is a video, though, and was made manually back in 2018. Now, I would like to know if I can get agential help creating dynamic GIFs from SVG files.
The starting point
As a reminder, the visual design of the MishMasb “bubbles” comes from an SVG file with three elements:
- A purple circle (
#A7A1F4) on the left at position (150, 160) - A green circle (
#C1F7AE) on the right at position (270, 160) - A dark overlap region (
#363644) created with an SVG clip path
<circle cx="150" cy="160" r="110" fill="#A7A1F4" stroke="#777" stroke-width="1"/>
<circle cx="270" cy="160" r="110" fill="#C1F7AE" stroke="#777" stroke-width="1"/>
The overlap uses a <clipPath> to constrain the dark fill to the intersection area, which moves naturally as the circles reposition.
The approach: SVG frames → PNG → GIF
Rather than drawing each frame by hand, the CoPilot agent (using GPT 5.3) wrote shell scripts that:
- generated SVG files for each animation frame, varying the circle positions mathematically
- rasterised each SVG to PNG using ImageMagick’s
convert - assembled PNGs into a looping GIF with per-frame delay control
This made it easy to experiment with different motion paths and timings.
Variation 1: Overlap centre
The circles slide inward until they fully overlap at the centre, then slide back out. This was achieved using a cosine easing function to make the motion smooth:
m=$(awk -v i="$i" 'BEGIN{pi=atan2(0,-1); print (1-cos(2*pi*i/12))/2 }')
cx1=$(awk -v m="$m" 'BEGIN{printf "%.3f", 150 + 60*m}')
cx2=$(awk -v m="$m" 'BEGIN{printf "%.3f", 270 - 60*m}')
At the midpoint (i=6), both circles converge to cx=210 (the centre of the canvas), creating a full overlap.

Variation 2: Sides and back
The inverse motion: circles move apart to the edges and then return. The offset is larger (55 units outward), so the circles visibly separate:
cx1=$(awk -v m="$m" 'BEGIN{printf "%.3f", 150 - 55*m}')
cx2=$(awk -v m="$m" 'BEGIN{printf "%.3f", 270 + 55*m}')

Variations 3 & 4: Vertical wrap
In these playful variations, one circle drops down and exits the bottom of the frame, then re-enters from the top. There are two versions, one where the right (green) circle moves, and one where the left (purple) circle moves.
The vertical positions were defined as a sequence of keyframes:
Y_VALUES=(160 200 240 280 320 360 400 440 -120 -80 -40 0 40 80 120 160)
Starting from the normal position (160), the circle moves down past the bottom edge (440), then jumps above the top edge (-120) and slides back down to its starting position.


Timing
All animations follow the same timing pattern:
- 10-second hold on the starting frame (delay=1000 in GIF centiseconds)
- Continuous motion through the remaining frames (delay=4 each, roughly 40ms per frame)
This creates a calm rhythm: the bubbles sit still, move once, then rest again.
The original blink animation was also retimed to match, with a 10-second pause between blinks.
Combined animation
Finally, I wanted a combined GIF that cycles through all five animations in sequence (blink, overlap centre, sides back, right wrap, and left wrap), with a 30-second pause between each. This was built by extracting the frames from each GIF and assembling them into a single sequence with the appropriate delays.

Reflections
Thanks to the support of CoPilot agents, I was able to turn an idea into reality in no time. Also, it helps to start from something simple (the original SVG image) and aim for straightforward animations. This makes the entire process deterministic and scriptable. In fact, it is easy to modify and rerun the script if I (or others) come up with other ideas.
Thanks to CoPilot for helping with creating the animations and for writing a draft for this blog post.
