I wanted to make a gift for a family member that should show them animated GIFs, including sounds, of some family moments as a keepsake. I have a ton of family photos and videos and I wanted to allow the recipient to take some of the more memorable ones on-the-go in a little portable battery-powered device that's easy to use.
After a a lot of back-and-forth help on the Adafruit forums, I was finally able to settle on the final design which I then released to GitHub. It uses the following main components:
All the parts are shoved quite densely into a tiny 3D printed enclosure. It's easy to use: press the button to reset the device and a random GIF and WAV start playing. When the GIF is done, the board enters deep sleep, and wakes up again once you reset it.
To load up the GIFs and WAVs in a compatible format, I included a wrapper script for FFmpeg. That guarantees that you can load up media that's compatible. And lastly, I added the ability to hold down one of the buttons to enter a USB mode to transfer GIFs without the need to remove the microSD card.
I learned a few important lessons on the way:
- Rendering GIFs takes a lot more bandwidth and processing power than you might first think. I had to set the SPI bus speed for the LCD to its highest possible setting, way above the default value. Even a little 240x135 screen would show tearing without this.
- IO speed was actually a limiting factor, not the CPU for a while. I initially tried to use an SPI-based SD card reader, but ultimately had to go with one that supported SDIO to get the transfer speeds I needed.
- A design goal was to show the GIF as quickly as possible after pressing the button. I wanted to use CircuitPython, but it turned out to be just too slow at booting up.
- I wanted to cleverly package the components in a way that took up the least amount of space. Fortunately, all the pins on the SDIO breakout would align perfectly to power, ground, and usable GPIO pins. I could do the same with the data pins on the I2S amplifier, although I needed to solder in extra wires to get power. It got complicated because I repurposed the SPI bus's MISO pin as a normal GPIO pin for the I2S amplifier, but that required initializing SPI without MISO, which isn't how CircuitPython worked by default. That led me down a rabbit hole that ultimately added so much complexity to getting it working in CircuitPython that Arduino ended up being easier.
I built a prototype on a breadboard first by soldering on the full headers to all the boards, which turned out to be a good idea when I needed to make updates to the wiring and components to make it work. Once I had it working properly on the breadboard, I then built the real thing using a separate set of components I ordered.
See the project on GitHub for instructions on building your own!
This page (Noisy GIF Player: a tiny portable GIF player with sounds) was last updated on December 27, 2025.