Creating an Animated Eye for a Painted Minions Pumpkin
🗓️ • ⏱️ 10 min read

🗓️ • ⏱️ 10 min read
Every year, my daughter Natalia’s elementary school hosts a pumpkin painting contest. The rules are simple: decorate a pumpkin your kid can carry into school and, most importantly, have fun as a family. Pumpkins are brought in two days before Halloween, the kids vote on them the day before Halloween, and they stay on display at school until after the holiday. Voting is done with spare change, which is donated to a local family in need. At the end of the voting, a winner is selected.
As a family, we’ve participated in the contest for the past two years. Two years ago, Natalia and I worked on recreating the house from Up, complete with balloons. Last year, Natalia and my wife teamed up to make a mermaid pumpkin. Unfortunately, neither submission fared particularly well in the voting.


Looking back, the painting on the Up pumpkin wasn’t our best work, and while kids might not have noticed, all I could see in my wife’s mermaid pumpkin was E.T wearing a wig.


This past summer, I took Natalia and one of her friends to see Despicable Me 4 in theaters. Even though it was only July, halfway through the movie, I found myself thinking about how perfect a Minion pumpkin would be for this year’s contest—specifically one with an animated eye.
Of course, painting a Minion pumpkin has been done a million times over. But after a quick Google search, I realized no one had combined the classic Minion look with an animated eye. I was up for the challenge.

In the middle of summer, I started brainstorming. I’ve been tinkering with electronics and 3D printing for a few years now, so I figured this project would be the perfect way to combine those skills. The idea seemed doable, and I already had some components on hand. Over the next few months, I spent time tinkering with electronics, designing and 3D printing CAD models, and writing and testing code.
In the end, I used a Raspberry Pi Zero 2 W, a 2.8 inch round display I found on Amazon, animated GIFs of an eyeball I commissioned on Fiverr, code I wrote, and 3D prints Natalia and I designed to create exactly what I had envisioned over the summer.
The night before the submission deadline, Natalia and I painted the pumpkin to look like a Minion. Once the paint dried, we tested the electronics for the last time. Everything worked perfectly. On Tuesday, Natalia carried the finished pumpkin into school, and it was up to the students at her school to decide our fate.
On Halloween, Natalia was so excited as she stepped off the bus, proudly showing us the winning certificate. Sharing this project with her was so much fun. Natalia loves creating as much as I do, and involving her in the CAD, 3D printing, and electronics made the experience even more special.

Now let’s get into what exactly I used and how I connected it all together to create this award winning masterpiece. 😉
Like many of my other projects, I already had most of these parts on hand.
If you’re looking to power the system on a battery bank I would suggest adding a relay so that the Pi can turn the screen on and off on a fixed schedule to save power. If not, you can skip the relay and battery bank all together.
I created the following models for this project. Both models are available for free on Printables.com in STL and Fusion360 formats.
The goggle frame was modeled to look like what the Minion’s wear. There is a recessed space on the underside to fit the 2.8 inch display linked above. The holes on each side are just wide enough to fit the 1 inch elastic strap through.

This is used to tie together the two ends of the elastic strap. There is enough friction between the elastic and the print to keep the tension.

The following code handles both the playing of the animated gifs and the scheduling for turning the screen on and off. If you don’t plan on using the scheduling you can simply set SCHEDULE to False on line 9. There are other variables available for customizing the schedule and the GPIO pin used for the controlling the relay.
We’ll use this code further down in the Raspberry Pi Setup section.
1import pygame2from PIL import Image3import random4import os5import RPi.GPIO as GPIO6import schedule7
8# Configuration for scheduled GPIO control9SCHEDULE = True # Enable/disable scheduling10SCHEDULE_ON = '07:00' # Time to turn the relay ON11SCHEDULE_OFF = '19:05' # Time to turn the relay OFF12GPIO_PIN_FOR_RELAY = 26 # GPIO pin used to control the relay13
14if SCHEDULE:15 # Initialize GPIO in BCM (Broadcom pin numbering) mode16 GPIO.setmode(GPIO.BCM)17 GPIO.setup(GPIO_PIN_FOR_RELAY, GPIO.OUT)18
19 # Define function to set the GPIO pin HIGH (activate relay)20 def set_pin_high():21 GPIO.output(GPIO_PIN_FOR_RELAY, GPIO.HIGH)22 print(f"GPIO {GPIO_PIN_FOR_RELAY} set to HIGH ({SCHEDULE_ON})")23
24 # Define function to set the GPIO pin LOW (deactivate relay)25 def set_pin_low():26 GPIO.output(GPIO_PIN_FOR_RELAY, GPIO.LOW)27 print(f"GPIO {GPIO_PIN_FOR_RELAY} set to LOW ({SCHEDULE_OFF})")28
29 # Schedule tasks to run at specified times30 schedule.every().day.at(SCHEDULE_ON).do(set_pin_low) # Deactivate relay at SCHEDULE_ON31 schedule.every().day.at(SCHEDULE_OFF).do(set_pin_high) # Activate relay at SCHEDULE_OFF32
33# Initialize pygame for display and graphics handling34pygame.init()35
36# Set up a 480x480 window for displaying GIFs37screen = pygame.display.set_mode((480, 480))38
39# List of GIF files with their respective weights for random selection40gif_files = [41 ("blink.gif", 3), # More likely to be chosen (weight 3)42 ("look-left.gif", 1),43 ("look-right.gif", 1),44]45
46# Function to load and process a GIF file into pygame-compatible frames47def load_gif(gif_path):48 gif = Image.open(gif_path) # Open the GIF file49 frames = [] # List to store individual frames50 frame_durations = [] # List to store frame durations51
52 # Extract and process each frame53 for frame in range(0, gif.n_frames):54 gif.seek(frame) # Go to the specific frame55 frame_image = gif.convert("RGBA") # Convert to RGBA for pygame compatibility56
57 # Rotate the frame 90 degrees counterclockwise58 rotated_frame = frame_image.rotate(90, expand=True)59
60 # Convert the frame to a pygame image61 mode = rotated_frame.mode62 size = rotated_frame.size63 data = rotated_frame.tobytes()64 py_image = pygame.image.fromstring(data, size, mode)65
66 # Append frame and its duration67 frames.append(py_image)68 duration = gif.info.get("duration", 100) / 1000.0 # Duration in seconds69 frame_durations.append(duration)70
71 return frames, frame_durations72
73# Function to play a GIF frame-by-frame on the pygame display74def play_gif(frames, frame_durations):75 current_frame = 0 # Start with the first frame76 last_update_time = pygame.time.get_ticks() # Time tracking for frame updates77
78 while current_frame < len(frames):79 # Handle user events (e.g., quit or escape key)80 for event in pygame.event.get():81 if event.type == pygame.QUIT:82 return False83 elif event.type == pygame.KEYDOWN:84 if event.key == pygame.K_ESCAPE:85 return False86
87 now = pygame.time.get_ticks()88
89 # Check if it's time to update the frame90 if now - last_update_time > frame_durations[current_frame] * 1000:91 current_frame += 192 last_update_time = now93
94 if current_frame < len(frames):95 # Center the frame on the screen and display it96 frame_rect = frames[current_frame].get_rect(center=(235, 245))97 screen.blit(frames[current_frame], frame_rect)98 pygame.display.flip()99
100 clock.tick(60) # Limit the loop to 60 frames per second101
102 return True103
104# Main loop that handles GPIO scheduling and GIF playback105running = True106clock = pygame.time.Clock() # Clock to control frame rate107
108try:109 while running:110 if SCHEDULE:111 # Execute any scheduled GPIO tasks112 schedule.run_pending()113
114 # Randomly select a GIF file based on weights115 current_gif, _ = random.choices(gif_files, weights=[w for _, w in gif_files], k=1)[0]116 gif_path = os.path.join("/home/pi", current_gif) # Path to the selected GIF117
118 # Load and play the selected GIF119 frames, frame_durations = load_gif(gif_path)120 running = play_gif(frames, frame_durations)121
122except KeyboardInterrupt:123 # Graceful exit on manual interruption124 print("Program interrupted")125
126finally:127 # Clean up GPIO and quit pygame128 GPIO.cleanup()129 pygame.quit()I found someone on Fiverr to create these gifs for me. Feel free to download them and use them.



Connect the Raspberry Pi and the relay to the battery bank for power.
Connect the display to the relay for power.
Connect the display to the Pi via mini HDMI.
Connect the relay to the Raspberry Pi’s GPIO pins: 26, 3.3v, Ground. For a more detailed look at the GPIO pins, checkout pinout.xyz.

sudo apt updatesudo apt full-upgradesudo pip3 install pygame pillow schedule RPi.GPIOeye.py.cd /home/pi/touch eye.pyeye.py.nano eye.pyUse either a flash drive or scp to transfer the three GIF files to the Raspberry Pi. The files should be named blink.gif, look-left.gif, and look-right.gif.
Place the files next to eye.py in the /home/pi/ directory.
If you’d like the animation to automatically play after the Pi boots then follow these instructions, otherwise skip to the next section.
/etc/systemd/system/ directory.cd /etc/systemd/system/eye.service and add the following.[Unit]Description=Eye GIF DisplayAfter=multi-user.target
[Service]ExecStart=/usr/bin/python3 /home/pi/eye.pyUser=piEnvironment=DISPLAY=:0Environment=XAUTHORITY=/home/pi/.Xauthority
[Install]WantedBy=multi-user.targeteye.py file from earlier executable.chmod +x /home/pi/eye.pysystemd manager configuration and enable the eye.service so it runs automatically after boot.sudo systemctl daemon-reloadsudo systemctl enable eye.servicesudo rebootAs I mentioned above, there are a ton of existing guides on how to paint a Minions pumpkin. A simple search for how to paint minion pumpkin should yield a lot of great written and video tutorials.
Loop the elastic through the printed goggle frame and then create a loop and use the printed elastic clip to keep things together.
Cut a large hole in the backside of the pumpkin and scrape out the seeds as you would a normal pumpkin carving.
Create a square 1in x 1in hole behind where the elastic strap is to route the display’s power and HDMI cables through to the inside of the pumpkin.
Make all connections and insert everything into the pumpkin.
Close up the hole in the back with the piece you cut out.


Comments